From cf1399e59ca60ffee3e42f6c8fcaac679bd06a12 Mon Sep 17 00:00:00 2001 From: matthias muntwiler Date: Thu, 21 Sep 2017 12:36:30 +0200 Subject: [PATCH] update pshell explorer and data import, misc. improvements FEATURES - pshell: convert scienta data to true counts - pre-process: add gauss2_reduction data reduction function - anglescan: add set_contrast and normalize_strip_phi functions - explorer: show info about multi-region scans - documentation: add detailed instructions for angle-scan processing BUGFIXES - explorer: fix attributes notebook - pshell: fix progress bar - elog: increase the number of accepted attachments --- doc/html/PageProjections.html | 4 +- doc/html/annotated.html | 4 +- doc/html/classes.html | 4 +- .../dir_fe5dc42579d4b99403482a3a637d9f7d.html | 4 +- doc/html/fermi-edge-analysis_8ipf.html | 4 +- doc/html/fermi-edge-analysis_8ipf_source.html | 4 +- doc/html/files.html | 4 +- doc/html/functions.html | 4 +- doc/html/functions_vars.html | 4 +- doc/html/globals.html | 4 +- doc/html/globals_b.html | 4 +- doc/html/globals_c.html | 7 +- doc/html/globals_d.html | 4 +- doc/html/globals_e.html | 4 +- doc/html/globals_f.html | 4 +- doc/html/globals_func.html | 4 +- doc/html/globals_func_b.html | 4 +- doc/html/globals_func_c.html | 7 +- doc/html/globals_func_d.html | 4 +- doc/html/globals_func_e.html | 4 +- doc/html/globals_func_f.html | 4 +- doc/html/globals_func_g.html | 7 +- doc/html/globals_func_h.html | 4 +- doc/html/globals_func_i.html | 4 +- doc/html/globals_func_k.html | 4 +- doc/html/globals_func_l.html | 4 +- doc/html/globals_func_m.html | 4 +- doc/html/globals_func_n.html | 7 +- doc/html/globals_func_o.html | 4 +- doc/html/globals_func_p.html | 9 +- doc/html/globals_func_q.html | 4 +- doc/html/globals_func_r.html | 4 +- doc/html/globals_func_s.html | 7 +- doc/html/globals_func_t.html | 7 +- doc/html/globals_func_u.html | 4 +- doc/html/globals_func_w.html | 4 +- doc/html/globals_g.html | 7 +- doc/html/globals_h.html | 4 +- doc/html/globals_i.html | 4 +- doc/html/globals_k.html | 11 +- doc/html/globals_l.html | 4 +- doc/html/globals_m.html | 4 +- doc/html/globals_n.html | 7 +- doc/html/globals_o.html | 4 +- doc/html/globals_p.html | 9 +- doc/html/globals_q.html | 4 +- doc/html/globals_r.html | 4 +- doc/html/globals_s.html | 7 +- doc/html/globals_t.html | 7 +- doc/html/globals_u.html | 4 +- doc/html/globals_v.html | 4 +- doc/html/globals_vars.html | 7 +- doc/html/globals_w.html | 4 +- doc/html/group___arpes_package.html | 4 +- doc/html/index.html | 6 +- doc/html/mainpage_8dox.html | 4 +- doc/html/modules.html | 4 +- .../namespace_pearl_anglescan_process.html | 4 +- doc/html/namespace_pearl_area_display.html | 4 +- doc/html/namespace_pearl_area_import.html | 4 +- doc/html/namespace_pearl_area_profiles.html | 4 +- doc/html/namespace_pearl_arpes.html | 4 +- doc/html/namespace_pearl_data_explorer.html | 4 +- doc/html/namespace_pearl_elog.html | 4 +- doc/html/namespace_pearl_matrix_import.html | 4 +- doc/html/namespace_pearl_p_shell_import.html | 4 +- .../namespace_pearl_scienta_preprocess.html | 4 +- doc/html/namespaces.html | 4 +- doc/html/navtreedata.js | 4 +- doc/html/navtreeindex0.js | 100 +++--- doc/html/navtreeindex1.js | 22 +- doc/html/navtreeindex2.js | 35 +- doc/html/pages.html | 4 +- doc/html/pearl-anglescan-process_8ipf.html | 304 ++++++++++++++---- doc/html/pearl-anglescan-process_8ipf.js | 3 + .../pearl-anglescan-process_8ipf_source.html | 113 +++---- doc/html/pearl-anglescan-tracker_8ipf.html | 4 +- .../pearl-anglescan-tracker_8ipf_source.html | 28 +- doc/html/pearl-area-display_8ipf.html | 25 +- doc/html/pearl-area-display_8ipf_source.html | 24 +- doc/html/pearl-area-import_8ipf.html | 4 +- doc/html/pearl-area-import_8ipf_source.html | 4 +- doc/html/pearl-area-profiles_8ipf.html | 4 +- doc/html/pearl-area-profiles_8ipf_source.html | 4 +- doc/html/pearl-arpes_8ipf.html | 4 +- doc/html/pearl-arpes_8ipf_source.html | 4 +- doc/html/pearl-data-explorer_8ipf.html | 86 ++--- doc/html/pearl-data-explorer_8ipf_source.html | 94 +++--- doc/html/pearl-elog_8ipf.html | 118 ++++--- doc/html/pearl-elog_8ipf_source.html | 82 ++--- doc/html/pearl-fitfuncs_8ipf.html | 4 +- doc/html/pearl-fitfuncs_8ipf_source.html | 4 +- doc/html/pearl-gui-tools_8ipf.html | 4 +- doc/html/pearl-gui-tools_8ipf_source.html | 4 +- doc/html/pearl-matrix-import_8ipf.html | 4 +- doc/html/pearl-matrix-import_8ipf_source.html | 4 +- doc/html/pearl-menu_8ipf.html | 4 +- doc/html/pearl-menu_8ipf_source.html | 4 +- doc/html/pearl-otf-import_8ipf.html | 4 +- doc/html/pearl-otf-import_8ipf_source.html | 4 +- doc/html/pearl-polar-coordinates_8ipf.html | 4 +- .../pearl-polar-coordinates_8ipf_source.html | 4 +- doc/html/pearl-pshell-import_8ipf.html | 114 ++++--- doc/html/pearl-pshell-import_8ipf.js | 3 +- doc/html/pearl-pshell-import_8ipf_source.html | 75 ++--- doc/html/pearl-scienta-preprocess_8ipf.html | 160 +++++++-- doc/html/pearl-scienta-preprocess_8ipf.js | 3 + .../pearl-scienta-preprocess_8ipf_source.html | 43 +-- doc/html/pearl-tools_8ipf.html | 4 +- doc/html/pearl-tools_8ipf_source.html | 4 +- doc/html/pearl-vector-operations_8ipf.html | 4 +- .../pearl-vector-operations_8ipf_source.html | 4 +- doc/html/search/all_11.js | 1 + doc/html/search/all_12.js | 1 + doc/html/search/all_2.js | 1 + doc/html/search/all_6.js | 1 + doc/html/search/all_9.js | 1 + doc/html/search/all_c.js | 1 + doc/html/search/all_e.js | 3 +- doc/html/search/functions_11.js | 1 + doc/html/search/functions_12.js | 1 + doc/html/search/functions_2.js | 1 + doc/html/search/functions_6.js | 1 + doc/html/search/functions_c.js | 1 + doc/html/search/functions_e.js | 3 +- doc/html/search/variables_7.js | 1 + doc/html/struct_doniach_sunjic_struct.html | 4 +- doc/html/structerror_code.html | 4 +- doc/html/todo.html | 4 +- doc/latex/refman.pdf | Bin 566487 -> 578978 bytes pearl/pearl-anglescan-process.ipf | 195 ++++++++++- pearl/pearl-area-display.ipf | 65 ++-- pearl/pearl-data-explorer.ipf | 32 +- pearl/pearl-elog.ipf | 156 ++++++--- pearl/pearl-pshell-import.ipf | 109 ++++--- pearl/pearl-scienta-preprocess.ipf | 202 +++++++++++- .../pearl_explorer/attr_filter_pearl.itx | 32 ++ 137 files changed, 1824 insertions(+), 853 deletions(-) create mode 100644 pearl/preferences/pearl_explorer/attr_filter_pearl.itx diff --git a/doc/html/PageProjections.html b/doc/html/PageProjections.html index 084b6f7..253ad75 100644 --- a/doc/html/PageProjections.html +++ b/doc/html/PageProjections.html @@ -32,7 +32,7 @@
PEARL Procedures -  rev-distro-1.4.0-0-g80a01f2 +  rev-distro-1.4.0-1-g0a436db-dirty
Igor procedures for the analysis of PEARL data
@@ -126,7 +126,7 @@ $(document).ready(function(){initNavTree('PageProjections.html','');}); @@ -2408,7 +2548,61 @@ 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 2536 of file pearl-anglescan-process.ipf.

+

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

+ + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variable set_contrast (variable pcmin,
variable pcmax,
string graphname = defaultValue,
string colortable = defaultValue 
)
+
+ +

set the pseudocolor contrast by percentile.

+

set the minimum and maximum values of the pseudocolor scale such that a specified percentile of the distribution lies outside the limits.

+

the new contrast is applied to traces and images of the selected graph that have pseudocolor tables.

+

the function is not specific to angle scans. it can be used for any pseudocolor trace or image plots except contour plots.

+
Parameters
+ + + + + +
pcminpercentile below the minimum color (0-100).
pcmaxpercentile above the maximum color (0-100).
graphnamename of graph. default: top graph.
colortablename of new colortable. default: keep current table.
+
+
+ +

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

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

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

+

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

@@ -2550,7 +2744,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 687 of file pearl-anglescan-process.ipf.

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

@@ -2881,7 +3075,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.7
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-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 //
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 
275 variable normalize_strip_theta(wave strip, wave theta, variable theta_offset = defaultValue, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
276  wave strip
277  wave theta
278  variable theta_offset
279  variable smooth_method
280  variable smooth_factor
281  variable check
282 
283  if (ParamIsDefault(check))
284  check = 0
285  endif
286  if (ParamIsDefault(theta_offset))
287  theta_offset = 0
288  endif
289  if (ParamIsDefault(smooth_method))
290  smooth_method = 4
291  endif
292  if (ParamIsDefault(smooth_factor))
293  smooth_factor = 0.5
294  endif
295 
296  // average over analyser angles
297  wave dist = ad_profile_y(strip, -inf, inf, "")
298 
299  // smooth distribution function
300  duplicate /free dist, dist_smoo
301  duplicate /free theta, theta_int
302  theta_int = theta - theta_offset
303  setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
304  variable nx = dimsize(strip, 0)
305  variable ix
306 
307  switch(smooth_method)
308  case 1:
309  Smooth /B /E=3 smooth_factor, dist_smoo
310  break
311  case 2:
312  Smooth /E=3 smooth_factor, dist_smoo
313  break
314  case 4:
315  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={theta_int}
316  break
317  case 3:
318  for (ix = 0; ix < nx; ix += 1)
319  dist = strip[ix][p]
320  if (smooth_factor > 1)
321  CurveFit /nthr=0 /q /w=2 poly smooth_factor+1, dist /x=theta_int /d=dist_smoo
322  else
323  CurveFit /nthr=0 /q /w=2 line, dist /x=theta_int /d=dist_smoo
324  endif
325  strip[ix,ix][] /= dist_smoo[q]
326  endfor
327  dist_smoo = 1
328  break
329  endswitch
330 
331  // divide
332  if (check != 2)
333  strip /= dist_smoo[q]
334  endif
335 
336  // check
337  if (check)
338  duplicate /o dist, check_dist
339  duplicate /o dist_smoo, check_smoo
340  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
341  endif
342 };
343 
357 variable normalize_strip_2d(wave strip, wave theta, variable theta_offset = defaultValue, variable smooth_method = defaultValue, variable smooth_factor = defaultValue, variable check = defaultValue){
358  wave strip
359  wave theta
360  variable theta_offset
361  variable smooth_method
362  variable smooth_factor
363  variable check
364 
365  if (ParamIsDefault(check))
366  check = 0
367  endif
368  if (ParamIsDefault(theta_offset))
369  theta_offset = 0
370  endif
371  if (ParamIsDefault(smooth_method))
372  smooth_method = 4
373  endif
374  if (ParamIsDefault(smooth_factor))
375  smooth_factor = 0.5
376  endif
377 
378  variable nx = dimsize(strip, 0)
379  variable ny = dimsize(strip, 1)
380 
381  duplicate /free strip, dist, alpha_int, theta_int
382  theta_int = theta[q] - theta_offset
383  alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
384  redimension /n=(nx * ny) dist, alpha_int, theta_int
385 
386  switch(smooth_method)
387  case 4:
388  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={alpha_int, theta_int}
389  redimension /n=(nx, ny) dist_smoo
390  break
391  default:
392  Abort "undefined smooth method"
393  break
394  endswitch
395 
396  // divide
397  if (check != 2)
398  strip /= dist_smoo
399  endif
400 
401  // check
402  if (check)
403  //duplicate /o dist, check_dist
404  duplicate /o dist_smoo, check_smoo
405  endif
406 };
407 
417 variable crop_strip(wave strip, variable xlo, variable xhi){
418  wave strip
419  variable xlo
420  variable xhi
421 
422  variable plo = round((xlo - dimoffset(strip, 0)) / dimdelta(strip, 0))
423  variable phi = round((xhi - dimoffset(strip, 0)) / dimdelta(strip, 0))
424  xlo = plo * dimdelta(strip, 0) + dimoffset(strip, 0)
425  xhi = phi * dimdelta(strip, 0) + dimoffset(strip, 0)
426  variable nx = phi - plo + 1
427  variable ny = dimsize(strip, 1)
428 
429  duplicate /free strip, strip_copy
430  redimension /n=(nx,ny) strip
431  strip = strip_copy[p + plo][q]
432  setscale /i x xlo, xhi, waveunits(strip, 0), strip
433 };
434 
477 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){
478  wave data
479  string nickname
480  variable theta_offset
481  variable tilt_offset
482  variable phi_offset
483  variable npolar
484  variable nograph
485  variable folding
486  variable xpdplot
487 
488  if (ParamIsDefault(npolar))
489  npolar = 91
490  endif
491  if (ParamIsDefault(nograph))
492  nograph = 0
493  endif
494  if (ParamIsDefault(folding))
495  folding = 1
496  endif
497  if (ParamIsDefault(xpdplot))
498  xpdplot = 0
499  endif
500 
501  // sort out data folder structure
502  dfref saveDF = GetDataFolderDFR()
503  dfref dataDF = GetWavesDataFolderDFR(data)
504  setdatafolder dataDF
505  if (DataFolderExists(":attr"))
506  setdatafolder :attr
507  endif
508  dfref attrDF = GetDataFolderDFR()
509 
510  wave /sdfr=attrDF ManipulatorTheta
511  wave /sdfr=attrDF ManipulatorTilt
512  wave /sdfr=attrDF ManipulatorPhi
513 
514  if ((dimsize(ManipulatorTheta, 0) != dimsize(data, 1)) || (dimsize(ManipulatorTilt, 0) != dimsize(data, 1)) || (dimsize(ManipulatorPhi, 0) != dimsize(data, 1)))
515  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."
516  endif
517 
518  duplicate /free ManipulatorTheta, m_theta
519  duplicate /free ManipulatorTilt, m_tilt
520  duplicate /free ManipulatorPhi, m_phi
521 
522  m_theta -= theta_offset
523  m_tilt -= tilt_offset
524  m_phi -= phi_offset
525 
526  pizza_service_2(data, nickname, m_theta, m_tilt, m_phi, npolar=npolar, nograph=nograph, folding=folding, xpdplot=xpdplot)
527 
528  setdatafolder saveDF
529 };
530 
570 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){
571  wave data
572  string nickname
573  wave m_theta
574  wave m_tilt
575  wave m_phi
576  variable npolar
577  variable nograph
578  variable folding
579  variable xpdplot
580 
581  if (ParamIsDefault(npolar))
582  npolar = 91
583  endif
584  if (ParamIsDefault(nograph))
585  nograph = 0
586  endif
587  if (ParamIsDefault(folding))
588  folding = 1
589  endif
590  if (ParamIsDefault(xpdplot))
591  xpdplot = 0
592  endif
593 
594  if ((dimsize(m_theta, 0) != dimsize(data, 1)) || (dimsize(m_tilt, 0) != dimsize(data, 1)) || (dimsize(m_phi, 0) != dimsize(data, 1)))
595  Abort "Warning: The dimension size of the manipulator waves does not match the Y dimension of the data wave!"
596  endif
597 
598  string graphname = "graph_" + nickname
599  string outprefix = nickname
600 
601  // sort out data folder structure
602  dfref saveDF = GetDataFolderDFR()
603  dfref dataDF = GetWavesDataFolderDFR(data)
604  setdatafolder dataDF
605 
606  if (xpdplot)
607  setdatafolder root:
608  outprefix = nickname
609  else
610  setdatafolder dataDF
611  newdatafolder /s/o $nickname
612  outprefix = ""
613  endif
614  dfref destDF = GetDataFolderDFR()
615 
616  // performance monitoring
617  variable timerRefNum
618  variable /g pol_perf_secs
619  timerRefNum = startMSTimer
620 
621  duplicate /free m_tilt, corr_tilt
622  duplicate /free m_phi, corr_phi
623  corr_tilt = -m_tilt// checked 140702
624  corr_phi = m_phi// checked 140702
625 
626  make /n=1/d/free d_polar, d_azi
627 
628  convert_angles_ttpd2polar(m_theta, corr_tilt, corr_phi, data, d_polar, d_azi)
629  d_azi += 180// changed 151030 (v1.6)
630  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
631  variable ifold
632  for (ifold = 0; ifold < folding; ifold += 1)
633  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
634  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
635  d_azi += 360 / folding
636  endfor
637 
638  // normalize folding
639  if (strlen(outprefix))
640  string s_prefix = outprefix + "_"
641  string s_int = s_prefix + "i"
642  else
643  s_prefix = ""
644  s_int = "values"
645  endif
646  if (folding > 1)
647  wave values = $s_int
648  values /= folding
649  endif
650 
651  if (!nograph)
652  display_hemi_scan(outprefix, graphname = graphname)
653  endif
654 
655  if (timerRefNum >= 0)
656  pol_perf_secs = stopMSTimer(timerRefNum) / 1e6
657  endif
658 
659  setdatafolder saveDF
660 };
661 
687 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){
688  variable theta
689  variable tilt
690  variable phi
691  variable theta_offset
692  variable tilt_offset
693  variable phi_offset
694  variable npolar
695  variable nograph
696  variable xpdplot
697 
698  string nickname = "analyser"
699 
700  if (ParamIsDefault(npolar))
701  npolar = 91
702  endif
703  if (ParamIsDefault(nograph))
704  nograph = 0
705  endif
706  if (ParamIsDefault(xpdplot))
707  xpdplot = 0
708  endif
709  string graphname = "graph_" + nickname
710  string outprefix = nickname
711 
712  // sort out data folder structure
713  dfref saveDF = GetDataFolderDFR()
714  dfref dataDF = saveDF
715  if (xpdplot)
716  setdatafolder root:
717  outprefix = nickname
718  else
719  setdatafolder dataDF
720  newdatafolder /s/o $nickname
721  outprefix = ""
722  endif
723  dfref destDF = GetDataFolderDFR()
724 
725  make /n=1 /free m_theta
726  make /n=1 /free m_tilt
727  make /n=1 /free m_phi
728  m_theta = theta - theta_offset
729  m_tilt = tilt - tilt_offset
730  m_tilt *= -1// checked 140702
731  m_phi = phi - phi_offset
732  //m_phi *= -1 // checked 140702
733 
734  make /n=60 /free data
735  setscale /i x -30, 30, data
736  data = x
737  make /n=1/d/free d_polar, d_azi
738 
739  convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
740  d_azi += 180// changed 151030 (v1.6)
741  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
742  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
743  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
744 
745  if (!nograph)
746  display_hemi_scan(outprefix, graphname = graphname)
747  endif
748 
749  setdatafolder saveDF
750 };
751 
756 
757 variable convert_angles_ttpd2polar(wave theta, wave tilt, wave phi, wave data, wave polar, wave azi){
758  wave theta, tilt, phi// see convert_angles_ttpa2polar
759  wave data// in, 1D or 2D
760  // X-scale must be set to analyser angle scale
761  wave polar, azi// see convert_angles_ttpa2polar
762 
763  make /n=(dimsize(data, 0)) /d /free ana
764  setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), ana
765  ana = x
766  convert_angles_ttpa2polar(theta, tilt, phi, ana, polar, azi)
767 };
768 
796 variable convert_angles_ttpa2polar(wave theta, wave tilt, wave phi, wave analyser, wave polar, wave azi){
797  wave theta
798  wave tilt
799  wave phi
800  wave analyser
801  wave polar, azi
802 
803  variable nn = numpnts(theta)
804  variable na = numpnts(analyser)
805  redimension /n=(na, nn) polar, azi
806 
807  variable radius = 1// don't need to specify - everything is scalable
808 
809  // step 1: calculate cartesian detection vectors at normal emission
810  // this is simply a polar-cartesian mapping, independent of the manipulator
811  // phi=0 is in the polar rotation plane
812  make /n=(3,na) /d /free w_orig_polar, w_orig_cart, w_rot_cart, w_rot_polar
813  w_orig_polar[0][] = radius
814  w_orig_polar[1][] = analyser[q]
815  w_orig_polar[2][] = 0
816  polar2cart_wave(w_orig_polar, w_orig_cart)
817  // if the angle-dispersive axis was horizontal, we'd need to rotate the detector
818  //rotate_z_wave(w_orig_cart, 90)
819 
820  variable ii
821  for (ii = 0; ii < nn; ii += 1)
822  // step 2: rotate the detection vectors according to the manipulator angles
823  // the order of rotations is important because we rotate about fixed axes
824  // y-axis = tilt rotation axis
825  // x-axis = polar rotation axis
826  // z-axis = normal emission = azimuthal rotation axis
827  w_rot_cart = w_orig_cart
828  rotate_y_wave(w_rot_cart, -tilt[ii])
829  rotate_x_wave(w_rot_cart, -theta[ii])
830  rotate_z_wave(w_rot_cart, -phi[ii] - 90)
831  // map the vectors back to the sample coordinate system
832  cart2polar_wave(w_rot_cart, w_rot_polar)
833  // copy to output
834  polar[][ii] = w_rot_polar[1][p]
835  azi[][ii] = w_rot_polar[2][p]
836  endfor
837 };
838 
839 static variable line_average(wave source, wave dest){
840  // is this function used?
841  wave source
842  wave dest
843 
844  variable ii
845  variable nn = dimsize(source, 1)
846  make /n=(dimsize(source, 0))/d/free line
847  for (ii = 0; ii < nn; ii += 1)
848  line = source[p][ii]
849  wavestats /q line
850  dest[][ii] = line[p] / v_max
851  endfor
852 };
853 
857 static variable calc_nth(variable Theta_st, variable Theta_in, variable th, variable Phi_ran, variable Phi_ref, string Holomode){
858  Variable Theta_st, Theta_in, th, Phi_ran, Phi_ref
859  String Holomode
860  Variable The_step
861  Variable deg2rad=0.01745329
862 
863  if ( cmpstr(Holomode, "Stereographic") == 0)
864  The_step =trunc( Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st )
865  if(th==90)
866  The_step =trunc( Phi_ran*sin(th*pi/180)*Phi_ref/Theta_st )
867  endif
868  else
869  if (cmpstr(Holomode, "Parallel") == 0)
870  The_step=trunc( Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st )
871  else
872  if ( cmpstr(Holomode, "h") == 0)
873  The_step=trunc( th/Theta_in*Phi_ran/Theta_st )
874  else
875  //altro
876  endif
877  endif
878  endif
879 
880  return(The_step)
881 };
882 
886 static variable calc_phi_step(variable Theta_in, variable th, variable Theta_st, variable Phi_ran, variable Phi_ref, string Holomode){
887  Variable Theta_in, th, Theta_st, Phi_ran, Phi_ref
888  String Holomode
889 
890  Variable Phi_st
891  Variable deg2rad=0.01745329
892 
893  if ( cmpstr(Holomode, "Stereographic") == 0 )
894  if ((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
895  Phi_st=0.0
896  else
897  Phi_st=Phi_ran/(trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st))
898  endif
899  if(th==90)
900  Phi_st=2.0
901  endif
902  endif
903 
904  if ( cmpstr(Holomode, "Parallel") == 0 )
905  if((th < 0.5) || (trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st) == 0))
906  Phi_st=0.0
907  else
908  Phi_st=Phi_ran/(trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st))
909  endif
910  endif
911 
912  if ( cmpstr(Holomode, "h") == 0 )
913  if((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
914  Phi_st=0.0
915  else
916  Phi_st=Phi_ran/trunc(th/Theta_in*Phi_ran/Theta_st)
917  endif
918  endif
919 
920  if (Phi_st==0)
921  Phi_st=360
922  endif
923 
924  return(Phi_st)
925 };
926 
930 static variable Calc_The_step(variable th, variable Theta_st, string Holomode){
931  String Holomode
932  Variable th, Theta_st
933 
934  Variable deg2rad=0.01745329, dt_loc,The_step
935 
936  if ( (cmpstr(Holomode, "Stereographic")) ==0 )
937  The_step=Theta_st
938  endif
939 
940  if ( (cmpstr(Holomode, "h")) ==0 )
941  The_step=Theta_st
942  endif
943 
944  if ( cmpstr(Holomode, "Parallel") == 0 )
945  if(th < 89.5)
946  dt_loc = Theta_st/cos(th*deg2rad)
947  if(dt_loc > 10)
948  dt_loc=10
949  endif
950  The_step=dt_loc
951  else
952  The_step=10
953  endif
954  endif
955  return(The_step)
956 };
957 
961 static variable CalcN_Theta(string HoloMode, variable Theta_in, variable Theta_ran, variable Theta_st){
962  String HoloMode
963  Variable Theta_in,Theta_ran,Theta_st
964  Variable n_theta, aux, aux1,ii
965 
966  aux = Theta_in
967  aux1= Theta_in - Theta_ran
968  ii = 0
969  do
970  aux = aux - Calc_The_step(aux, Theta_st, HoloMode)
971  if(aux<=Theta_in-Theta_ran)
972  aux=Theta_in-Theta_ran
973  endif
974  ii = ii+1
975  while((aux>aux1)%&(Theta_in-aux<=Theta_ran))//
976  n_theta=ii+1
977  Return(n_theta)
978 };
979 
999 variable make_hemi_grid(variable npol, string nickname, variable xpdplot = defaultValue){
1000  variable npol
1001  string nickname
1002  variable xpdplot
1003 
1004  if (ParamIsDefault(xpdplot))
1005  xpdplot = 0
1006  endif
1007 
1008  string HoloMode = "h"
1009  variable Theta_in = 90
1010  variable Theta_ran = 90
1011  variable Theta_st = 90 / (npol - 1)
1012  variable Phi_ran = 360
1013  variable Phi_ref = 1
1014  variable Phi_in = 0
1015 
1016  variable n_theta = CalcN_Theta(HoloMode, Theta_in, Theta_ran, Theta_st)
1017 
1018  // wave names
1019  if (strlen(nickname))
1020  string s_prefix = nickname + "_"
1021  string s_int = s_prefix + "i"// Intensity wave (counts/sec)
1022  else
1023  s_prefix = ""
1024  s_int = "values"// "i" is not a valid wave name
1025  endif
1026  string s_polar = s_prefix + "pol"// thetas for each int-point of the holo
1027  string s_azim = s_prefix + "az"// phis for each int-point of the holo
1028 
1029  string s_index = s_prefix + "index"// starting index for each theta
1030  string s_theta = s_prefix + "th"// theta values
1031  string s_dphi = s_prefix + "dphi"// delta phis at each theta
1032  string s_nphis = s_prefix + "nphis"// number of phis at each theta
1033 
1034  string s_HoloData = s_prefix + "data"// All holo exp.- parameter information
1035  string s_HoloInfo = s_prefix + "info"
1036 
1037  // the following two waves are used by the pearl-anglescan procedures but not by XPDplot
1038  string s_tot = s_prefix + "tot"// accumulated counts at each point
1039  string s_weight = s_prefix + "wt"// total accumulation time at each point (arb. units)
1040 
1041  make /O/D/n=(n_theta) $s_index /wave=index
1042  make /O/D/n=(n_theta) $s_theta /wave=theta
1043  make /O/D/n=(n_theta) $s_dphi /wave=dphi
1044  make /O/D/n=(n_theta) $s_nphis /wave=nphis
1045 
1046  //---------- calculate phi-step-size for this theta:
1047  variable aux = Calc_The_step(Theta_in, Theta_st, HoloMode)
1048  dphi[0] = calc_phi_step(Theta_in, Theta_in, aux, Phi_ran, Phi_ref, HoloMode)
1049  Theta[0] = Theta_in
1050  nphis[0] = calc_nth(aux, Theta_in, Theta_in, Phi_ran, Phi_ref, HoloMode)
1051  Index[0] = nphis[0]
1052 
1053  //---------- calculate number of phis, phi-step, and starting-index for each theta:
1054  variable ii = 1
1055  do
1056  Theta[ii] = Theta[ii-1] - aux
1057  if(Theta[ii] <= Theta_in-Theta_ran)
1058  Theta[ii] = Theta_in-Theta_ran
1059  endif
1060  aux = Calc_The_step(Theta[ii], Theta_st, HoloMode)
1061  dphi[ii] = calc_phi_step(Theta_in, Theta[ii], aux, Phi_ran, Phi_ref, HoloMode)
1062  nphis[ii] = calc_nth(aux, Theta_in, Theta[ii], Phi_ran, Phi_ref, HoloMode)
1063  Index[ii] = Index[ii-1] + nphis[ii]
1064  ii=ii+1
1065  while(ii < n_theta)
1066 
1067  if (Index[n_theta-1]==Index[n_theta-2])
1068  Index[n_theta-1]=Index[n_theta-2]+1
1069  nphis[n_theta-1]=1
1070  endif
1071 
1072  variable NumPoints = sum(nphis, 0, numpnts(nphis))
1073 
1074  //---------- calculate theta and phi for each data point:
1075  make /O/D/N=(NumPoints) $s_polar /wave=polar, $s_azim /wave=azim
1076  note azim, "version=1.6"
1077 
1078  ii = 0
1079  variable StartIndex = 0
1080  variable EndIndex
1081  do
1082  EndIndex=Index[ii]
1083  Polar[StartIndex, EndIndex-1]=Theta[ii]
1084  Azim[StartIndex, EndIndex-1]= mod(Phi_ran+(x-StartIndex)*dphi[ii]+Phi_in,Phi_ran)
1085  ii = ii + 1
1086  StartIndex = EndIndex
1087  while(ii < n_theta)
1088 
1089  duplicate /o azim, $s_int /wave=values
1090  duplicate /o azim, $s_tot /wave=totals
1091  duplicate /o azim, $s_weight /wave=weights
1092  values = nan
1093  totals = 0
1094  weights = 0
1095 
1096  // XPDplot metadata
1097  if (xpdplot)
1098  string s_FileName = ""
1099  string s_Comment = "created by pearl-anglescan-process.ipf"
1100  string s_HoloMode = "Stereographic"
1101  variable /g gb_SpectraFile = 0
1102 
1103  Make/O/D/n=22 $s_HoloData /wave=HoloData
1104  HoloData[0] = NaN// v_StartKE
1105  HoloData[1] = NaN// v_StoppKE
1106  HoloData[6] = NumPoints
1107  HoloData[7] = Theta_in
1108  HoloData[8] = Theta_ran
1109  HoloData[9] = Theta_st
1110  HoloData[11] = Phi_in
1111  HoloData[12] = Phi_ran
1112  HoloData[13] = Theta_st
1113  HoloData[15] = Phi_ref
1114  HoloData[16] = Phi_ran
1115  HoloData[17] = 0// v_HoloBit (stereographic)
1116 
1117  Make/O/T/n=22 $s_HoloInfo /wave=HoloInfo
1118  HoloInfo[0] = s_FileName
1119  HoloInfo[1] = s_Comment
1120  HoloInfo[10] = s_HoloMode
1121  HoloInfo[11] = ""// s_MeasuringMode
1122 
1123  // notebook for XPDplot
1124  if (WinType(NickName) == 5)
1125  Notebook $NickName selection={startOfFile, endOfFile}
1126  Notebook $NickName text=""
1127  else
1128  NewNotebook /F=0 /K=1 /N=$NickName /W=(5,40,341,260)
1129  Notebook $NickName defaultTab=140
1130  Notebook $NickName statusWidth=300
1131  Notebook $NickName backRGB=(56797,56797,56797)
1132  Notebook $NickName pageMargins={80,80,80,80}
1133  Notebook $NickName fSize=10
1134  Notebook $NickName fStyle=0,textRGB=(65535,0,26214)
1135  Notebook $NickName textRGB=(65535,0,26214)
1136  endif
1137  Notebook $NickName text = "File:\t" + s_FileName + "\r"
1138  Notebook $NickName text = "*** " + s_Comment + " ***\r\r"
1139  Notebook $NickName text = "Angle-Mode:\t" + s_HoloMode + "\r"
1140  Notebook $NickName text = "XPDplot Nickname:\t" + NickName + "\r"
1141  endif
1142 };
1143 
1150 string get_hemi_nickname(wave w){
1151  wave w
1152 
1153  string prefix = get_hemi_prefix(w)
1154  string wname = nameofwave(w)
1155  string nickname
1156 
1157  if (strlen(prefix))
1158  nickname = prefix
1159  else
1160  string s_wave_df = GetWavesDataFolder(w, 1)
1161  dfref parent_df = $(s_wave_df + "::")
1162  nickname = GetDataFolder(0, parent_df)
1163  endif
1164 
1165  return nickname
1166 };
1167 
1175 string get_hemi_prefix(wave w){
1176  wave w
1177 
1178  string wname = nameofwave(w)
1179  string prefix
1180  if (ItemsInList(wname, "_") >= 2)
1181  prefix = StringFromList(0, wname, "_")
1182  else
1183  prefix = ""
1184  endif
1185 
1186  return prefix
1187 };
1188 
1206 dfr find_hemi_data(string nickname, string* prefix, string* intwave){
1207  string nickname
1208  string &prefix
1209  string &intwave
1210 
1211  dfref datadf
1212  prefix = ""
1213  intwave = "values"
1214  if (strlen(nickname))
1215  if (DataFolderExists(nickname))
1216  datadf = $nickname
1217  else
1218  datadf = getdatafolderdfr()
1219  prefix = nickname + "_"
1220  intwave = prefix + "i"
1221  if (exists(intwave) != 1)
1222  datadf = root:
1223  endif
1224  endif
1225  else
1226  datadf = getdatafolderdfr()
1227  prefix = ""
1228  intwave = "values"
1229  endif
1230  return datadf
1231 };
1232 
1240 variable clear_hemi_grid(string nickname){
1241  string nickname
1242 
1243  dfref datadf
1244  string s_prefix
1245  string s_int
1246  datadf = find_hemi_data(nickname, s_prefix, s_int)
1247 
1248  string s_totals = s_prefix + "tot"
1249  string s_weights = s_prefix + "wt"
1250 
1251  wave /sdfr=datadf /z w_values = $s_int
1252  wave /sdfr=datadf /z w_totals = $s_totals
1253  wave /sdfr=datadf /z w_weights = $s_weights
1254 
1255  if (waveexists(w_totals))
1256  w_totals = 0
1257  endif
1258  if (waveexists(w_weights))
1259  w_weights = 0
1260  endif
1261  if (waveexists(w_values))
1262  w_values = nan
1263  endif
1264 };
1265 
1287 variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot = defaultValue){
1288  string source_nickname
1289  dfref dest_folder
1290  string dest_nickname
1291  variable xpdplot
1292 
1293  if (ParamIsDefault(xpdplot))
1294  xpdplot = 0
1295  endif
1296 
1297  dfref savedf = getdatafolderdfr()
1298 
1299  // source data
1300  if (strlen(source_nickname))
1301  string s_prefix = source_nickname + "_"
1302  string s_int = s_prefix + "i"
1303  else
1304  s_prefix = ""
1305  s_int = "values"
1306  endif
1307  string s_polar = s_prefix + "pol"
1308  string s_azim = s_prefix + "az"
1309  string s_theta = s_prefix + "th"
1310  string s_tot = s_prefix + "tot"
1311  string s_weight = s_prefix + "wt"
1312  string s_matrix = s_prefix + "matrix"
1313 
1314  wave theta1 = $s_theta
1315  wave polar1 = $s_polar
1316  wave azim1 = $s_azim
1317  wave tot1 = $s_tot
1318  wave weight1 = $s_weight
1319  wave values1 = $s_int
1320  wave /z matrix1 = $s_matrix
1321 
1322  variable npol = numpnts(theta1)
1323 
1324  setdatafolder dest_folder
1325  make_hemi_grid(npol, dest_nickname, xpdplot=xpdplot)
1326 
1327  // dest data
1328  if (strlen(dest_nickname))
1329  s_prefix = dest_nickname + "_"
1330  s_int = s_prefix + "i"
1331  else
1332  s_prefix = ""
1333  s_int = "values"
1334  endif
1335  s_polar = s_prefix + "pol"
1336  s_azim = s_prefix + "az"
1337  s_theta = s_prefix + "th"
1338  s_tot = s_prefix + "tot"
1339  s_weight = s_prefix + "wt"
1340  s_matrix = s_prefix + "matrix"
1341 
1342  wave theta2 = $s_theta
1343  wave polar2 = $s_polar
1344  wave azim2 = $s_azim
1345  wave tot2 = $s_tot
1346  wave weight2 = $s_weight
1347  wave values2 = $s_int
1348 
1349  tot2 = tot1
1350  weight2 = weight1
1351  values2 = values1
1352  if (waveexists(matrix1))
1353  duplicate /o matrix1, $s_matrix
1354  endif
1355 
1356  if (!(NumberByKey("version", note(azim1), "=", "\r") >= 1.6))
1357  azim2 += 180// changed 151030 (v1.6)
1358  azim2 = azim2 >= 360 ? azim2 - 360 : azim2
1359  endif
1360 
1361  setdatafolder saveDF
1362 };
1363 
1371 variable rotate_hemi_scan(string nickname, variable angle){
1372  string nickname
1373  variable angle
1374 
1375  dfref savedf = getdatafolderdfr()
1376 
1377  if (strlen(nickname))
1378  string s_prefix = nickname + "_"
1379  string s_int = s_prefix + "i"
1380  else
1381  s_prefix = ""
1382  s_int = "values"
1383  endif
1384  string s_polar = s_prefix + "pol"
1385  string s_azim = s_prefix + "az"
1386  string s_tot = s_prefix + "tot"
1387  string s_weight = s_prefix + "wt"
1388 
1389  wave polar = $s_polar
1390  wave azim = $s_azim
1391  wave tot = $s_tot
1392  wave weight = $s_weight
1393  wave values = $s_int
1394 
1395  azim += angle
1396  azim = azim < 0 ? azim + 360 : azim
1397  azim = azim >= 360 ? azim - 360 : azim
1398 
1399  duplicate /free polar, neg_polar
1400  neg_polar = -polar
1401  sort {neg_polar, azim}, polar, azim, tot, weight, values
1402 
1403  setdatafolder saveDF
1404 };
1405 
1450 string display_hemi_scan(string nickname, variable projection = defaultValue, variable graphtype = defaultValue, variable do_ticks = defaultValue, variable do_grids = defaultValue, string graphname = defaultValue){
1451  string nickname
1452  variable projection
1453  variable graphtype
1454  variable do_ticks
1455  variable do_grids
1456  string graphname
1457 
1458  if (ParamIsDefault(projection))
1459  projection = 1
1460  endif
1461  if (ParamIsDefault(graphtype))
1462  graphtype = 1
1463  endif
1464  if (ParamIsDefault(do_ticks))
1465  do_ticks = 3
1466  endif
1467  if (ParamIsDefault(do_grids))
1468  do_grids = 3
1469  endif
1470  if (ParamIsDefault(graphname))
1471  if (strlen(nickname) > 0)
1472  graphname = nickname
1473  else
1474  graphname = GetDataFolder(0)
1475  endif
1476  endif
1477 
1478  // hemi grid waves
1479  if (strlen(nickname))
1480  string s_prefix = nickname + "_"
1481  string s_int = s_prefix + "i"
1482  else
1483  s_prefix = ""
1484  s_int = "values"
1485  endif
1486  string s_polar = s_prefix + "pol"
1487  string s_azim = s_prefix + "az"
1488  string s_matrix = s_prefix + "matrix"
1489 
1490  wave /z values = $s_int
1491  wave /z azim = $s_azim
1492  wave /z polar = $s_polar
1493  wave /z matrix = $s_matrix
1494 
1495  string s_ster_rad = s_prefix + "ster_rad"
1496  duplicate /o polar, $s_ster_rad /wave=ster_rad
1497  ster_rad = calc_graph_radius(polar, projection=projection)
1498 
1499  string s_ster_x = s_prefix + "ster_x"
1500  string s_ster_y = s_prefix + "ster_y"
1501  duplicate /o azim, $s_ster_x /wave=ster_x, $s_ster_y /wave=ster_y
1502  ster_x = ster_rad * cos(azim * pi / 180)
1503  ster_y = ster_rad * sin(azim * pi / 180)
1504 
1505  variable azim_offset = 0
1506  if (!(NumberByKey("version", note(azim), "=", "\r") >= 1.6))
1507  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!"
1508  azim_offset = 180// changed 151030 (v1.6)
1509  endif
1510 
1511  string s_trace
1512  switch(graphtype)
1513  case 1:
1514  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1515 
1516  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1517  ModifyGraph /W=$graphname mode($s_trace)=2, lsize($s_trace)=2
1518  ModifyGraph /W=$graphname zColor($s_trace)={values,*,*,BlueGreenOrange,0}
1519 
1520  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 trace=polarY0
1521  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1522  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1523 
1524  SetWindow $graphname, userdata(projection)=num2str(projection)
1525  draw_hemi_axes(graphname, do_grids=do_grids)
1526  break
1527  case 3:
1528  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1529 
1530  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1531  ModifyGraph /W=$graphname mode($s_trace)=0, lsize($s_trace)=0
1532  AppendImage /L=VertCrossing /B=HorizCrossing matrix
1533 
1534  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 image=$s_matrix
1535  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1536  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1537 
1538  SetWindow $graphname, userdata(projection)=num2str(projection)
1539  draw_hemi_axes(graphname, do_grids=do_grids)
1540  break
1541  endswitch
1542 
1543  return graphname
1544 };
1545 
1587 static string display_polar_graph(string graphname, variable angle_offset = defaultValue, variable do_ticks = defaultValue){
1588 
1589  string graphname
1590  variable angle_offset
1591  variable do_ticks
1592 
1593  dfref savedf = GetDataFolderDFR()
1594 
1595  if (ParamIsDefault(angle_offset))
1596  angle_offset = 0
1597  endif
1598  if (ParamIsDefault(do_ticks))
1599  do_ticks = 3
1600  endif
1601 
1602  if ((strlen(graphname) == 0) || (wintype(graphname) == 0))
1603  Display /k=1 /W=(10,45,360,345)
1604  DoWindow /C $graphname
1605  graphname = WMNewPolarGraph("", graphname)
1606  WMPolarGraphSetVar(graphname, "zeroAngleWhere", angle_offset)
1607 
1608  WMPolarGraphSetVar(graphname, "angleAxisThick", 0.5)
1609  WMPolarGraphSetStr(graphname, "doMajorAngleTicks", "manual")
1610  WMPolarGraphSetVar(graphname, "majorAngleInc", 30)// major ticks in 30 deg steps
1611  WMPolarGraphSetVar(graphname, "minorAngleTicks", 2)// minor ticks in 10 deg steps
1612  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1613  WMPolarGraphSetVar(graphname, "doAngleTickLabelSubRange", 1)
1614  WMPolarGraphSetVar(graphname, "angleTickLabelRangeStart", 0)
1615  WMPolarGraphSetVar(graphname, "angleTickLabelRangeExtent", 90)
1616  WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g")
1617 
1618  WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
1619  WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
1620  WMPolarGraphSetStr(graphname, "radiusAxesWhere", " Off")// note the leading spaces, cf. WMPolarAnglesForRadiusAxes
1621  WMPolarGraphSetStr(graphname, "radiusTicksLocation", "Off")
1622 
1623  WMPolarGraphSetVar(graphname, "majorTickLength", 2)
1624  WMPolarGraphSetVar(graphname, "majorTickThick", 0.5)
1625  WMPolarGraphSetVar(graphname, "minorTickLength", 1)
1626  WMPolarGraphSetVar(graphname, "minorTickThick", 0.5)
1627  WMPolarGraphSetVar(graphname, "tickLabelOpaque", 0)
1628  WMPolarGraphSetVar(graphname, "tickLabelFontSize", 7)
1629 
1630  // changes
1631  if (do_ticks & 1)
1632  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1633  else
1634  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Off")
1635  endif
1636  if (do_ticks & 2)
1637  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 1)
1638  else
1639  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 0)
1640  endif
1641 
1642  DoWindow /T $graphname, graphname
1643 
1644  // cursor info in angles
1645  string graphdf = "root:packages:WMPolarGraphs:" + graphname
1646  setdatafolder graphdf
1647  // current theta, phi coordinates are stored in global variables in the package folder of the graph
1648  variable /g csrA_theta
1649  variable /g csrA_phi
1650  variable /g csrB_theta
1651  variable /g csrB_phi
1652  // the text box is hidden initially. it shows up and hides with the cursor info box.
1653  string tb
1654  tb = "\\{"
1655  tb = tb + "\"A = (%.1f, %.1f)\","
1656  tb = tb + graphdf + ":csrA_theta,"
1657  tb = tb + graphdf + ":csrA_phi"
1658  tb = tb + "}"
1659  TextBox /W=$graphname /A=LT /B=1 /E=2 /F=0 /N=tb_angles /X=1 /Y=1 /V=0 tb
1660  tb = "\\{"
1661  tb = tb + "\"B = (%.1f, %.1f)\","
1662  tb = tb + graphdf + ":csrB_theta,"
1663  tb = tb + graphdf + ":csrB_phi"
1664  tb = tb + "}"
1665  AppendText /W=$graphname /N=tb_angles tb
1666  // updates are triggered by a window hook
1667  SetWindow $graphname, hook(polar_graph_hook)=PearlAnglescanProcess#polar_graph_hook
1668  else
1669  // graph window exists
1670  DoWindow /F $graphname
1671  endif
1672 
1673  setdatafolder savedf
1674  return graphname
1675 };
1676 
1702 static string draw_hemi_axes(string graphname, variable do_grids = defaultValue){
1703  string graphname
1704  variable do_grids
1705 
1706  if (ParamIsDefault(do_grids))
1707  do_grids = 3
1708  endif
1709 
1710  dfref savedf = GetDataFolderDFR()
1711 
1712  string sproj = GetUserData(graphname, "", "projection")
1713  variable projection = str2num("0" + sproj)
1714 
1715  SetDrawLayer /W=$graphname ProgFront
1716 
1717  // polar axis
1718  SetDrawEnv /W=$graphname xcoord=HorizCrossing, ycoord=VertCrossing
1719  SetDrawEnv /W=$graphname linethick= 0.5
1720  SetDrawEnv /W=$graphname dash=2
1721  SetDrawEnv /W=$graphname fillpat=0
1722  SetDrawEnv /W=$graphname fname="default", fsize=7
1723  SetDrawEnv /W=$graphname textxjust=1, textyjust=1
1724  //SetDrawEnv /W=$graphname linefgc=(65535,65535,65535)
1725  SetDrawEnv /W=$graphname save
1726 
1727  if (do_grids & 1)
1728  DrawLine /W=$graphname 0, -2, 0, 2
1729  DrawLine /W=$graphname -2, 0, 2, 0
1730  endif
1731 
1732  variable radi
1733  if (do_grids & 2)
1734  radi = calc_graph_radius(0.5, projection=projection)
1735  DrawOval /W=$graphname -radi, radi, radi, -radi
1736  radi = calc_graph_radius(30, projection=projection)
1737  DrawOval /W=$graphname -radi, radi, radi, -radi
1738  radi = calc_graph_radius(60, projection=projection)
1739  DrawOval /W=$graphname -radi, radi, radi, -radi
1740 
1741  SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
1742  SetDrawEnv /W=$graphname save
1743  radi = calc_graph_radius(30, projection=projection)
1744  DrawText /W=$graphname radi, -0.1, "30"
1745  radi = calc_graph_radius(60, projection=projection)
1746  DrawText /W=$graphname radi, -0.1, "60"
1747  endif
1748 
1749  setdatafolder savedf
1750 };
1751 
1774 variable draw_diffraction_cone(string graphname, string groupname, variable theta_axis, variable theta_inner, variable phi){
1775  string graphname
1776  string groupname
1777 
1778  variable theta_axis
1779  variable theta_inner
1780  variable phi
1781 
1782  variable r_axis = calc_graph_radius(theta_axis)
1783  variable r_inner = calc_graph_radius(theta_inner)
1784  variable r_outer = calc_graph_radius(2 * theta_axis - theta_inner)
1785 
1786  SetDrawEnv push
1787  SetDrawLayer UserFront
1788  DrawAction getgroup=$groupname, delete
1789  SetDrawEnv gstart, gname=$groupname
1790  variable xc, yc, xr, yr
1791 
1792  // cone periphery
1793  variable r_center = (r_outer + r_inner) / 2
1794  variable r_radius = (r_outer - r_inner) / 2
1795  xc = r_center * cos(phi * pi / 180)
1796  yc = r_center * sin(phi * pi / 180)
1797  xr = r_radius
1798  yr = r_radius
1799  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1800  SetDrawEnv dash=11, fillpat=0
1801  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1802 
1803  // cone axis
1804  xc = r_axis * cos(phi * pi / 180)
1805  yc = r_axis * sin(phi * pi / 180)
1806  r_radius = calc_graph_radius(2)
1807  xr = r_radius
1808  yr = r_radius
1809  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1810  SetDrawEnv fillfgc=(0,0,0)
1811  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1812 
1813  SetDrawEnv gstop
1814  SetDrawEnv pop
1815 };
1816 
1838 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){
1839  string nickname
1840  variable alpha_lo
1841  variable alpha_hi
1842  wave m_theta
1843  wave m_tilt
1844  wave m_phi
1845  variable folding
1846  variable projection
1847 
1848  if (ParamIsDefault(folding))
1849  folding = 1
1850  endif
1851  if (ParamIsDefault(projection))
1852  projection = 1
1853  endif
1854 
1855  // sort out data folder structure
1856  dfref saveDF = GetDataFolderDFR()
1857  newdatafolder /s/o $nickname
1858  string graphname = "graph_" + nickname
1859 
1860  duplicate /free m_tilt, loc_m_tilt
1861  loc_m_tilt = -m_tilt
1862 
1863  make /n=1 /d /free d_polar, d_azi
1864  variable n_alpha = round(alpha_hi - alpha_lo) + 1
1865  make /n=(n_alpha) /d /free analyser
1866  setscale /i x alpha_lo, alpha_hi, "", analyser
1867  analyser = x
1868 
1869  convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
1870  duplicate /free d_polar, d_radius
1871  d_radius = calc_graph_radius(d_polar, projection=projection)
1872  d_azi += 180// changed 151030 (v1.6)
1873 
1874  graphname = display_polar_graph(graphname)
1875  SetWindow $graphname, userdata(projection)=num2str(projection)
1876 
1877  variable ifold
1878  variable iang
1879  variable nang = numpnts(m_theta)
1880  string s_rad
1881  string s_azi
1882  string s_trace
1883  for (ifold = 0; ifold < folding; ifold += 1)
1884  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
1885  for (iang = 0; iang < nang; iang += 1)
1886  sprintf s_rad, "rad_%d_%d", ifold, iang
1887  duplicate /o analyser, $s_rad
1888  wave w_rad = $s_rad
1889  w_rad = d_radius[p][iang]
1890 
1891  sprintf s_azi, "azi_%d_%d", ifold, iang
1892  duplicate /o analyser, $s_azi
1893  wave w_azi = $s_azi
1894  w_azi = d_azi[p][iang]
1895 
1896  if (numtype(sum(w_rad)) == 0)
1897  s_trace = WMPolarAppendTrace(graphname, w_rad, w_azi, 360)
1898  ModifyGraph /w=$graphname mode($s_trace)=0, lsize($s_trace)=0.5
1899  endif
1900  endfor
1901  d_azi += 360 / folding
1902  endfor
1903 
1904  draw_hemi_axes(graphname)
1905 
1906  setdatafolder saveDF
1907  return graphname
1908 };
1909 
1926 const variable kProjDist = 0;
1927 const variable kProjStereo = 1;
1928 const variable kProjArea = 2;
1929 const variable kProjGnom = 3;
1930 const variable kProjOrtho = 4;
1931 
1932 static const variable kProjScaleDist = 2;
1933 static const variable kProjScaleStereo = 2;
1934 static const variable kProjScaleArea = 2;
1935 // scaled so that radius(gnom) = radius(stereo) for polar = 88
1936 static const variable kProjScaleGnom = 0.06744519021;
1937 static const variable kProjScaleOrtho = 2;
1938 
1953 threadsafe variable calc_graph_radius(variable polar, variable projection = defaultValue){
1954  variable polar
1955  variable projection
1956 
1957  if (ParamIsDefault(projection))
1958  projection = 1
1959  endif
1960 
1961  variable radius
1962  switch(projection)
1963  case kProjStereo:// stereographic
1964  radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
1965  break
1966  case kProjArea:// equal area
1967  radius = kProjScaleArea * sin(polar / 2 * pi / 180)
1968  break
1969  case kProjGnom:// gnomonic
1970  radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
1971  break
1972  case kProjOrtho:// orthographic
1973  radius = kProjScaleOrtho * sin(polar * pi / 180)
1974  break
1975  default:// equidistant
1976  radius = kProjScaleDist * polar / 90
1977  endswitch
1978 
1979  return radius
1980 };
1981 
1998 threadsafe variable calc_graph_polar(variable x, variable y, variable projection = defaultValue){
1999  variable x
2000  variable y
2001  variable projection
2002 
2003  if (ParamIsDefault(projection))
2004  projection = 1
2005  endif
2006 
2007  variable radius
2008  variable polar
2009 
2010  radius = sqrt(x^2 + y^2)
2011  switch(projection)
2012  case kProjStereo:// stereographic
2013  polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
2014  break
2015  case kProjArea:// equal area
2016  polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
2017  break
2018  case kProjGnom:// gnomonic
2019  polar = atan(radius / kProjScaleGnom) * 180 / pi
2020  break
2021  case kProjOrtho:// orthographic
2022  polar = asin(radius / kProjScaleOrtho) * 180 / pi
2023  break
2024  default:// equidistant
2025  polar = 90 * radius / kProjScaleDist
2026  endswitch
2027 
2028  return polar
2029 };
2030 
2051 threadsafe variable calc_graph_azi(variable x, variable y, variable projection = defaultValue, variable zeroAngle = defaultValue){
2052  variable x
2053  variable y
2054  variable projection
2055  variable zeroAngle
2056 
2057  if (ParamIsDefault(projection))
2058  projection = 1
2059  endif
2060  if (ParamIsDefault(zeroAngle))
2061  zeroAngle = 0
2062  endif
2063 
2064  variable azi
2065  if (x > 0)
2066  azi = atan(y / x) * 180 / pi
2067  else
2068  azi = atan(y / x) * 180 / pi + 180
2069  endif
2070 
2071  azi += zeroAngle
2072  if (azi < 0)
2073  azi += 360
2074  endif
2075  if (azi >= 360)
2076  azi -= 360
2077  endif
2078  if (numtype(azi) != 0)
2079  azi = 0
2080  endif
2081 
2082  return azi
2083 };
2084 
2096 static variable update_polar_info(string graphname){
2097  string graphname
2098 
2099  dfref savedf = GetDataFolderDFR()
2100 
2101  string graphdf = "root:packages:WMPolarGraphs:" + graphname
2102  setdatafolder graphdf
2103 
2104  nvar csrA_theta
2105  nvar csrA_phi
2106  nvar csrB_theta
2107  nvar csrB_phi
2108 
2109  string sproj = GetUserData(graphname, "", "projection")
2110  variable projection = str2num("0" + sproj)
2111  nvar zeroAngleWhere
2112 
2113  variable x = hcsr(A, graphname)
2114  variable y = vcsr(A, graphname)
2115  csrA_theta = calc_graph_polar(x, y, projection=projection)
2116  csrA_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2117 
2118  x = hcsr(B, graphname)
2119  y = vcsr(B, graphname)
2120  csrB_theta = calc_graph_polar(x, y, projection=projection)
2121  csrB_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2122 
2123  setdatafolder savedf
2124 };
2125 
2131 static variable polar_graph_hook(WMWinHookStruct* s){
2132  STRUCT WMWinHookStruct &s
2133 
2134  Variable hookResult = 0
2135 
2136  switch(s.eventCode)
2137  case 7:// cursor moved
2138  update_polar_info(s.winname)
2139  break
2140  case 20:// show info
2141  TextBox /W=$s.winname /N=tb_angles /C /V=1
2142  break
2143  case 21:// hide info
2144  TextBox /W=$s.winname /N=tb_angles /C /V=0
2145  break
2146  endswitch
2147 
2148  return hookResult// 0 if nothing done, else 1
2149 };
2150 
2151 variable set_polar_graph_cursor(string nickname, string cursorname, variable polar_angle, variable azim_angle, string graphname = defaultValue){
2152  string nickname
2153  string cursorname
2154  variable polar_angle
2155  variable azim_angle
2156  string graphname
2157 
2158  if (ParamIsDefault(graphname))
2159  if (strlen(nickname) > 0)
2160  graphname = nickname
2161  else
2162  graphname = GetDataFolder(0)
2163  endif
2164  endif
2165 
2166  if (strlen(nickname))
2167  string s_prefix = nickname + "_"
2168  else
2169  s_prefix = ""
2170  endif
2171  string s_polar = s_prefix + "pol"
2172  string s_azim = s_prefix + "az"
2173  wave /z azim = $s_azim
2174  wave /z polar = $s_polar
2175 
2176  FindLevel /P /Q polar, polar_angle
2177  if (v_flag == 0)
2178  variable polar_level = floor(v_levelx)
2179  FindLevel /P /Q /R=[polar_level] azim, azim_angle
2180  if (v_flag == 0)
2181  variable azim_level = round(v_levelx)
2182  string tracename = "polarY0"
2183  Cursor /W=$graphname /P $cursorname $traceName azim_level
2184  endif
2185  endif
2186 };
2187 
2197 variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights = defaultValue){
2198  string nickname// name prefix of holo waves.
2199  // may be empty.
2200  wave values// intensity values
2201  // the wave can be one- or two-dimensional.
2202  // no specific order required, the function sorts the arrays internally
2203  wave polar// polar coordinates. allowed range 0 <= theta <= 90
2204  // dimensions corresponding to value.
2205  wave azi// azimuthal coordinates. allowed range -360 <= phi < +360
2206  // dimensions corresponding to value.
2207  wave weights// total accumulation time of each point of values. default = 1
2208 
2209  if (ParamIsDefault(weights))
2210  duplicate /free values, weights
2211  weights = 1
2212  endif
2213 
2214  // quick check whether hemi grid is existing
2215  if (strlen(nickname))
2216  string s_prefix = nickname + "_"
2217  string s_int = s_prefix + "i"
2218  else
2219  s_prefix = ""
2220  s_int = "values"
2221  endif
2222  string s_polar = s_prefix + "pol"
2223  string s_azim = s_prefix + "az"
2224  string s_theta = s_prefix + "th"
2225 
2226  wave /z w_values = $s_int
2227  wave /z w_azim = $s_azim
2228  wave /z w_polar = $s_polar
2229  wave /z w_theta = $s_theta
2230  if (!waveexists(w_values) || !waveexists(w_azim) || !waveexists(w_polar))
2231  abort "Missing hemispherical scan grid. Please call make_hemi_grid() first."
2232  endif
2233 
2234  // make internal copies, one-dimensional, ordered in theta
2235  duplicate /free values, values_copy
2236  duplicate /free polar, polar_copy
2237  duplicate /free azi, azi_copy
2238  duplicate /free weights, weights_copy
2239  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2240  redimension /n=(nn) values_copy, polar_copy, azi_copy, weights_copy
2241  sort /r polar_copy, polar_copy, azi_copy, values_copy, weights_copy
2242 
2243  variable pol
2244  variable pol_st = abs(w_theta[1] - w_theta[0])
2245  variable pol1, pol2
2246 
2247  duplicate /free azi_copy, azi_slice
2248  duplicate /free values_copy, values_slice
2249  duplicate /free weights_copy, weights_slice
2250  for (pol = 90; pol >= 0; pol -= pol_st)
2251  pol1 = pol - pol_st / 2
2252  pol2 = pol + pol_st / 2
2253  extract /free /indx polar_copy, sel, (pol1 < polar_copy) && (polar_copy <= pol2)
2254  if (numpnts(sel) > 0)
2255  redimension /n=(numpnts(sel)) azi_slice, values_slice, weights_slice
2256  azi_slice = azi_copy[sel]
2257  values_slice = values_copy[sel]
2258  weights_slice = weights_copy[sel]
2259  hemi_add_aziscan(nickname, values_slice, pol, azi_slice, weights=weights_slice)
2260  endif
2261  endfor
2262 };
2263 
2270 variable hemi_add_aziscan(string nickname, wave values, variable polar, wave azi, wave weights = defaultValue){
2271  string nickname// name prefix of holo waves.
2272  // may be empty.
2273  wave values// intensity values of the azimuthal scan at the positions given in the azi parameter
2274  variable polar// polar angle where to add the azi scan
2275  wave azi// angle positions of the azimuthal scan
2276  // acceptable range: >= -360 and < +360
2277  // no specific order required, the function sorts the array internally
2278  wave weights// total accumulation time of each point of values. default = 1
2279 
2280  if (ParamIsDefault(weights))
2281  duplicate /free values, weights
2282  weights = 1
2283  endif
2284 
2285  // hemi grid waves
2286  if (strlen(nickname))
2287  string s_prefix = nickname + "_"
2288  string s_int = s_prefix + "i"
2289  else
2290  s_prefix = ""
2291  s_int = "values"
2292  endif
2293  string s_totals = s_prefix + "tot"
2294  string s_weights = s_prefix + "wt"
2295  string s_polar = s_prefix + "pol"
2296  string s_azim = s_prefix + "az"
2297  string s_index = s_prefix + "index"
2298  string s_theta = s_prefix + "th"
2299  string s_dphi = s_prefix + "dphi"
2300  string s_nphis = s_prefix + "nphis"
2301 
2302  wave w_polar = $s_polar
2303  wave w_azim = $s_azim
2304  wave w_values = $s_int
2305  wave w_totals = $s_totals
2306  wave w_weights = $s_weights
2307  wave w_index = $s_index
2308  wave w_theta = $s_theta
2309  wave w_dphi = $s_dphi
2310  wave w_nphis = $s_nphis
2311 
2312  // destination slice coordinates
2313  //polar = round(polar)
2314  //variable ipol = 90 - polar
2315  variable ipol = BinarySearch(w_theta, polar)
2316  if (ipol < 0)
2317  abort "assertion failed in hemi_add_aziscan(): polar angle not found in grid."
2318  endif
2319 
2320  variable d1, d2
2321  if (ipol >= 1)
2322  d1 = w_index[ipol - 1]
2323  else
2324  d1 = 0
2325  endif
2326  d2 = w_index[ipol] - 1
2327  variable nd = d2 - d1 + 1
2328  variable dphi = w_dphi[ipol]
2329  variable az1, az2
2330 
2331  // source slice coordinates
2332  // order the slice from -dphi/2 to 360-dphi/2
2333  azi = azi < 0 ? azi + 360 : azi
2334  azi = azi >= 360 - dphi/2 ? azi - 360 : azi
2335  duplicate /free values, sel_values
2336  duplicate /free weights, sel_weights
2337 
2338  // loop over destination
2339  variable id
2340  variable v1, v2, w1, w2
2341  for (id = 0; id < nd; id += 1)
2342  az1 = (id - 0.5) * dphi
2343  az2 = (id + 0.5) * dphi
2344  extract /free /indx azi, sel, (az1 <= azi) && (azi < az2)
2345  if (numpnts(sel) > 0)
2346  redimension /n=(numpnts(sel)) sel_values, sel_weights
2347  sel_values = values[sel]
2348  sel_weights = weights[sel]
2349  v1 = w_totals[d1 + id]
2350  w1 = w_weights[d1 + id]
2351  if ((numtype(v1) == 2) || (w1 <= 0))
2352  v1 = 0
2353  w1 = 0
2354  endif
2355  v2 = sum(sel_values)
2356  w2 = sum(sel_weights)
2357  w_totals[d1 + id] = v1 + v2
2358  w_weights[d1 + id] = w1 + w2
2359  endif
2360  endfor
2361  w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p]
2362 };
2363 
2371 variable interpolate_hemi_scan(string nickname){
2372  string nickname
2373 
2374  if (strlen(nickname))
2375  string s_prefix = nickname + "_"
2376  string s_int = s_prefix + "i"
2377  else
2378  s_prefix = ""
2379  s_int = "values"
2380  endif
2381 
2382  string s_polar = s_prefix + "pol"
2383  string s_azim = s_prefix + "az"
2384  string s_ster_x = s_prefix + "ster_x"
2385  string s_ster_y = s_prefix + "ster_y"
2386 
2387  wave values = $s_int
2388  wave azim = $s_azim
2389  wave polar = $s_polar
2390  wave ster_x = $s_ster_x
2391  wave ster_y = $s_ster_y
2392 
2393  variable min_ster_x = wavemin(ster_x)
2394  variable max_ster_x = wavemax(ster_x)
2395  variable x0 = min_ster_x
2396  variable xn = 181
2397  variable dx = (max_ster_x - min_ster_x) / (xn - 1)
2398  make /n=(numpnts(ster_x), 3) /free triplet
2399  triplet[][0] = ster_x[p]
2400  triplet[][1] = ster_y[p]
2401  triplet[][2] = values[p]
2402  //ImageInterpolate /stw /s={x0, dx, xn, x0, dx, xn} voronoi triplet
2403 
2404  variable size = 181
2405  make /n=(size, size) /d /o $(s_prefix + "matrix") /wave=matrix
2406  make /n=(size, size) /free mnorm
2407  ImageFromXYZ /as {ster_x, ster_y, values}, matrix, mnorm
2408  matrix /= mnorm
2409  matrixfilter NanZapMedian, matrix
2410  matrixfilter gauss, matrix
2411 
2412  matrix = (x^2 + y^2) < 4 ? matrix : nan
2413 };
2414 
2425 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){
2426  wave data// 2D intensity wave, see requirements above
2427  string nickname// nick name for output data
2428  // in default mode, this will be the name of a child folder containing the output
2429  // in XPDplot mode, this will be a prefix of the generated data in the root folder
2430  variable theta_offset// manipulator theta angle corresponding to normal emission
2431  variable tilt_offset// manipulator tilt angle corresponding to normal emission
2432  variable phi_offset// manipulator phi angle corresponding to phi_result = 0
2433  variable npolar// number of polar angles, determines polar and azimuthal step size
2434  // default = 91 (1 degree steps)
2435  variable nograph// 0 (default) = display a new polar graph
2436  // 1 = don't display a new graph (if a graph is existing from a previous call, it will update)
2437  variable folding// rotational averaging, default = 1
2438 
2439  if (ParamIsDefault(npolar))
2440  npolar = 91
2441  endif
2442  if (ParamIsDefault(nograph))
2443  nograph = 0
2444  endif
2445  if (ParamIsDefault(folding))
2446  folding = 1
2447  endif
2448  string graphname = "graph_" + nickname
2449  string s_prefix = ""
2450 
2451  // sort out data folder structure
2452  dfref saveDF = GetDataFolderDFR()
2453  dfref dataDF = GetWavesDataFolderDFR(data)
2454  setdatafolder dataDF
2455  if (DataFolderExists(":attr"))
2456  setdatafolder :attr
2457  endif
2458  dfref attrDF = GetDataFolderDFR()
2459  setdatafolder dataDF
2460  newdatafolder /s/o $nickname
2461  dfref destDF = GetDataFolderDFR()
2462 
2463  // performance monitoring
2464  variable timerRefNum
2465  variable /g xyz_perf_secs
2466  timerRefNum = startMSTimer
2467 
2468  wave /sdfr=attrDF ManipulatorTheta
2469  wave /sdfr=attrDF ManipulatorTilt
2470  wave /sdfr=attrDF ManipulatorPhi
2471  duplicate /free ManipulatorTheta, m_theta
2472  duplicate /free ManipulatorTilt, m_tilt
2473  duplicate /free ManipulatorPhi, m_phi
2474  m_theta -= theta_offset
2475  m_tilt -= tilt_offset
2476  m_tilt *= -1// checked 140702
2477  m_phi -= phi_offset
2478  //m_phi *= -1 // checked 140702
2479 
2480  make /n=1/d/free d_polar, d_azi
2481  convert_angles_ttpd2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
2482  d_azi += 180// changed 151030 (v1.6)
2483  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
2484 
2485  duplicate /free data, values
2486  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2487  redimension /n=(nn) values, d_polar, d_azi
2488  duplicate /o d_polar, ster_rad, ster_x, ster_y
2489 
2490  variable projection = 1
2491  switch(projection)
2492  case 1:// stereographic
2493  ster_rad = 2 * tan(d_polar / 2 * pi / 180)
2494  break
2495  case 2:// azimuthal
2496  ster_rad = 2 * cos((180 - d_polar) / 2 * pi / 180)
2497  break
2498  endswitch
2499  string s_ster_x = s_prefix + "ster_x"
2500  string s_ster_y = s_prefix + "ster_y"
2501 
2502  nn = 401
2503  make /n=(nn, nn) /d /o matrix
2504  make /n=(nn, nn) /free mnorm
2505  setscale /i x -2, +2, matrix, mnorm
2506  setscale /i y -2, +2, matrix, mnorm
2507  matrix = 0
2508  mnorm = 0
2509 
2510  variable ifold
2511  for (ifold = 0; ifold < folding; ifold += 1)
2512  ster_x = ster_rad * cos(d_azi * pi / 180)
2513  ster_y = ster_rad * sin(d_azi * pi / 180)
2514  ImageFromXYZ {ster_x, ster_y, values}, matrix, mnorm
2515  d_azi = d_azi >= 180 ? d_azi + 360 / folding - 180 : d_azi + 360 / folding
2516  endfor
2517 
2518  matrix /= mnorm
2519  matrixfilter /n=5 NanZapMedian matrix
2520  matrixfilter /n=3 gauss matrix
2521 
2522  if (!nograph)
2523  display /k=1
2524  appendimage matrix
2525  modifygraph width={Plan,1,bottom,left}
2526  endif
2527 
2528  if (timerRefNum >= 0)
2529  xyz_perf_secs = stopMSTimer(timerRefNum) / 1e6
2530  endif
2531 
2532  setdatafolder saveDF
2533 };
2534 
2536 variable save_hemi_scan(string nickname, string pathname, string filename){
2537  string nickname
2538  string pathname
2539  string filename
2540 
2541  dfref savedf = getdatafolderdfr()
2542 
2543  // source data
2544  if (strlen(nickname))
2545  string s_prefix = nickname + "_"
2546  string s_int = s_prefix + "i"
2547  else
2548  s_prefix = ""
2549  s_int = "values"
2550  endif
2551  string s_polar = s_prefix + "pol"
2552  string s_azim = s_prefix + "az"
2553  string s_theta = s_prefix + "th"
2554  string s_tot = s_prefix + "tot"
2555  string s_weight = s_prefix + "wt"
2556 
2557  wave theta1 = $s_theta
2558  wave polar1 = $s_polar
2559  wave azim1 = $s_azim
2560  wave tot1 = $s_tot
2561  wave weight1 = $s_weight
2562  wave values1 = $s_int
2563 
2564  save /m="\r\n" /o /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2565 
2566  setdatafolder saveDF
2567 };
2568 
2572 variable load_hemi_scan(string nickname, string pathname, string filename){
2573  string nickname
2574  string pathname
2575  string filename
2576 
2577  dfref savedf = getdatafolderdfr()
2578 
2579  //loadwave /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2580  //LoadWave /t/p=pearl_explorer_filepath/q filename
2581  //svar waves = s_wavenames
2582  //if (v_flag > 0)
2583  // string /g pearl_explorer_import = "load_itx_file"
2584  //endif
2585 
2586  setdatafolder saveDF
2587 };
2588 
2621 variable import_tpi_scan(string nickname, wave theta, wave phi, wave intensity, variable folding = defaultValue, variable npolar = defaultValue, variable nograph = defaultValue, variable xpdplot = defaultValue){
2622  string nickname
2623  wave theta
2624  wave phi
2625  wave intensity
2626 
2627  variable folding
2628  variable npolar
2629  variable nograph
2630  variable xpdplot
2631 
2632  if (ParamIsDefault(npolar))
2633  npolar = 91
2634  endif
2635  if (ParamIsDefault(nograph))
2636  nograph = 0
2637  endif
2638  if (ParamIsDefault(folding))
2639  folding = 1
2640  endif
2641  if (ParamIsDefault(xpdplot))
2642  xpdplot = 0
2643  endif
2644 
2645  make_hemi_grid(npolar, nickname, xpdplot=xpdplot)
2646 
2647  variable ifold
2648  duplicate /free phi, fold_phi
2649  for (ifold = 0; ifold < folding; ifold += 1)
2650  hemi_add_anglescan(nickname, intensity, theta, fold_phi)
2651  fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
2652  endfor
2653 
2654  if (nograph==0)
2655  display_hemi_scan(nickname)
2656  endif
2657 };
2658 
2670 variable trim_hemi_scan(string nickname, variable theta_max){
2671  string nickname
2672  variable theta_max
2673 
2674  if (strlen(nickname))
2675  string s_prefix = nickname + "_"
2676  string s_int = s_prefix + "i"
2677  else
2678  s_prefix = ""
2679  s_int = "values"
2680  endif
2681  string s_totals = s_prefix + "tot"
2682  string s_weights = s_prefix + "wt"
2683  string s_polar = s_prefix + "pol"
2684 
2685  wave w_polar = $s_polar
2686  wave w_values = $s_int
2687  wave w_totals = $s_totals
2688  wave w_weights = $s_weights
2689 
2690  w_values = w_polar <= theta_max ? w_totals / w_weights : nan
2691 };
2692 
2712 wave hemi_polar_cut(string nickname, variable azim){
2713  string nickname
2714  variable azim
2715 
2716  if (strlen(nickname))
2717  string s_prefix = nickname + "_"
2718  string s_int = s_prefix + "i"
2719  else
2720  s_prefix = ""
2721  s_int = "values"
2722  endif
2723  string s_totals = s_prefix + "tot"
2724  string s_weights = s_prefix + "wt"
2725  string s_polar = s_prefix + "pol"
2726  string s_azim = s_prefix + "az"
2727  string s_index = s_prefix + "index"
2728  string s_theta = s_prefix + "th"
2729  string s_dphi = s_prefix + "dphi"
2730  string s_nphis = s_prefix + "nphis"
2731  string s_cut
2732  sprintf s_cut, "%s_azi%03u", s_int, round(azim)
2733 
2734  wave w_polar = $s_polar
2735  wave w_azim = $s_azim
2736  wave w_values = $s_int
2737  wave w_totals = $s_totals
2738  wave w_weights = $s_weights
2739  wave w_index = $s_index
2740  wave w_theta = $s_theta
2741  wave w_dphi = $s_dphi
2742  wave w_nphis = $s_nphis
2743 
2744  variable npol = numpnts(w_theta)
2745  variable ipol
2746  variable pol_st = abs(w_theta[1] - w_theta[0])
2747  variable pol
2748  variable pol1, pol2
2749  variable nsel
2750  make /n=(npol) /o $s_cut
2751  wave w_cut = $s_cut
2752  setscale /i x w_theta[0], w_theta[numpnts(w_theta)-1], "deg", w_cut
2753  make /n=1 /free azi_slice
2754  make /n=1 /free values_slice
2755 
2756  for (ipol = 0; ipol < npol; ipol += 1)
2757  pol = w_theta[ipol]
2758  pol1 = pol - pol_st / 2
2759  pol2 = pol + pol_st / 2
2760  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2761  nsel = numpnts(sel)
2762  if (nsel > 0)
2763  redimension /n=(nsel+2) azi_slice, values_slice
2764  azi_slice[1, nsel] = w_azim[sel[p-1]]
2765  azi_slice[0] = azi_slice[nsel] - 360
2766  azi_slice[nsel+1] = azi_slice[1] + 360
2767  values_slice[1, nsel] = w_values[sel[p-1]]
2768  values_slice[0] = values_slice[nsel]
2769  values_slice[nsel+1] = values_slice[1]
2770  w_cut[ipol] = interp(azim, azi_slice, values_slice)
2771  else
2772  w_cut[ipol] = nan
2773  endif
2774  endfor
2775  return w_cut
2776 };
2777 
2796 wave hemi_azi_cut(string nickname, variable pol){
2797  string nickname
2798  variable pol
2799 
2800  if (strlen(nickname))
2801  string s_prefix = nickname + "_"
2802  string s_int = s_prefix + "i"
2803  else
2804  s_prefix = ""
2805  s_int = "values"
2806  endif
2807  string s_totals = s_prefix + "tot"
2808  string s_weights = s_prefix + "wt"
2809  string s_polar = s_prefix + "pol"
2810  string s_azim = s_prefix + "az"
2811  string s_index = s_prefix + "index"
2812  string s_theta = s_prefix + "th"
2813  string s_dphi = s_prefix + "dphi"
2814  string s_nphis = s_prefix + "nphis"
2815  string s_cut
2816  sprintf s_cut, "%s_pol%03u", s_int, round(pol)
2817 
2818  wave w_polar = $s_polar
2819  wave w_azim = $s_azim
2820  wave w_values = $s_int
2821  wave w_totals = $s_totals
2822  wave w_weights = $s_weights
2823  wave w_index = $s_index
2824  wave w_theta = $s_theta
2825  wave w_dphi = $s_dphi
2826  wave w_nphis = $s_nphis
2827 
2828  variable pol_st = abs(w_theta[1] - w_theta[0])
2829  variable pol1, pol2
2830  variable nsel
2831 
2832  pol1 = pol - pol_st / 2
2833  pol2 = pol + pol_st / 2
2834  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2835  nsel = numpnts(sel)
2836  if (nsel > 0)
2837  make /n=(nsel) /o $s_cut
2838  wave w_cut = $s_cut
2839  w_cut = w_values[sel]
2840  setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "", w_cut
2841  return w_cut
2842  else
2843  return $""
2844  endif
2845 };
2846 
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 = 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  if (strlen(source_nickname))
1379  string s_prefix = source_nickname + "_"
1380  string s_int = s_prefix + "i"
1381  else
1382  s_prefix = ""
1383  s_int = "values"
1384  endif
1385  string s_polar = s_prefix + "pol"
1386  string s_azim = s_prefix + "az"
1387  string s_theta = s_prefix + "th"
1388  string s_tot = s_prefix + "tot"
1389  string s_weight = s_prefix + "wt"
1390  string s_matrix = s_prefix + "matrix"
1391 
1392  wave theta1 = $s_theta
1393  wave polar1 = $s_polar
1394  wave azim1 = $s_azim
1395  wave tot1 = $s_tot
1396  wave weight1 = $s_weight
1397  wave values1 = $s_int
1398  wave /z matrix1 = $s_matrix
1399 
1400  variable npol = numpnts(theta1)
1401 
1402  setdatafolder dest_folder
1403  make_hemi_grid(npol, dest_nickname, xpdplot=xpdplot)
1404 
1405  // dest data
1406  if (strlen(dest_nickname))
1407  s_prefix = dest_nickname + "_"
1408  s_int = s_prefix + "i"
1409  else
1410  s_prefix = ""
1411  s_int = "values"
1412  endif
1413  s_polar = s_prefix + "pol"
1414  s_azim = s_prefix + "az"
1415  s_theta = s_prefix + "th"
1416  s_tot = s_prefix + "tot"
1417  s_weight = s_prefix + "wt"
1418  s_matrix = s_prefix + "matrix"
1419 
1420  wave theta2 = $s_theta
1421  wave polar2 = $s_polar
1422  wave azim2 = $s_azim
1423  wave tot2 = $s_tot
1424  wave weight2 = $s_weight
1425  wave values2 = $s_int
1426 
1427  tot2 = tot1
1428  weight2 = weight1
1429  values2 = values1
1430  if (waveexists(matrix1))
1431  duplicate /o matrix1, $s_matrix
1432  endif
1433 
1434  if (!(NumberByKey("version", note(azim1), "=", "\r") >= 1.6))
1435  azim2 += 180// changed 151030 (v1.6)
1436  azim2 = azim2 >= 360 ? azim2 - 360 : azim2
1437  endif
1438 
1439  setdatafolder saveDF
1440 };
1441 
1449 variable rotate_hemi_scan(string nickname, variable angle){
1450  string nickname
1451  variable angle
1452 
1453  dfref savedf = getdatafolderdfr()
1454 
1455  if (strlen(nickname))
1456  string s_prefix = nickname + "_"
1457  string s_int = s_prefix + "i"
1458  else
1459  s_prefix = ""
1460  s_int = "values"
1461  endif
1462  string s_polar = s_prefix + "pol"
1463  string s_azim = s_prefix + "az"
1464  string s_tot = s_prefix + "tot"
1465  string s_weight = s_prefix + "wt"
1466 
1467  wave polar = $s_polar
1468  wave azim = $s_azim
1469  wave tot = $s_tot
1470  wave weight = $s_weight
1471  wave values = $s_int
1472 
1473  azim += angle
1474  azim = azim < 0 ? azim + 360 : azim
1475  azim = azim >= 360 ? azim - 360 : azim
1476 
1477  duplicate /free polar, neg_polar
1478  neg_polar = -polar
1479  sort {neg_polar, azim}, polar, azim, tot, weight, values
1480 
1481  setdatafolder saveDF
1482 };
1483 
1528 string display_hemi_scan(string nickname, variable projection = defaultValue, variable graphtype = defaultValue, variable do_ticks = defaultValue, variable do_grids = defaultValue, string graphname = defaultValue){
1529  string nickname
1530  variable projection
1531  variable graphtype
1532  variable do_ticks
1533  variable do_grids
1534  string graphname
1535 
1536  if (ParamIsDefault(projection))
1537  projection = 1
1538  endif
1539  if (ParamIsDefault(graphtype))
1540  graphtype = 1
1541  endif
1542  if (ParamIsDefault(do_ticks))
1543  do_ticks = 3
1544  endif
1545  if (ParamIsDefault(do_grids))
1546  do_grids = 3
1547  endif
1548  if (ParamIsDefault(graphname))
1549  if (strlen(nickname) > 0)
1550  graphname = nickname
1551  else
1552  graphname = GetDataFolder(0)
1553  endif
1554  endif
1555 
1556  // hemi grid waves
1557  if (strlen(nickname))
1558  string s_prefix = nickname + "_"
1559  string s_int = s_prefix + "i"
1560  else
1561  s_prefix = ""
1562  s_int = "values"
1563  endif
1564  string s_polar = s_prefix + "pol"
1565  string s_azim = s_prefix + "az"
1566  string s_matrix = s_prefix + "matrix"
1567 
1568  wave /z values = $s_int
1569  wave /z azim = $s_azim
1570  wave /z polar = $s_polar
1571  wave /z matrix = $s_matrix
1572 
1573  string s_ster_rad = s_prefix + "ster_rad"
1574  duplicate /o polar, $s_ster_rad /wave=ster_rad
1575  ster_rad = calc_graph_radius(polar, projection=projection)
1576 
1577  string s_ster_x = s_prefix + "ster_x"
1578  string s_ster_y = s_prefix + "ster_y"
1579  duplicate /o azim, $s_ster_x /wave=ster_x, $s_ster_y /wave=ster_y
1580  ster_x = ster_rad * cos(azim * pi / 180)
1581  ster_y = ster_rad * sin(azim * pi / 180)
1582 
1583  variable azim_offset = 0
1584  if (!(NumberByKey("version", note(azim), "=", "\r") >= 1.6))
1585  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!"
1586  azim_offset = 180// changed 151030 (v1.6)
1587  endif
1588 
1589  string s_trace
1590  switch(graphtype)
1591  case 1:
1592  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1593 
1594  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1595  ModifyGraph /W=$graphname mode($s_trace)=2, lsize($s_trace)=2
1596  ModifyGraph /W=$graphname zColor($s_trace)={values,*,*,BlueGreenOrange,0}
1597 
1598  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 trace=polarY0
1599  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1600  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1601 
1602  SetWindow $graphname, userdata(projection)=num2str(projection)
1603  draw_hemi_axes(graphname, do_grids=do_grids)
1604  break
1605  case 3:
1606  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1607 
1608  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1609  ModifyGraph /W=$graphname mode($s_trace)=0, lsize($s_trace)=0
1610  AppendImage /L=VertCrossing /B=HorizCrossing matrix
1611 
1612  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 image=$s_matrix
1613  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1614  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1615 
1616  SetWindow $graphname, userdata(projection)=num2str(projection)
1617  draw_hemi_axes(graphname, do_grids=do_grids)
1618  break
1619  endswitch
1620 
1621  return graphname
1622 };
1623 
1665 static string display_polar_graph(string graphname, variable angle_offset = defaultValue, variable do_ticks = defaultValue){
1666 
1667  string graphname
1668  variable angle_offset
1669  variable do_ticks
1670 
1671  dfref savedf = GetDataFolderDFR()
1672 
1673  if (ParamIsDefault(angle_offset))
1674  angle_offset = 0
1675  endif
1676  if (ParamIsDefault(do_ticks))
1677  do_ticks = 3
1678  endif
1679 
1680  if ((strlen(graphname) == 0) || (wintype(graphname) == 0))
1681  Display /k=1 /W=(10,45,360,345)
1682  DoWindow /C $graphname
1683  graphname = WMNewPolarGraph("", graphname)
1684  WMPolarGraphSetVar(graphname, "zeroAngleWhere", angle_offset)
1685 
1686  WMPolarGraphSetVar(graphname, "angleAxisThick", 0.5)
1687  WMPolarGraphSetStr(graphname, "doMajorAngleTicks", "manual")
1688  WMPolarGraphSetVar(graphname, "majorAngleInc", 30)// major ticks in 30 deg steps
1689  WMPolarGraphSetVar(graphname, "minorAngleTicks", 2)// minor ticks in 10 deg steps
1690  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1691  WMPolarGraphSetVar(graphname, "doAngleTickLabelSubRange", 1)
1692  WMPolarGraphSetVar(graphname, "angleTickLabelRangeStart", 0)
1693  WMPolarGraphSetVar(graphname, "angleTickLabelRangeExtent", 90)
1694  WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g")
1695 
1696  WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
1697  WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
1698  WMPolarGraphSetStr(graphname, "radiusAxesWhere", " Off")// note the leading spaces, cf. WMPolarAnglesForRadiusAxes
1699  WMPolarGraphSetStr(graphname, "radiusTicksLocation", "Off")
1700 
1701  WMPolarGraphSetVar(graphname, "majorTickLength", 2)
1702  WMPolarGraphSetVar(graphname, "majorTickThick", 0.5)
1703  WMPolarGraphSetVar(graphname, "minorTickLength", 1)
1704  WMPolarGraphSetVar(graphname, "minorTickThick", 0.5)
1705  WMPolarGraphSetVar(graphname, "tickLabelOpaque", 0)
1706  WMPolarGraphSetVar(graphname, "tickLabelFontSize", 7)
1707 
1708  // changes
1709  if (do_ticks & 1)
1710  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
1711  else
1712  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Off")
1713  endif
1714  if (do_ticks & 2)
1715  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 1)
1716  else
1717  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 0)
1718  endif
1719 
1720  DoWindow /T $graphname, graphname
1721 
1722  // cursor info in angles
1723  string graphdf = "root:packages:WMPolarGraphs:" + graphname
1724  setdatafolder graphdf
1725  // current theta, phi coordinates are stored in global variables in the package folder of the graph
1726  variable /g csrA_theta
1727  variable /g csrA_phi
1728  variable /g csrB_theta
1729  variable /g csrB_phi
1730  // the text box is hidden initially. it shows up and hides with the cursor info box.
1731  string tb
1732  tb = "\\{"
1733  tb = tb + "\"A = (%.1f, %.1f)\","
1734  tb = tb + graphdf + ":csrA_theta,"
1735  tb = tb + graphdf + ":csrA_phi"
1736  tb = tb + "}"
1737  TextBox /W=$graphname /A=LT /B=1 /E=2 /F=0 /N=tb_angles /X=1 /Y=1 /V=0 tb
1738  tb = "\\{"
1739  tb = tb + "\"B = (%.1f, %.1f)\","
1740  tb = tb + graphdf + ":csrB_theta,"
1741  tb = tb + graphdf + ":csrB_phi"
1742  tb = tb + "}"
1743  AppendText /W=$graphname /N=tb_angles tb
1744  // updates are triggered by a window hook
1745  SetWindow $graphname, hook(polar_graph_hook)=PearlAnglescanProcess#polar_graph_hook
1746  else
1747  // graph window exists
1748  DoWindow /F $graphname
1749  endif
1750 
1751  setdatafolder savedf
1752  return graphname
1753 };
1754 
1780 static string draw_hemi_axes(string graphname, variable do_grids = defaultValue){
1781  string graphname
1782  variable do_grids
1783 
1784  if (ParamIsDefault(do_grids))
1785  do_grids = 3
1786  endif
1787 
1788  dfref savedf = GetDataFolderDFR()
1789 
1790  string sproj = GetUserData(graphname, "", "projection")
1791  variable projection = str2num("0" + sproj)
1792 
1793  SetDrawLayer /W=$graphname ProgFront
1794 
1795  // polar axis
1796  SetDrawEnv /W=$graphname xcoord=HorizCrossing, ycoord=VertCrossing
1797  SetDrawEnv /W=$graphname linethick= 0.5
1798  SetDrawEnv /W=$graphname dash=2
1799  SetDrawEnv /W=$graphname fillpat=0
1800  SetDrawEnv /W=$graphname fname="default", fsize=7
1801  SetDrawEnv /W=$graphname textxjust=1, textyjust=1
1802  //SetDrawEnv /W=$graphname linefgc=(65535,65535,65535)
1803  SetDrawEnv /W=$graphname save
1804 
1805  if (do_grids & 1)
1806  DrawLine /W=$graphname 0, -2, 0, 2
1807  DrawLine /W=$graphname -2, 0, 2, 0
1808  endif
1809 
1810  variable radi
1811  if (do_grids & 2)
1812  radi = calc_graph_radius(0.5, projection=projection)
1813  DrawOval /W=$graphname -radi, radi, radi, -radi
1814  radi = calc_graph_radius(30, projection=projection)
1815  DrawOval /W=$graphname -radi, radi, radi, -radi
1816  radi = calc_graph_radius(60, projection=projection)
1817  DrawOval /W=$graphname -radi, radi, radi, -radi
1818 
1819  SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
1820  SetDrawEnv /W=$graphname save
1821  radi = calc_graph_radius(30, projection=projection)
1822  DrawText /W=$graphname radi, -0.1, "30"
1823  radi = calc_graph_radius(60, projection=projection)
1824  DrawText /W=$graphname radi, -0.1, "60"
1825  endif
1826 
1827  setdatafolder savedf
1828 };
1829 
1852 variable draw_diffraction_cone(string graphname, string groupname, variable theta_axis, variable theta_inner, variable phi){
1853  string graphname
1854  string groupname
1855 
1856  variable theta_axis
1857  variable theta_inner
1858  variable phi
1859 
1860  variable r_axis = calc_graph_radius(theta_axis)
1861  variable r_inner = calc_graph_radius(theta_inner)
1862  variable r_outer = calc_graph_radius(2 * theta_axis - theta_inner)
1863 
1864  SetDrawEnv push
1865  SetDrawLayer UserFront
1866  DrawAction getgroup=$groupname, delete
1867  SetDrawEnv gstart, gname=$groupname
1868  variable xc, yc, xr, yr
1869 
1870  // cone periphery
1871  variable r_center = (r_outer + r_inner) / 2
1872  variable r_radius = (r_outer - r_inner) / 2
1873  xc = r_center * cos(phi * pi / 180)
1874  yc = r_center * sin(phi * pi / 180)
1875  xr = r_radius
1876  yr = r_radius
1877  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1878  SetDrawEnv dash=11, fillpat=0
1879  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1880 
1881  // cone axis
1882  xc = r_axis * cos(phi * pi / 180)
1883  yc = r_axis * sin(phi * pi / 180)
1884  r_radius = calc_graph_radius(2)
1885  xr = r_radius
1886  yr = r_radius
1887  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
1888  SetDrawEnv fillfgc=(0,0,0)
1889  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
1890 
1891  SetDrawEnv gstop
1892  SetDrawEnv pop
1893 };
1894 
1916 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){
1917  string nickname
1918  variable alpha_lo
1919  variable alpha_hi
1920  wave m_theta
1921  wave m_tilt
1922  wave m_phi
1923  variable folding
1924  variable projection
1925 
1926  if (ParamIsDefault(folding))
1927  folding = 1
1928  endif
1929  if (ParamIsDefault(projection))
1930  projection = 1
1931  endif
1932 
1933  // sort out data folder structure
1934  dfref saveDF = GetDataFolderDFR()
1935  newdatafolder /s/o $nickname
1936  string graphname = "graph_" + nickname
1937 
1938  duplicate /free m_tilt, loc_m_tilt
1939  loc_m_tilt = -m_tilt
1940 
1941  make /n=1 /d /free d_polar, d_azi
1942  variable n_alpha = round(alpha_hi - alpha_lo) + 1
1943  make /n=(n_alpha) /d /free analyser
1944  setscale /i x alpha_lo, alpha_hi, "", analyser
1945  analyser = x
1946 
1947  convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
1948  duplicate /free d_polar, d_radius
1949  d_radius = calc_graph_radius(d_polar, projection=projection)
1950  d_azi += 180// changed 151030 (v1.6)
1951 
1952  graphname = display_polar_graph(graphname)
1953  SetWindow $graphname, userdata(projection)=num2str(projection)
1954 
1955  variable ifold
1956  variable iang
1957  variable nang = numpnts(m_theta)
1958  string s_rad
1959  string s_azi
1960  string s_trace
1961  for (ifold = 0; ifold < folding; ifold += 1)
1962  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
1963  for (iang = 0; iang < nang; iang += 1)
1964  sprintf s_rad, "rad_%d_%d", ifold, iang
1965  duplicate /o analyser, $s_rad
1966  wave w_rad = $s_rad
1967  w_rad = d_radius[p][iang]
1968 
1969  sprintf s_azi, "azi_%d_%d", ifold, iang
1970  duplicate /o analyser, $s_azi
1971  wave w_azi = $s_azi
1972  w_azi = d_azi[p][iang]
1973 
1974  if (numtype(sum(w_rad)) == 0)
1975  s_trace = WMPolarAppendTrace(graphname, w_rad, w_azi, 360)
1976  ModifyGraph /w=$graphname mode($s_trace)=0, lsize($s_trace)=0.5
1977  endif
1978  endfor
1979  d_azi += 360 / folding
1980  endfor
1981 
1982  draw_hemi_axes(graphname)
1983 
1984  setdatafolder saveDF
1985  return graphname
1986 };
1987 
2004 const variable kProjDist = 0;
2005 const variable kProjStereo = 1;
2006 const variable kProjArea = 2;
2007 const variable kProjGnom = 3;
2008 const variable kProjOrtho = 4;
2009 
2010 static const variable kProjScaleDist = 2;
2011 static const variable kProjScaleStereo = 2;
2012 static const variable kProjScaleArea = 2;
2013 // scaled so that radius(gnom) = radius(stereo) for polar = 88
2014 static const variable kProjScaleGnom = 0.06744519021;
2015 static const variable kProjScaleOrtho = 2;
2016 
2031 threadsafe variable calc_graph_radius(variable polar, variable projection = defaultValue){
2032  variable polar
2033  variable projection
2034 
2035  if (ParamIsDefault(projection))
2036  projection = 1
2037  endif
2038 
2039  variable radius
2040  switch(projection)
2041  case kProjStereo:// stereographic
2042  radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
2043  break
2044  case kProjArea:// equal area
2045  radius = kProjScaleArea * sin(polar / 2 * pi / 180)
2046  break
2047  case kProjGnom:// gnomonic
2048  radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
2049  break
2050  case kProjOrtho:// orthographic
2051  radius = kProjScaleOrtho * sin(polar * pi / 180)
2052  break
2053  default:// equidistant
2054  radius = kProjScaleDist * polar / 90
2055  endswitch
2056 
2057  return radius
2058 };
2059 
2076 threadsafe variable calc_graph_polar(variable x, variable y, variable projection = defaultValue){
2077  variable x
2078  variable y
2079  variable projection
2080 
2081  if (ParamIsDefault(projection))
2082  projection = 1
2083  endif
2084 
2085  variable radius
2086  variable polar
2087 
2088  radius = sqrt(x^2 + y^2)
2089  switch(projection)
2090  case kProjStereo:// stereographic
2091  polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
2092  break
2093  case kProjArea:// equal area
2094  polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
2095  break
2096  case kProjGnom:// gnomonic
2097  polar = atan(radius / kProjScaleGnom) * 180 / pi
2098  break
2099  case kProjOrtho:// orthographic
2100  polar = asin(radius / kProjScaleOrtho) * 180 / pi
2101  break
2102  default:// equidistant
2103  polar = 90 * radius / kProjScaleDist
2104  endswitch
2105 
2106  return polar
2107 };
2108 
2129 threadsafe variable calc_graph_azi(variable x, variable y, variable projection = defaultValue, variable zeroAngle = defaultValue){
2130  variable x
2131  variable y
2132  variable projection
2133  variable zeroAngle
2134 
2135  if (ParamIsDefault(projection))
2136  projection = 1
2137  endif
2138  if (ParamIsDefault(zeroAngle))
2139  zeroAngle = 0
2140  endif
2141 
2142  variable azi
2143  if (x > 0)
2144  azi = atan(y / x) * 180 / pi
2145  else
2146  azi = atan(y / x) * 180 / pi + 180
2147  endif
2148 
2149  azi += zeroAngle
2150  if (azi < 0)
2151  azi += 360
2152  endif
2153  if (azi >= 360)
2154  azi -= 360
2155  endif
2156  if (numtype(azi) != 0)
2157  azi = 0
2158  endif
2159 
2160  return azi
2161 };
2162 
2174 static variable update_polar_info(string graphname){
2175  string graphname
2176 
2177  dfref savedf = GetDataFolderDFR()
2178 
2179  string graphdf = "root:packages:WMPolarGraphs:" + graphname
2180  setdatafolder graphdf
2181 
2182  nvar csrA_theta
2183  nvar csrA_phi
2184  nvar csrB_theta
2185  nvar csrB_phi
2186 
2187  string sproj = GetUserData(graphname, "", "projection")
2188  variable projection = str2num("0" + sproj)
2189  nvar zeroAngleWhere
2190 
2191  variable x = hcsr(A, graphname)
2192  variable y = vcsr(A, graphname)
2193  csrA_theta = calc_graph_polar(x, y, projection=projection)
2194  csrA_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2195 
2196  x = hcsr(B, graphname)
2197  y = vcsr(B, graphname)
2198  csrB_theta = calc_graph_polar(x, y, projection=projection)
2199  csrB_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2200 
2201  setdatafolder savedf
2202 };
2203 
2209 static variable polar_graph_hook(WMWinHookStruct* s){
2210  STRUCT WMWinHookStruct &s
2211 
2212  Variable hookResult = 0
2213 
2214  switch(s.eventCode)
2215  case 7:// cursor moved
2216  update_polar_info(s.winname)
2217  break
2218  case 20:// show info
2219  TextBox /W=$s.winname /N=tb_angles /C /V=1
2220  break
2221  case 21:// hide info
2222  TextBox /W=$s.winname /N=tb_angles /C /V=0
2223  break
2224  endswitch
2225 
2226  return hookResult// 0 if nothing done, else 1
2227 };
2228 
2229 variable set_polar_graph_cursor(string nickname, string cursorname, variable polar_angle, variable azim_angle, string graphname = defaultValue){
2230  string nickname
2231  string cursorname
2232  variable polar_angle
2233  variable azim_angle
2234  string graphname
2235 
2236  if (ParamIsDefault(graphname))
2237  if (strlen(nickname) > 0)
2238  graphname = nickname
2239  else
2240  graphname = GetDataFolder(0)
2241  endif
2242  endif
2243 
2244  if (strlen(nickname))
2245  string s_prefix = nickname + "_"
2246  else
2247  s_prefix = ""
2248  endif
2249  string s_polar = s_prefix + "pol"
2250  string s_azim = s_prefix + "az"
2251  wave /z azim = $s_azim
2252  wave /z polar = $s_polar
2253 
2254  FindLevel /P /Q polar, polar_angle
2255  if (v_flag == 0)
2256  variable polar_level = floor(v_levelx)
2257  FindLevel /P /Q /R=[polar_level] azim, azim_angle
2258  if (v_flag == 0)
2259  variable azim_level = round(v_levelx)
2260  string tracename = "polarY0"
2261  Cursor /W=$graphname /P $cursorname $traceName azim_level
2262  endif
2263  endif
2264 };
2265 
2275 variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights = defaultValue){
2276  string nickname// name prefix of holo waves.
2277  // may be empty.
2278  wave values// intensity values
2279  // the wave can be one- or two-dimensional.
2280  // no specific order required, the function sorts the arrays internally
2281  wave polar// polar coordinates. allowed range 0 <= theta <= 90
2282  // dimensions corresponding to value.
2283  wave azi// azimuthal coordinates. allowed range -360 <= phi < +360
2284  // dimensions corresponding to value.
2285  wave weights// total accumulation time of each point of values. default = 1
2286 
2287  if (ParamIsDefault(weights))
2288  duplicate /free values, weights
2289  weights = 1
2290  endif
2291 
2292  // quick check whether hemi grid is existing
2293  if (strlen(nickname))
2294  string s_prefix = nickname + "_"
2295  string s_int = s_prefix + "i"
2296  else
2297  s_prefix = ""
2298  s_int = "values"
2299  endif
2300  string s_polar = s_prefix + "pol"
2301  string s_azim = s_prefix + "az"
2302  string s_theta = s_prefix + "th"
2303 
2304  wave /z w_values = $s_int
2305  wave /z w_azim = $s_azim
2306  wave /z w_polar = $s_polar
2307  wave /z w_theta = $s_theta
2308  if (!waveexists(w_values) || !waveexists(w_azim) || !waveexists(w_polar))
2309  abort "Missing hemispherical scan grid. Please call make_hemi_grid() first."
2310  endif
2311 
2312  // make internal copies, one-dimensional, ordered in theta
2313  duplicate /free values, values_copy
2314  duplicate /free polar, polar_copy
2315  duplicate /free azi, azi_copy
2316  duplicate /free weights, weights_copy
2317  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2318  redimension /n=(nn) values_copy, polar_copy, azi_copy, weights_copy
2319  sort /r polar_copy, polar_copy, azi_copy, values_copy, weights_copy
2320 
2321  variable pol
2322  variable pol_st = abs(w_theta[1] - w_theta[0])
2323  variable pol1, pol2
2324 
2325  duplicate /free azi_copy, azi_slice
2326  duplicate /free values_copy, values_slice
2327  duplicate /free weights_copy, weights_slice
2328  for (pol = 90; pol >= 0; pol -= pol_st)
2329  pol1 = pol - pol_st / 2
2330  pol2 = pol + pol_st / 2
2331  extract /free /indx polar_copy, sel, (pol1 < polar_copy) && (polar_copy <= pol2)
2332  if (numpnts(sel) > 0)
2333  redimension /n=(numpnts(sel)) azi_slice, values_slice, weights_slice
2334  azi_slice = azi_copy[sel]
2335  values_slice = values_copy[sel]
2336  weights_slice = weights_copy[sel]
2337  hemi_add_aziscan(nickname, values_slice, pol, azi_slice, weights=weights_slice)
2338  endif
2339  endfor
2340 };
2341 
2348 variable hemi_add_aziscan(string nickname, wave values, variable polar, wave azi, wave weights = defaultValue){
2349  string nickname// name prefix of holo waves.
2350  // may be empty.
2351  wave values// intensity values of the azimuthal scan at the positions given in the azi parameter
2352  variable polar// polar angle where to add the azi scan
2353  wave azi// angle positions of the azimuthal scan
2354  // acceptable range: >= -360 and < +360
2355  // no specific order required, the function sorts the array internally
2356  wave weights// total accumulation time of each point of values. default = 1
2357 
2358  if (ParamIsDefault(weights))
2359  duplicate /free values, weights
2360  weights = 1
2361  endif
2362 
2363  // hemi grid waves
2364  if (strlen(nickname))
2365  string s_prefix = nickname + "_"
2366  string s_int = s_prefix + "i"
2367  else
2368  s_prefix = ""
2369  s_int = "values"
2370  endif
2371  string s_totals = s_prefix + "tot"
2372  string s_weights = s_prefix + "wt"
2373  string s_polar = s_prefix + "pol"
2374  string s_azim = s_prefix + "az"
2375  string s_index = s_prefix + "index"
2376  string s_theta = s_prefix + "th"
2377  string s_dphi = s_prefix + "dphi"
2378  string s_nphis = s_prefix + "nphis"
2379 
2380  wave w_polar = $s_polar
2381  wave w_azim = $s_azim
2382  wave w_values = $s_int
2383  wave w_totals = $s_totals
2384  wave w_weights = $s_weights
2385  wave w_index = $s_index
2386  wave w_theta = $s_theta
2387  wave w_dphi = $s_dphi
2388  wave w_nphis = $s_nphis
2389 
2390  // destination slice coordinates
2391  //polar = round(polar)
2392  //variable ipol = 90 - polar
2393  variable ipol = BinarySearch(w_theta, polar)
2394  if (ipol < 0)
2395  abort "assertion failed in hemi_add_aziscan(): polar angle not found in grid."
2396  endif
2397 
2398  variable d1, d2
2399  if (ipol >= 1)
2400  d1 = w_index[ipol - 1]
2401  else
2402  d1 = 0
2403  endif
2404  d2 = w_index[ipol] - 1
2405  variable nd = d2 - d1 + 1
2406  variable dphi = w_dphi[ipol]
2407  variable az1, az2
2408 
2409  // source slice coordinates
2410  // order the slice from -dphi/2 to 360-dphi/2
2411  azi = azi < 0 ? azi + 360 : azi
2412  azi = azi >= 360 - dphi/2 ? azi - 360 : azi
2413  duplicate /free values, sel_values
2414  duplicate /free weights, sel_weights
2415 
2416  // loop over destination
2417  variable id
2418  variable v1, v2, w1, w2
2419  for (id = 0; id < nd; id += 1)
2420  az1 = (id - 0.5) * dphi
2421  az2 = (id + 0.5) * dphi
2422  extract /free /indx azi, sel, (az1 <= azi) && (azi < az2)
2423  if (numpnts(sel) > 0)
2424  redimension /n=(numpnts(sel)) sel_values, sel_weights
2425  sel_values = values[sel]
2426  sel_weights = weights[sel]
2427  v1 = w_totals[d1 + id]
2428  w1 = w_weights[d1 + id]
2429  if ((numtype(v1) == 2) || (w1 <= 0))
2430  v1 = 0
2431  w1 = 0
2432  endif
2433  v2 = sum(sel_values)
2434  w2 = sum(sel_weights)
2435  w_totals[d1 + id] = v1 + v2
2436  w_weights[d1 + id] = w1 + w2
2437  endif
2438  endfor
2439  w_values[d1, d1 + nd - 1] = w_totals[p] / w_weights[p]
2440 };
2441 
2449 variable interpolate_hemi_scan(string nickname){
2450  string nickname
2451 
2452  if (strlen(nickname))
2453  string s_prefix = nickname + "_"
2454  string s_int = s_prefix + "i"
2455  else
2456  s_prefix = ""
2457  s_int = "values"
2458  endif
2459 
2460  string s_polar = s_prefix + "pol"
2461  string s_azim = s_prefix + "az"
2462  string s_ster_x = s_prefix + "ster_x"
2463  string s_ster_y = s_prefix + "ster_y"
2464 
2465  wave values = $s_int
2466  wave azim = $s_azim
2467  wave polar = $s_polar
2468  wave ster_x = $s_ster_x
2469  wave ster_y = $s_ster_y
2470 
2471  variable min_ster_x = wavemin(ster_x)
2472  variable max_ster_x = wavemax(ster_x)
2473  variable x0 = min_ster_x
2474  variable xn = 181
2475  variable dx = (max_ster_x - min_ster_x) / (xn - 1)
2476  make /n=(numpnts(ster_x), 3) /free triplet
2477  triplet[][0] = ster_x[p]
2478  triplet[][1] = ster_y[p]
2479  triplet[][2] = values[p]
2480  //ImageInterpolate /stw /s={x0, dx, xn, x0, dx, xn} voronoi triplet
2481 
2482  variable size = 181
2483  make /n=(size, size) /d /o $(s_prefix + "matrix") /wave=matrix
2484  make /n=(size, size) /free mnorm
2485  ImageFromXYZ /as {ster_x, ster_y, values}, matrix, mnorm
2486  matrix /= mnorm
2487  matrixfilter NanZapMedian, matrix
2488  matrixfilter gauss, matrix
2489 
2490  matrix = (x^2 + y^2) < 4 ? matrix : nan
2491 };
2492 
2503 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){
2504  wave data// 2D intensity wave, see requirements above
2505  string nickname// nick name for output data
2506  // in default mode, this will be the name of a child folder containing the output
2507  // in XPDplot mode, this will be a prefix of the generated data in the root folder
2508  variable theta_offset// manipulator theta angle corresponding to normal emission
2509  variable tilt_offset// manipulator tilt angle corresponding to normal emission
2510  variable phi_offset// manipulator phi angle corresponding to phi_result = 0
2511  variable npolar// number of polar angles, determines polar and azimuthal step size
2512  // default = 91 (1 degree steps)
2513  variable nograph// 0 (default) = display a new polar graph
2514  // 1 = don't display a new graph (if a graph is existing from a previous call, it will update)
2515  variable folding// rotational averaging, default = 1
2516 
2517  if (ParamIsDefault(npolar))
2518  npolar = 91
2519  endif
2520  if (ParamIsDefault(nograph))
2521  nograph = 0
2522  endif
2523  if (ParamIsDefault(folding))
2524  folding = 1
2525  endif
2526  string graphname = "graph_" + nickname
2527  string s_prefix = ""
2528 
2529  // sort out data folder structure
2530  dfref saveDF = GetDataFolderDFR()
2531  dfref dataDF = GetWavesDataFolderDFR(data)
2532  setdatafolder dataDF
2533  if (DataFolderExists(":attr"))
2534  setdatafolder :attr
2535  endif
2536  dfref attrDF = GetDataFolderDFR()
2537  setdatafolder dataDF
2538  newdatafolder /s/o $nickname
2539  dfref destDF = GetDataFolderDFR()
2540 
2541  // performance monitoring
2542  variable timerRefNum
2543  variable /g xyz_perf_secs
2544  timerRefNum = startMSTimer
2545 
2546  wave /sdfr=attrDF ManipulatorTheta
2547  wave /sdfr=attrDF ManipulatorTilt
2548  wave /sdfr=attrDF ManipulatorPhi
2549  duplicate /free ManipulatorTheta, m_theta
2550  duplicate /free ManipulatorTilt, m_tilt
2551  duplicate /free ManipulatorPhi, m_phi
2552  m_theta -= theta_offset
2553  m_tilt -= tilt_offset
2554  m_tilt *= -1// checked 140702
2555  m_phi -= phi_offset
2556  //m_phi *= -1 // checked 140702
2557 
2558  make /n=1/d/free d_polar, d_azi
2559  convert_angles_ttpd2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
2560  d_azi += 180// changed 151030 (v1.6)
2561  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
2562 
2563  duplicate /free data, values
2564  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2565  redimension /n=(nn) values, d_polar, d_azi
2566  duplicate /o d_polar, ster_rad, ster_x, ster_y
2567 
2568  variable projection = 1
2569  switch(projection)
2570  case 1:// stereographic
2571  ster_rad = 2 * tan(d_polar / 2 * pi / 180)
2572  break
2573  case 2:// azimuthal
2574  ster_rad = 2 * cos((180 - d_polar) / 2 * pi / 180)
2575  break
2576  endswitch
2577  string s_ster_x = s_prefix + "ster_x"
2578  string s_ster_y = s_prefix + "ster_y"
2579 
2580  nn = 401
2581  make /n=(nn, nn) /d /o matrix
2582  make /n=(nn, nn) /free mnorm
2583  setscale /i x -2, +2, matrix, mnorm
2584  setscale /i y -2, +2, matrix, mnorm
2585  matrix = 0
2586  mnorm = 0
2587 
2588  variable ifold
2589  for (ifold = 0; ifold < folding; ifold += 1)
2590  ster_x = ster_rad * cos(d_azi * pi / 180)
2591  ster_y = ster_rad * sin(d_azi * pi / 180)
2592  ImageFromXYZ {ster_x, ster_y, values}, matrix, mnorm
2593  d_azi = d_azi >= 180 ? d_azi + 360 / folding - 180 : d_azi + 360 / folding
2594  endfor
2595 
2596  matrix /= mnorm
2597  matrixfilter /n=5 NanZapMedian matrix
2598  matrixfilter /n=3 gauss matrix
2599 
2600  if (!nograph)
2601  display /k=1
2602  appendimage matrix
2603  modifygraph width={Plan,1,bottom,left}
2604  endif
2605 
2606  if (timerRefNum >= 0)
2607  xyz_perf_secs = stopMSTimer(timerRefNum) / 1e6
2608  endif
2609 
2610  setdatafolder saveDF
2611 };
2612 
2614 variable save_hemi_scan(string nickname, string pathname, string filename){
2615  string nickname
2616  string pathname
2617  string filename
2618 
2619  dfref savedf = getdatafolderdfr()
2620 
2621  // source data
2622  if (strlen(nickname))
2623  string s_prefix = nickname + "_"
2624  string s_int = s_prefix + "i"
2625  else
2626  s_prefix = ""
2627  s_int = "values"
2628  endif
2629  string s_polar = s_prefix + "pol"
2630  string s_azim = s_prefix + "az"
2631  string s_theta = s_prefix + "th"
2632  string s_tot = s_prefix + "tot"
2633  string s_weight = s_prefix + "wt"
2634 
2635  wave theta1 = $s_theta
2636  wave polar1 = $s_polar
2637  wave azim1 = $s_azim
2638  wave tot1 = $s_tot
2639  wave weight1 = $s_weight
2640  wave values1 = $s_int
2641 
2642  save /m="\r\n" /o /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2643 
2644  setdatafolder saveDF
2645 };
2646 
2650 variable load_hemi_scan(string nickname, string pathname, string filename){
2651  string nickname
2652  string pathname
2653  string filename
2654 
2655  dfref savedf = getdatafolderdfr()
2656 
2657  //loadwave /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
2658  //LoadWave /t/p=pearl_explorer_filepath/q filename
2659  //svar waves = s_wavenames
2660  //if (v_flag > 0)
2661  // string /g pearl_explorer_import = "load_itx_file"
2662  //endif
2663 
2664  setdatafolder saveDF
2665 };
2666 
2699 variable import_tpi_scan(string nickname, wave theta, wave phi, wave intensity, variable folding = defaultValue, variable npolar = defaultValue, variable nograph = defaultValue, variable xpdplot = defaultValue){
2700  string nickname
2701  wave theta
2702  wave phi
2703  wave intensity
2704 
2705  variable folding
2706  variable npolar
2707  variable nograph
2708  variable xpdplot
2709 
2710  if (ParamIsDefault(npolar))
2711  npolar = 91
2712  endif
2713  if (ParamIsDefault(nograph))
2714  nograph = 0
2715  endif
2716  if (ParamIsDefault(folding))
2717  folding = 1
2718  endif
2719  if (ParamIsDefault(xpdplot))
2720  xpdplot = 0
2721  endif
2722 
2723  make_hemi_grid(npolar, nickname, xpdplot=xpdplot)
2724 
2725  variable ifold
2726  duplicate /free phi, fold_phi
2727  for (ifold = 0; ifold < folding; ifold += 1)
2728  hemi_add_anglescan(nickname, intensity, theta, fold_phi)
2729  fold_phi = fold_phi >= 180 ? fold_phi + 360 / folding - fold_phi : fold_phi + 360 / folding
2730  endfor
2731 
2732  if (nograph==0)
2733  display_hemi_scan(nickname)
2734  endif
2735 };
2736 
2748 variable trim_hemi_scan(string nickname, variable theta_max){
2749  string nickname
2750  variable theta_max
2751 
2752  if (strlen(nickname))
2753  string s_prefix = nickname + "_"
2754  string s_int = s_prefix + "i"
2755  else
2756  s_prefix = ""
2757  s_int = "values"
2758  endif
2759  string s_totals = s_prefix + "tot"
2760  string s_weights = s_prefix + "wt"
2761  string s_polar = s_prefix + "pol"
2762 
2763  wave w_polar = $s_polar
2764  wave w_values = $s_int
2765  wave w_totals = $s_totals
2766  wave w_weights = $s_weights
2767 
2768  w_values = w_polar <= theta_max ? w_totals / w_weights : nan
2769 };
2770 
2790 wave hemi_polar_cut(string nickname, variable azim){
2791  string nickname
2792  variable azim
2793 
2794  if (strlen(nickname))
2795  string s_prefix = nickname + "_"
2796  string s_int = s_prefix + "i"
2797  else
2798  s_prefix = ""
2799  s_int = "values"
2800  endif
2801  string s_totals = s_prefix + "tot"
2802  string s_weights = s_prefix + "wt"
2803  string s_polar = s_prefix + "pol"
2804  string s_azim = s_prefix + "az"
2805  string s_index = s_prefix + "index"
2806  string s_theta = s_prefix + "th"
2807  string s_dphi = s_prefix + "dphi"
2808  string s_nphis = s_prefix + "nphis"
2809  string s_cut
2810  sprintf s_cut, "%s_azi%03u", s_int, round(azim)
2811 
2812  wave w_polar = $s_polar
2813  wave w_azim = $s_azim
2814  wave w_values = $s_int
2815  wave w_totals = $s_totals
2816  wave w_weights = $s_weights
2817  wave w_index = $s_index
2818  wave w_theta = $s_theta
2819  wave w_dphi = $s_dphi
2820  wave w_nphis = $s_nphis
2821 
2822  variable npol = numpnts(w_theta)
2823  variable ipol
2824  variable pol_st = abs(w_theta[1] - w_theta[0])
2825  variable pol
2826  variable pol1, pol2
2827  variable nsel
2828  make /n=(npol) /o $s_cut
2829  wave w_cut = $s_cut
2830  setscale /i x w_theta[0], w_theta[numpnts(w_theta)-1], "deg", w_cut
2831  make /n=1 /free azi_slice
2832  make /n=1 /free values_slice
2833 
2834  for (ipol = 0; ipol < npol; ipol += 1)
2835  pol = w_theta[ipol]
2836  pol1 = pol - pol_st / 2
2837  pol2 = pol + pol_st / 2
2838  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2839  nsel = numpnts(sel)
2840  if (nsel > 0)
2841  redimension /n=(nsel+2) azi_slice, values_slice
2842  azi_slice[1, nsel] = w_azim[sel[p-1]]
2843  azi_slice[0] = azi_slice[nsel] - 360
2844  azi_slice[nsel+1] = azi_slice[1] + 360
2845  values_slice[1, nsel] = w_values[sel[p-1]]
2846  values_slice[0] = values_slice[nsel]
2847  values_slice[nsel+1] = values_slice[1]
2848  w_cut[ipol] = interp(azim, azi_slice, values_slice)
2849  else
2850  w_cut[ipol] = nan
2851  endif
2852  endfor
2853  return w_cut
2854 };
2855 
2874 wave hemi_azi_cut(string nickname, variable pol){
2875  string nickname
2876  variable pol
2877 
2878  if (strlen(nickname))
2879  string s_prefix = nickname + "_"
2880  string s_int = s_prefix + "i"
2881  else
2882  s_prefix = ""
2883  s_int = "values"
2884  endif
2885  string s_totals = s_prefix + "tot"
2886  string s_weights = s_prefix + "wt"
2887  string s_polar = s_prefix + "pol"
2888  string s_azim = s_prefix + "az"
2889  string s_index = s_prefix + "index"
2890  string s_theta = s_prefix + "th"
2891  string s_dphi = s_prefix + "dphi"
2892  string s_nphis = s_prefix + "nphis"
2893  string s_cut
2894  sprintf s_cut, "%s_pol%03u", s_int, round(pol)
2895 
2896  wave w_polar = $s_polar
2897  wave w_azim = $s_azim
2898  wave w_values = $s_int
2899  wave w_totals = $s_totals
2900  wave w_weights = $s_weights
2901  wave w_index = $s_index
2902  wave w_theta = $s_theta
2903  wave w_dphi = $s_dphi
2904  wave w_nphis = $s_nphis
2905 
2906  variable pol_st = abs(w_theta[1] - w_theta[0])
2907  variable pol1, pol2
2908  variable nsel
2909 
2910  pol1 = pol - pol_st / 2
2911  pol2 = pol + pol_st / 2
2912  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
2913  nsel = numpnts(sel)
2914  if (nsel > 0)
2915  make /n=(nsel) /o $s_cut
2916  wave w_cut = $s_cut
2917  w_cut = w_values[sel]
2918  setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "", w_cut
2919  return w_cut
2920  else
2921  return $""
2922  endif
2923 };
2924 
2925 static variable check_contrast(wave values, variable pcmin, variable pcmax, variable* vmin, variable* vmax){
2926  wave values
2927  variable pcmin
2928  variable pcmax
2929  variable &vmin
2930  variable &vmax
2931 
2932  dfref save_df = GetDataFolderDFR()
2933  dfref dfr = NewFreeDataFolder()
2934  setdatafolder dfr
2935  StatsQuantiles /inan /iw /q /z values
2936  wave index = w_quantilesindex
2937  variable imin = round(numpnts(index) * pcmin / 100)
2938  variable imax = round(numpnts(index) * (100 - pcmax) / 100)
2939  vmin = values[index[imin]]
2940  vmax = values[index[imax]]
2941  KillDataFolder dfr
2942  setdatafolder save_df
2943 };
2944 
2961 variable set_contrast(variable pcmin, variable pcmax, string graphname = defaultValue, string colortable = defaultValue){
2962  variable pcmin
2963  variable pcmax
2964  string graphname
2965  string colortable
2966 
2967  if (ParamIsDefault(graphname))
2968  graphname = ""
2969  endif
2970  if (ParamIsDefault(colortable))
2971  colortable = ""
2972  endif
2973 
2974  dfref save_df = GetDataFolderDFR()
2975 
2976  string objname
2977  string info
2978  string wname
2979  string ctab
2980  variable rev
2981  variable n
2982  variable i
2983  variable vmin
2984  variable vmax
2985 
2986  string traces = TraceNameList(graphname, ";", 1+4)
2987  n = ItemsInList(traces, ";")
2988  for (i = 0; i < n; i += 1)
2989  objname = StringFromList(i, traces, ";")
2990  info = TraceInfo(graphname, objname, 0)
2991  if (strlen(info) > 0)
2992  info = StringByKey("RECREATION", info, ":", ";")
2993  info = StringByKey("zColor(x)", info, "=", ";")
2994  if (strlen(info) > 2)
2995  info = info[1,strlen(info)-2]
2996  wname = StringFromList(0, info, ",")
2997  wave w = $wname
2998  ctab = StringFromList(3, info, ",")
2999  rev = str2num("0" + StringFromList(4, info, ","))
3000  if (strlen(colortable) > 0)
3001  ctab = colortable
3002  endif
3003  check_contrast(w, pcmin, pcmax, vmin, vmax)
3004  ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
3005  endif
3006  endif
3007  endfor
3008 
3009  string images = ImageNameList(graphname, ";")
3010  n = ItemsInList(images, ";")
3011  for (i = 0; i < n; i += 1)
3012  objname = StringFromList(i, images, ";")
3013  wave w = ImageNameToWaveRef(graphname, objname)
3014  info = ImageInfo(graphname, objname, 0)
3015  if (strlen(info) > 0)
3016  info = StringByKey("RECREATION", info, ":", ";")
3017  info = StringByKey("ctab", info, "=", ";")
3018  if (strlen(info) > 2)
3019  info = info[1,strlen(info)-2]
3020  ctab = StringFromList(2, info, ",")
3021  rev = str2num("0" + StringFromList(3, info, ","))
3022  if (strlen(colortable) > 0)
3023  ctab = colortable
3024  endif
3025  check_contrast(w, pcmin, pcmax, vmin, vmax)
3026  ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
3027  endif
3028  endif
3029  endfor
3030 
3031  setdatafolder save_df
3032 };
3033 
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
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_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
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 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
+
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 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
-
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
+
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 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.
@@ -179,7 +182,7 @@ $(document).ready(function(){initNavTree('pearl-anglescan-process_8ipf_source.ht @@ -1070,7 +1071,7 @@ Functions -

Definition at line 1770 of file pearl-area-display.ipf.

+

Definition at line 1783 of file pearl-area-display.ipf.

@@ -1163,7 +1164,7 @@ Functions

export a slice (button procedure).

extract a slice and saves it in a separate wave.

-

Definition at line 1599 of file pearl-area-display.ipf.

+

Definition at line 1612 of file pearl-area-display.ipf.

@@ -1191,7 +1192,7 @@ Functions

move slice (button procedure).

-

Definition at line 1554 of file pearl-area-display.ipf.

+

Definition at line 1563 of file pearl-area-display.ipf.

@@ -1235,7 +1236,7 @@ Functions

move the slice to the center of the dimension (button procedure).

-

Definition at line 1653 of file pearl-area-display.ipf.

+

Definition at line 1666 of file pearl-area-display.ipf.

@@ -1503,7 +1504,9 @@ Functions
-

Definition at line 1498 of file pearl-area-display.ipf.

+

set slice coordinate (slider procedure).

+ +

Definition at line 1499 of file pearl-area-display.ipf.

@@ -1531,7 +1534,7 @@ Functions

set slice coordinate (button procedure).

-

Definition at line 1526 of file pearl-area-display.ipf.

+

Definition at line 1531 of file pearl-area-display.ipf.

@@ -1595,7 +1598,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 = PearlAreaDisplay
4 #pragma version = 1.04
5 
19 // 3D data is handled by 3 windows. they don't have to be visible all at the same time.
48 
54 
56 static string graphname_from_dfref(dfref df, string prefix){
57  dfref df
58  string prefix
59 
60  string name
61 
62  name = GetDataFolder(1, df)
63  name = ReplaceString("root:", name, "")
64  name = name[0, strlen(name) - 2]
65  name = ReplaceString(" ", name, "")
66  name = CleanupName(prefix + name, 0)
67  if (CheckName(name, 6))
68  name = UniqueName(name, 6, 0)
69  endif
70 
71  return name
72 };
73 
84 string ad_display(wave image){
85  wave image// wave which contains the image data from the detector
86  // returns the name of the graph window
87 
88  dfref savedf = GetDataFolderDFR()
89  dfref imagedf = GetWavesDataFolderDFR(image)
90  setdatafolder imagedf
91 
92  string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
93  string graphtitle = dfname + " View"
94  string /g view_graphname = graphname_from_dfref(imagedf, "view_")
95  svar graphname = view_graphname
96  display /k=1/n=$graphname as graphtitle
97  graphname = s_name
98  appendimage /w=$graphname image
99 
100  setdatafolder savedf
101  return graphname
102 };
103 
114 string ad_display_histogram(wave image){
115  wave image
116 
117  dfref savedf = GetDataFolderDFR()
118  dfref imagedf = GetWavesDataFolderDFR(image)
119  string s_imagedf = GetDataFolder(1, imagedf)
120  setdatafolder imagedf
121 
122  make /n=(1)/o hist// histogram
123 
124  string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
125  string graphtitle = dfname + " Histogram"
126  string /g hist_graphname = graphname_from_dfref(imagedf, "hist_")
127  svar graphname = hist_graphname
128  display /k=1/n=$graphname as graphtitle
129  graphname = s_name
130  appendtograph /w=$graphname hist
131 
132  ModifyGraph /w=$graphname rgb(hist)=(39168,0,0)
133  ModifyGraph /w=$graphname mode=6
134  ModifyGraph /w=$graphname mirror=1
135  ModifyGraph /w=$graphname minor=1
136  ModifyGraph /w=$graphname axThick=0.5
137  ModifyGraph /w=$graphname lblPosMode=1,lblPos=30,lblMargin=0
138  ModifyGraph /w=$graphname btLen=4
139  ModifyGraph /w=$graphname margin(left)=45,margin(bottom)=35,margin(top)=10,margin(right)=10
140  ModifyGraph /w=$graphname gfSize=10
141  Label /w=$graphname bottom "value"
142  Label /w=$graphname left "# pixels"
143 
144  ad_calc_histogram(image)
145 
146  setdatafolder savedf
147  return graphname
148 };
149 
165 string ad_display_profiles(wave image, string filter = defaultValue){
166  wave image
167  string filter
168  variable show_legend = 0// currently not supported
169 
170  if (WaveDims(image) != 2)
171  abort "ad_display_profiles: image wave must be two-dimensional."
172  endif
173  if (ParamIsDefault(filter))
174  filter = "ad_box_filter"
175  endif
176 
177  // data folders and references
178  dfref savedf = GetDataFolderDFR()
179  dfref imagedf = GetWavesDataFolderDFR(image)
180  string s_imagedf = GetDataFolder(1, imagedf)
181  setdatafolder imagedf
182  string s_viewdf = CleanupName("view_" + NameOfWave(image), 0)
183  newdatafolder /o/s $s_viewdf
184  dfref viewdf = GetDataFolderDFR()
185  s_viewdf = GetDataFolder(1, viewdf)
186 
187  // data structures
188  string /g sourcepath = GetWavesDataFolder(image, 2)
189  string viewname = "view_image"
190  duplicate /o image, $viewname /wave=view
191  make /n=(3,3)/o xprofiles// NX x 3 wave with 3 one-dimensional profiles along Y dimension
192  make /n=(3,3)/o yprofiles// NY x 3 wave with 3 one-dimensional profiles along X dimension
193  string /g view_filter
194  string /g view_filter_options
195  view_filter = filter
196  view_filter_options = ""
197  variable /g view_filter_smoothing_x = 1
198  variable /g view_filter_smoothing_y = 1
199  variable /g view_cursor_mode = 0
200  string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
201  string graphtitle = dfname + NameOfWave(image) + " Profiles"
202  string /g prof_graphname = graphname_from_dfref(imagedf, "prof_")
203  svar graphname = prof_graphname
204  variable /g graph_avg// average value in ROI (ROI is defined by the crosshairs A and B)
205  variable /g graph_min// minimum value in ROI
206  variable /g graph_max// maximum value in ROI
207  variable /g graph_sum// sum of all values in ROI
208  variable /g graph_sdev// standard deviation of all values in ROI
209 
210  // graph setup
211  display /k=1 /n=$graphname /w=(100,100,500,400) as graphtitle
212  graphname = s_name
213  AppendToGraph /w=$graphname /L=xprofiles xprofiles[*][0],xprofiles[*][1],xprofiles[*][2]
214  AppendToGraph /w=$graphname /VERT/B=yprofiles yprofiles[*][0],yprofiles[*][1],yprofiles[*][2]
215  AppendImage /w=$graphname view
216  string imgname = StringFromList(0, ImageNameList(graphname, ";"))
217  ModifyImage /w=$graphname $imgname ctab= {*,*,BlueGreenOrange,0}
218  ModifyGraph /w=$graphname rgb(xprofiles)=(39168,0,0),rgb(yprofiles)=(39168,0,0)
219  ModifyGraph /w=$graphname rgb(xprofiles#1)=(0,26112,0),rgb(yprofiles#1)=(0,26112,0)
220  ModifyGraph /w=$graphname rgb(xprofiles#2)=(0,9472,39168),rgb(yprofiles#2)=(0,9472,39168)
221  ModifyGraph /w=$graphname mirror(xprofiles)=2,mirror(bottom)=3,mirror(yprofiles)=2,mirror(left)=3
222  ModifyGraph /w=$graphname nticks=3
223  ModifyGraph /w=$graphname minor=1
224  ModifyGraph /w=$graphname axThick=0.5
225  ModifyGraph /w=$graphname lblPosMode=1,lblPos=30,lblMargin=0
226  ModifyGraph /w=$graphname btLen=4
227  ModifyGraph /w=$graphname freePos(xprofiles)=0
228  ModifyGraph /w=$graphname freePos(yprofiles)=0
229  ModifyGraph /w=$graphname axisEnab(xprofiles)={0.64,1}
230  ModifyGraph /w=$graphname axisEnab(bottom)={0,0.6}
231  ModifyGraph /w=$graphname axisEnab(yprofiles)={0.64,1}
232  ModifyGraph /w=$graphname axisEnab(left)={0,0.6}
233  ModifyGraph /w=$graphname zero(left)=8
234  ModifyGraph /w=$graphname margin(left)=40,margin(bottom)=30,margin(top)=20,margin(right)=40
235  ModifyGraph /w=$graphname gfSize=10
236 
237  // axis labels
238  string labels = note(image)
239  string lab
240  lab = StringByKey("AxisLabelX", labels, "=", "\r")
241  if (!strlen(lab))
242  lab = "X"
243  endif
244  Label /w=$graphname bottom lab + " (\\U)"
245  lab = StringByKey("AxisLabelY", labels, "=", "\r")
246  if (!strlen(lab))
247  lab = "Y"
248  endif
249  Label /w=$graphname left lab + " (\\U)"
250  lab = StringByKey("AxisLabelD", labels, "=", "\r")
251  if (!strlen(lab))
252  lab = "value"
253  endif
254  Label /w=$graphname xprofiles lab + " (\\U)"
255  Label /w=$graphname yprofiles lab + " (\\U)"
256 
257  // legend
258  if (show_legend)
259  Legend /w=$graphname/C/N=text0/J/F=2/D=0.5/T={28}/A=RT/X=0.00/Y=0.00 "\\s(xprofiles)\tprofile A"
260  AppendText /w=$graphname "\\s(xprofiles#1)\tprofile B"
261  AppendText /w=$graphname "\\s(xprofiles#2)\tROI average"
262  AppendText /w=$graphname "min\t\\{" + s_viewdf + "graph_min}"
263  AppendText /w=$graphname "max\t\\{" + s_viewdf + "graph_max}"
264  AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
265  AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
266  AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
267  else
268  TextBox /w=$graphname /C/N=text0 /F=0 /B=1 /X=1.00 /Y=1.00
269  lab = StringByKey("Dataset", labels, "=", "\r")
270  if (strlen(lab))
271  AppendText /w=$graphname lab
272  endif
273  AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
274  AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
275  AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
276  endif
277 
278  // interactive elements
279  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A $imgname 0,0
280  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B $imgname DimSize(view, 0)-1, DimSize(view, 1)-1
281  variable pcurs
282  pcurs = floor(DimSize(xprofiles, 0) / 3)
283  Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs
284  pcurs = floor(DimSize(xprofiles, 0) * 2 / 3)
285  Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs
286  pcurs = floor(DimSize(yprofiles, 0) / 3)
287  Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs
288  pcurs = floor(DimSize(yprofiles, 0) * 2 / 3)
289  Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs
290  ShowInfo /w=$graphname /CP=0
291 
292  SetWindow $graphname, hook(ad_profiles_hook)=ad_profiles_hook
293  ControlBar /w=$graphname 21
294  Button b_reset_cursors win=$graphname, title="reset cursors",pos={0,0},size={70,20},proc=PearlAreaDisplay#bp_reset_cursors
295  Button b_reset_cursors win=$graphname, fColor=(65535,65535,65535),fSize=10
296 
297  SetVariable sv_smoothing_x win=$graphname, title="X smoothing",pos={130,2},bodyWidth=40
298  SetVariable sv_smoothing_x win=$graphname, value=view_filter_smoothing_x,limits={1,100,1}
299  SetVariable sv_smoothing_x win=$graphname, proc=PearlAreaDisplay#svp_smoothing
300  SetVariable sv_smooting_y win=$graphname, title="Y smoothing",pos={240,2},bodyWidth=40
301  SetVariable sv_smooting_y win=$graphname, value=view_filter_smoothing_y,limits={1,100,1}
302  SetVariable sv_smooting_y win=$graphname, proc=PearlAreaDisplay#svp_smoothing
303 
304  PopupMenu pm_export win=$graphname, mode=0,title="Export"
305  PopupMenu pm_export win=$graphname, value="X profile;Y profile;X profile (collate);Y profile (collate)"
306  PopupMenu pm_export win=$graphname, pos={308,0},bodyWidth=60,proc=PearlAreaDisplay#pmp_export
307  PopupMenu pm_export win=$graphname, help={"Export profile of selected area and display in graph. Collate mode = display all profiles in same graph."}
308 
309  // data processing
310  ad_update_profiles(image)
311 
312  setdatafolder savedf
313  return graphname
314 };
315 
321 variable ad_update_profiles(wave image){
322  wave image
323 
324  // data folders and references
325  dfref viewdf = get_view_folder(image)
326  if (DataFolderRefStatus(viewdf) == 0)
327  return -1// data folder not found
328  endif
329  dfref savedf = GetDataFolderDFR()
330  setdatafolder viewdf
331 
332  // data structures
333  string viewname = "view_image"
334  duplicate /o image, $viewname /wave=view
335 
336  // data processing
337  svar view_filter
338  svar view_filter_options
339  nvar smoothing_x = view_filter_smoothing_x
340  nvar smoothing_y = view_filter_smoothing_y
341  funcref ad_default_image_filter filterfunc = $view_filter
342  view_filter_options = ReplaceNumberByKey("SmoothingX", view_filter_options, smoothing_x, "=", ";")
343  view_filter_options = ReplaceNumberByKey("SmoothingY", view_filter_options, smoothing_y, "=", ";")
344  filterfunc(view, view_filter_options)
345 
347 
348  setdatafolder savedf
349  return 0
350 };
351 
368 variable ad_profiles_cursor_mode(wave image, variable mode){
369  wave image
370  variable mode
371 
372  dfref savedf = GetDataFolderDFR()
373  wave view_image = get_view_image(image)
374  dfref viewdf = GetWavesDataFolderDFR(view_image)
375  svar /sdfr=viewdf graphname = prof_graphname
376  nvar /sdfr=viewdf cursor_mode = view_cursor_mode
377  wave /sdfr=viewdf xprofiles, yprofiles
378 
379  variable dx = DimSize(view_image, 0)
380  variable dy = DimSize(view_image, 1)
381  switch(mode)
382  case 1:// background selection
383  Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 A view_image 0, 0
384  Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1
385  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 C view_image round(0.2 * dx) -1, 0
386  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 D view_image round(0.8 * dx) -1, 0
387  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 E view_image round(0.4 * dx) -1, 0
388  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 F view_image round(0.6 * dx) -1, 0
389 
390  ShowInfo /w=$graphname /CP=0
391  cursor_mode = mode
392  break
393  default:
394  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A view_image 0,0
395  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1
396  variable pcurs
397  pcurs = floor(DimSize(xprofiles, 0) / 3)
398  Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs
399  pcurs = floor(DimSize(xprofiles, 0) * 2 / 3)
400  Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs
401  pcurs = floor(DimSize(yprofiles, 0) / 3)
402  Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs
403  pcurs = floor(DimSize(yprofiles, 0) * 2 / 3)
404  Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs
405  ShowInfo /w=$graphname /CP=0
406  cursor_mode = 0
407  endswitch
408 
409  setdatafolder savedf
410  return 0
411 };
412 
429 variable ad_profiles_set_cursor(wave image, string cursorname, variable xa, variable ya, variable pscale = defaultValue){
430  wave image
431  string cursorname
432  variable xa, ya
433  variable pscale
434 
435  if (ParamIsDefault(pscale))
436  pscale = 0
437  endif
438 
439  // data folders and references
440  dfref savedf = GetDataFolderDFR()
441  wave view_image = get_view_image(image)
442  dfref viewdf = GetWavesDataFolderDFR(view_image)
443  svar /sdfr=viewdf graphname = prof_graphname
444 
445  variable pa, qa
446  if (pscale)
447  pa = xa
448  qa = ya
449  else
450  pa = round((xa - DimOffset(view_image, 0)) / DimDelta(view_image, 0))
451  qa = round((ya - DimOffset(view_image, 1)) / DimDelta(view_image, 1))
452  endif
453 
454  pa = min(pa, DimSize(view_image, 0) - 1)
455  pa = max(pa, 0)
456  qa = min(qa, DimSize(view_image, 1) - 1)
457  qa = max(qa, 0)
458  Cursor /i /p /w=$graphname $cursorname view_image pa, qa
459 
460  setdatafolder savedf
461  return 0
462 };
463 
474 // the lines can be removed manually using the draw toolbox, or by calling this function with @c clean=1.
481 variable ad_profiles_crosshairs(wave image, variable clear = defaultValue){
482  wave image
483  variable clear
484 
485  if (ParamIsDefault(clear))
486  clear = 0
487  endif
488 
489  // data folders and references
490  wave view_image = get_view_image(image)
491  dfref viewdf = GetWavesDataFolderDFR(view_image)
492  svar /sdfr=viewdf graphname = prof_graphname
493 
494  string cursors = "A;B"
495  string colors = "39168,0,0;0,26112,0"
496  string color
497  variable ncursors
498  variable icursor
499  string cursorname
500  string groupname = "crosshairs"
501  variable xx, yy
502  struct RGBColor rgb
503 
504  if (clear == 0)
505  SetDrawEnv /W=$graphname push
506  DrawAction /w=$graphname getgroup=$groupname, delete, begininsert
507  SetDrawEnv /w=$graphname gstart, gname=$groupname
508 
509  SetDrawEnv /W=$graphname dash=4
510  SetDrawEnv /W=$graphname linethick=0.5
511 
512  ncursors = ItemsInList(cursors, ";")
513  for (icursor=0; icursor < ncursors; icursor += 1)
514  cursorname = StringFromList(icursor, cursors, ";")
515  color = StringFromList(icursor, colors, ";")
516  rgb.red = str2num(StringFromList(0, color, ","))
517  rgb.green = str2num(StringFromList(1, color, ","))
518  rgb.blue = str2num(StringFromList(2, color, ","))
519  if (strlen(CsrInfo($cursorname, graphname)) > 0)
520  xx = hcsr($cursorname, graphname)
521  yy = vcsr($cursorname, graphname)
522  SetDrawEnv /W=$graphname linefgc=(rgb.red, rgb.green, rgb.blue)
523  SetDrawEnv /W=$graphname save
524  SetDrawEnv /W=$graphname xcoord=bottom, ycoord=prel
525  DrawLine /W=$graphname xx, 0, xx, 1
526  SetDrawEnv /W=$graphname xcoord=prel, ycoord=left
527  DrawLine /W=$graphname 0, yy, 1, yy
528  endif
529  endfor
530 
531  SetDrawEnv /w=$graphname gstop
532  DrawAction /w=$graphname endinsert
533  SetDrawEnv /W=$graphname pop
534  SetDrawEnv /W=$graphname save
535  else
536  DrawAction /w=$graphname getgroup=$groupname, delete
537  endif
538 
539  return 0
540 };
541 
547 static wave get_source_image(wave view){
548  wave view// image wave displayed in a profiles window
549 
550  dfref viewdf = GetWavesDataFolderDFR(view)
551  svar /z /sdfr=viewdf sourcepath
552  if (svar_exists(sourcepath))
553  wave /z img = $sourcepath
554  else
555  wave /z img = $""
556  endif
557  return img
558 };
559 
561 static dfr make_view_folder(wave source){
562  wave source// wave which contains the raw data from the detector.
563 
564  // data folders and references
565  dfref savedf = GetDataFolderDFR()
566  dfref imagedf = GetWavesDataFolderDFR(source)
567  string s_imagedf = GetDataFolder(1, imagedf)
568  setdatafolder imagedf
569  string s_viewdf = CleanupName("view_" + NameOfWave(source), 0)
570  newdatafolder /o/s $s_viewdf
571  dfref viewdf = GetDataFolderDFR()
572 
573  setdatafolder savedf
574  return viewdf
575 };
576 
585 static dfr get_view_folder(wave source){
586  wave source
587 
588  // data folders and references
589  dfref savedf = GetDataFolderDFR()
590  dfref imagedf = GetWavesDataFolderDFR(source)
591  dfref viewdf
592  setdatafolder imagedf
593  string s_viewdf = CleanupName("view_" + NameOfWave(source), 0)
594  if (DataFolderExists(s_viewdf))
595  setdatafolder $s_viewdf
596  viewdf = GetDataFolderDFR()
597  endif
598 
599  setdatafolder savedf
600  return viewdf
601 };
602 
608 static wave get_view_image(wave source){
609  wave source
610 
611  dfref viewdf = get_view_folder(source)
612  string viewname = "view_image"
613  wave /sdfr=viewdf view = $viewname
614 
615  return view
616 };
617 
618 static variable bp_reset_cursors(WMButtonAction* ba){
619  STRUCT WMButtonAction &ba
620 
621  switch( ba.eventCode )
622  case 2:// mouse up
623  string imgname = StringFromList(0, ImageNameList(ba.win, ";"))
624  wave /z image = ImageNameToWaveRef(ba.win, imgname)
625  if (waveexists(image))
626  Cursor /i/p A $imgname 0,0
627  Cursor /i/p B $imgname DimSize(image, 0)-1, DimSize(image, 1)-1
628  endif
629  break
630  case -1:// control being killed
631  break
632  endswitch
633 
634  return 0
635 };
636 
637 static variable svp_smoothing(WMSetVariableAction* sva){
638  STRUCT WMSetVariableAction &sva
639 
640  string imglist
641 
642  switch( sva.eventCode )
643  case 1:// mouse up
644  case 2:// Enter key
645  case 3:// Live update
646  imglist = ImageNameList(sva.win, ";")
647  wave /z img = ImageNameToWaveRef(sva.win, StringFromList(0, imglist))
648  if (WaveExists(img))
649  wave source = get_source_image(img)
650  if (WaveExists(source))
651  ad_update_profiles(source)
652  endif
653  endif
654  break
655  case -1:// control being killed
656  break
657  endswitch
658 
659  return 0
660 };
661 
662 static variable pmp_export(WMPopupAction* pa){
663  STRUCT WMPopupAction &pa
664 
665  switch( pa.eventCode )
666  case 2:// mouse up
667  variable popNum = pa.popNum
668 
669  string imgname = StringFromList(0, ImageNameList(pa.win, ";"))
670  wave /z image = ImageNameToWaveRef(pa.win, imgname)
671  if (waveexists(image) && (popNum >= 1) && (popNum <= 2))
672  ad_export_profile(image, popNum - 1, show=1)
673  else if (waveexists(image) && (popNum >= 3) && (popNum <= 4))
674  ad_export_profile(image, popNum - 3, show=2)
675  endif
676 
677  break
678  case -1:// control being killed
679  break
680  endswitch
681 
682  return 0
683 };
684 
686 variable ad_profiles_hook(WMWinHookStruct* s){
687  struct WMWinHookStruct &s
688  variable hookresult = 0
689  string imglist
690  string cmd
691  dfref viewdf
692 
693  switch(s.eventCode)
694  case 2:// delete data folder after window is killed
695  imglist = ImageNameList(s.winName, ";")
696  wave /z img = ImageNameToWaveRef(s.winName, StringFromList(0, imglist))
697  if (WaveExists(img))
698  viewdf = GetWavesDataFolderDFR(img)
699  cmd = "killdatafolder /z " + GetDataFolder(1, viewdf)
700  Execute /P/Q/Z cmd
701  endif
702  break
703  case 7:// update profiles when cursor is moved
704  imglist = ImageNameList(s.winName, ";")
705  wave /z img = ImageNameToWaveRef(s.winName, StringFromList(0, imglist))
706  if (WaveExists(img))
708  hookresult = 1
709  else
710  hookresult = 0
711  endif
712  break
713  endswitch
714 
715  return hookresult
716 };
717 
726 variable ad_calc_cursor_profiles(wave image){
727  wave image
728 
729  dfref savedf = GetDataFolderDFR()
730  dfref imagedf = GetWavesDataFolderDFR(image)
731  setdatafolder imagedf
732 
733  svar graphname = prof_graphname
734 
735  variable pa, qa// point coordinates cursor A
736  if (strlen(CsrInfo(A, graphname)) > 0)
737  pa = pcsr(A, graphname)
738  qa = qcsr(A, graphname)
739  else
740  pa = 0
741  qa = 0
742  endif
743 
744  variable pb, qb// point coordinates cursor B
745  if (strlen(CsrInfo(B, graphname)) > 0)
746  pb = pcsr(B, graphname)
747  qb = qcsr(B, graphname)
748  else
749  pb = DimSize(image, 0) - 1
750  qb = DimSize(image, 1) - 1
751  endif
752 
753  ad_calc_profiles(image, pa, qa, pb, qb)
754  setdatafolder savedf
755 };
756 
773 variable ad_calc_profiles(wave image, variable pa, variable qa, variable pb, variable qb){
774  wave image
775  variable pa, qa
776  variable pb, qb
777 
778  dfref savedf = GetDataFolderDFR()
779  dfref imagedf = GetWavesDataFolderDFR(image)
780  setdatafolder imagedf
781 
782  wave xprofiles
783  wave yprofiles
784  nvar graph_avg
785  nvar graph_min
786  nvar graph_max
787  nvar graph_sum
788  nvar graph_sdev
789 
790  // horizontal profiles at crosshairs
791  redimension /n=(dimsize(image,0), 3) xprofiles
792  setscale /p x dimoffset(image,0), dimdelta(image,0), WaveUnits(image,0), xprofiles
793  setscale d 0, 0, waveunits(image,-1), xprofiles
794  xprofiles[][0] = image[p][qa]
795  xprofiles[][1] = image[p][qb]
796 
797  note /k xprofiles
798  note xprofiles, "SourceWave=" + nameofwave(image)
799  note xprofiles, "SourceDimension=0"
800  note xprofiles, "SourceIndex0=" + num2str(qa)
801  note xprofiles, "SourceIndex1=" + num2str(qb)
802 
803  // average horizontal profile between crosshairs
804  variable qq, q0, q1
805  q0 = min(qa, qb)
806  q1 = max(qa, qb)
807  xprofiles[][2] = 0
808  for (qq = q0; qq <= q1; qq += 1)
809  xprofiles[][2] += image[p][qq]
810  endfor
811  xprofiles[][2] /= q1 - q0 + 1
812 
813  // vertical profiles at crosshairs
814  redimension /n=(dimsize(image,1), 3) yprofiles
815  setscale /p x dimoffset(image,1), dimdelta(image,1), WaveUnits(image,1), yprofiles
816  setscale d 0, 0, waveunits(image,-1), yprofiles
817  yprofiles[][0] = image[pa][p]
818  yprofiles[][1] = image[pb][p]
819 
820  note /k yprofiles
821  note yprofiles, "SourceWave=" + nameofwave(image)
822  note yprofiles, "SourceDimension=1"
823  note yprofiles, "SourceIndex0=" + num2str(pa)
824  note yprofiles, "SourceIndex1=" + num2str(pb)
825 
826  // average vertical profile between crosshairs
827  variable pp, p0, p1
828  p0 = min(pa, pb)
829  p1 = max(pa, pb)
830  yprofiles[][2] = 0
831  for (pp = p0; pp <= p1; pp += 1)
832  yprofiles[][2] += image[pp][p]
833  endfor
834  yprofiles[][2] /= p1 - p0 + 1
835 
836  // statistics between crosshairs
837  Duplicate /r=[p0,p1][q0,q1]/o image, roi_image
838  WaveStats /Q roi_image
839  graph_avg = v_avg
840  graph_min = v_min
841  graph_max = v_max
842  graph_sum = v_avg * v_npnts
843  graph_sdev = v_sdev
844 
845  // histogram
846  wave /z hist
847  if (waveexists(hist))
848  Histogram /B=3 roi_image, hist
849  endif
850 
851  setdatafolder savedf
852 };
853 
875 variable ad_export_profile(wave view_image, variable dim, variable trace = defaultValue, variable show = defaultValue, variable overwrite = defaultValue){
876  wave view_image
877  variable dim
878  variable trace
879  variable show
880  variable overwrite
881 
882  dfref savedf = GetDataFolderDFR()
883 
884  if (ParamIsDefault(trace))
885  trace = 2
886  endif
887  if (ParamIsDefault(show))
888  show = 0
889  endif
890  if (ParamIsDefault(overwrite))
891  overwrite = 0
892  endif
893 
894  // view folder
895  dfref imagedf = GetWavesDataFolderDFR(view_image)
896  string dim_label
897  switch(dim)
898  case 0:
899  wave /sdfr=imagedf profiles=xprofiles
900  dim_label = "x"
901  break
902  case 1:
903  wave /sdfr=imagedf profiles=yprofiles
904  dim_label = "y"
905  break
906  default:
907  return -1// invalid argument
908  endswitch
909  string graphname_string = "export_graph_" + dim_label
910  svar /z /sdfr=imagedf linked_graphname = $graphname_string
911 
912  // source folder
913  wave /z source_image = get_source_image(view_image)
914  if (WaveExists(source_image))
915  dfref sourcedf = GetWavesDataFolderDFR(source_image)
916  setdatafolder sourcedf
917  else
918  return -2// invalid source data folder
919  endif
920 
921  // format dest wave name
922  string profile_note = note(profiles)
923  string name_base
924  string name_dim
925  string name_index
926  string profile_name
927  variable index_width = ceil(log(DimSize(view_image, 1 - dim)))
928  variable index0 = NumberByKey("SourceIndex0", profile_note, "=", "\r")
929  variable index1 = NumberByKey("SourceIndex1", profile_note, "=", "\r")
930  name_dim = "_" + dim_label
931  sprintf name_index, "%0*u_%0*u", index_width, index0, index_width, index1
932  name_base = NameOfWave(source_image)
933  name_base = name_base[0, min(strlen(name_base), 31 - strlen(name_index) - strlen(name_dim) - 1)]
934  profile_name = name_base + name_dim + name_index
935  if ((overwrite == 0) && (CheckName(profile_name, 1)))
936  profile_name = UniqueName(profile_name + "_", 1, 0)
937  endif
938 
939  // create dest wave
940  duplicate /o /r=[][trace] profiles, $profile_name /wave=dest_profile
941  redimension /n=(dimsize(profiles, 0)) dest_profile
942  profile_note = ReplaceStringByKey("SourceWave", profile_note, NameOfWave(source_image), "=", "\r")
943  note /k dest_profile
944  note dest_profile, profile_note
945  print "created", GetWavesDataFolder(dest_profile, 2)
946 
947  if (show)
948  string graphname
949  string graphtitle
950  if (show == 2)
951  // common graph for all profiles of a dimension
952  graphname = "export_profiles_" + dim_label
953  graphtitle = UpperStr(dim_label) + " Profiles"
954  else
955  // one graph per source image
956  if (svar_exists(linked_graphname) && (ItemsInList(WinList(linked_graphname, ";", "WIN:1"), ";") >= 1))
957  graphname = linked_graphname
958  else
959  graphname = GetWavesDataFolder(source_image, 0) + name_dim
960  endif
961  graphtitle = UpperStr(dim_label) + " Profiles: " + GetWavesDataFolder(source_image, 2)
962  endif
963 
964  if ((ItemsInList(WinList(graphname, ";", "WIN:1"), ";") >= 1))
965  appendtograph /w=$graphname dest_profile
966  else
967  setdatafolder imagedf
968  display /k=1 /n=$graphname dest_profile as graphtitle
969  graphname = s_name
970  ModifyGraph /w=$graphname mirror=1,nticks=3,minor=1
971  ModifyGraph /w=$graphname axThick=0.5,btLen=4
972  ModifyGraph /w=$graphname gfSize=10
973  ModifyGraph /w=$graphname grid=2,gridHair=0,gridRGB=(52224,52224,52224)
974  Legend /w=$graphname /C/N=legend0/F=0/B=1/A=LT/X=0.00/Y=0.00
975 
976  if (show != 2)
977  string /g $graphname_string = graphname
978  endif
979  endif
980  endif
981 
982  setdatafolder savedf
983  return 0
984 };
985 
986 static variable set_trace_colors(string graphname){
987  string graphname
988 
989  ModifyGraph /w=$graphname /z rgb[0]=(0, 0, 0)
990  ModifyGraph /w=$graphname /z rgb[1]=(65535, 16385, 16385)
991  ModifyGraph /w=$graphname /z rgb[2]=(2, 39321, 1)
992  ModifyGraph /w=$graphname /z rgb[3]=(0, 0, 65535)
993  ModifyGraph /w=$graphname /z rgb[4]=(39321, 1, 31457)
994  ModifyGraph /w=$graphname /z rgb[5]=(48059, 48059, 48059)
995  ModifyGraph /w=$graphname /z rgb[6]=(65535, 32768, 32768)
996  ModifyGraph /w=$graphname /z rgb[7]=(0, 65535, 0)
997  ModifyGraph /w=$graphname /z rgb[8]=(16385,65535,65535)
998  ModifyGraph /w=$graphname /z rgb[9]=(65535, 32768, 58981)
999 };
1000 
1007 variable ad_calc_histogram(wave image){
1008  wave image
1009 
1010  dfref savedf = GetDataFolderDFR()
1011  dfref imagedf = GetWavesDataFolderDFR(image)
1012  setdatafolder imagedf
1013 
1014  wave hist
1015  Histogram /B=3 image, hist
1016 
1017  setdatafolder savedf
1018 };
1019 
1030 variable ad_default_image_filter(wave image, string options){
1031  wave image
1032  string options
1033 };
1034 
1044 variable ad_box_filter(wave image, string options){
1045  wave image
1046  string options
1047 
1048  variable xsmoothing = NumberByKey("SmoothingX", options, "=", ";")
1049  variable ysmoothing = NumberByKey("SmoothingY", options, "=", ";")
1050 
1051  if ((NumType(xsmoothing) == 0) && (xsmoothing >= 2))
1052  Smooth /B /DIM=0 /E=3 xsmoothing, image
1053  endif
1054  if ((NumType(ysmoothing) == 0) && (ysmoothing >= 2))
1055  Smooth /B /DIM=1 /E=3 ysmoothing, image
1056  endif
1057 };
1058 
1066 variable ad_transpose_filter(wave image, string options){
1067  wave image
1068  string options
1069 
1070  MatrixTranspose image
1071 };
1072 
1073 
1074 // ################### 3D DATA ##################
1075 
1082 string ad_display_brick(wave data){
1083  wave data
1084 
1085  if(exists("NewGizmo") != 4)
1086  abort "Gizmo XOP must be installed."
1087  endif
1088  if (WaveDims(data) != 3)
1089  abort "ad_display_brick: data must be three-dimensional."
1090  endif
1091 
1092  dfref savedf = GetDataFolderDFR()
1093  dfref datadf = GetWavesDataFolderDFR(data)
1094  string s_datadf = GetDataFolder(1, datadf)
1095  dfref viewdf = make_view_folder(data)
1096 
1097  setdatafolder viewdf
1098  string dfname = ReplaceString("root:", s_datadf, "")
1099  string graphtitle = dfname + " Gizmo"
1100  string /g gizmo_graphname = graphname_from_dfref(datadf, "giz_")
1101  svar graphname = gizmo_graphname
1102 
1103  if ((strlen(graphname) > 0) && (wintype(graphname) == 13))
1104  setdatafolder savedf
1105  return graphname// gizmo window exists
1106  endif
1107 
1108  variable nx = dimsize(data, 0)
1109  variable ny = dimsize(data, 1)
1110  variable nz = dimsize(data, 2)
1111 
1112  variable pp
1113  string obj
1114  string cmd
1115 
1116  // igor does not allow calling gizmo functions directly
1117  setdatafolder datadf
1118  sprintf cmd, "NewGizmo /k=1 /n=%s /w=(100,100,500,400) /t=\"%s\"", graphname, graphtitle
1119  execute /q cmd
1120  cmd = "AppendToGizmo /D Axes=BoxAxes, name=axes0"
1121  execute /q cmd
1122 
1123  obj = "surface_xmid"
1124  pp = round(nx / 2 - 1)
1125  sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj
1126  execute /q cmd
1127  sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 128}", obj
1128  execute /q cmd
1129  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp
1130  execute /q cmd
1131  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj
1132  execute /q cmd
1133  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj
1134  execute /q cmd
1135  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj
1136  execute /q cmd
1137 
1138  obj = "surface_ymid"
1139  pp = round(ny / 2 - 1)
1140  sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj
1141  execute /q cmd
1142  sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 64}", obj
1143  execute /q cmd
1144  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp
1145  execute /q cmd
1146  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj
1147  execute /q cmd
1148  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj
1149  execute /q cmd
1150  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj
1151  execute /q cmd
1152 
1153  obj = "surface_zmid"
1154  pp = round(nz / 2 - 1)
1155  sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj
1156  execute /q cmd
1157  sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 32}", obj
1158  execute /q cmd
1159  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp
1160  execute /q cmd
1161  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj
1162  execute /q cmd
1163  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj
1164  execute /q cmd
1165  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj
1166  execute /q cmd
1167 
1168  obj = "axes0"
1169  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={-1,axisScalingMode,1}", obj
1170  execute /q cmd
1171  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={-1,axisColor,0,0,0,1}", obj
1172  execute /q cmd
1173  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={0,ticks,3}", obj
1174  execute /q cmd
1175  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={1,ticks,3}", obj
1176  execute /q cmd
1177  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={2,ticks,3}", obj
1178  execute /q cmd
1179  sprintf cmd, "ModifyGizmo modifyObject=%s property={Clipped,0}", obj
1180  execute /q cmd
1181  sprintf cmd, "ModifyGizmo modifyObject=%s property={-1,fontScaleFactor,2}", obj
1182  execute /q cmd
1183 
1184  sprintf cmd, "ModifyGizmo showAxisCue=1"
1185  execute /q cmd
1186 
1187  setdatafolder savedf
1188  return graphname
1189 };
1190 
1197 variable ad_brick_slicer(wave data){
1198  wave data
1199 
1200  // data folders and references
1201  dfref savedf = GetDataFolderDFR()
1202  dfref datadf = GetWavesDataFolderDFR(data)
1203  string s_datadf = GetDataFolder(1, datadf)
1204  dfref viewdf = make_view_folder(data)
1205 
1206  setdatafolder viewdf
1207  svar /z ex_panel = slicer_panelname
1208  if (svar_exists(ex_panel))
1209  string panels = WinList("SlicerPanel*", ";", "WIN:64")
1210  if (WhichListItem(ex_panel, panels, ";") >= 0)
1211  dowindow /f $(StringFromList(0, panels, ";"))
1212  return 0
1213  endif
1214  endif
1215 
1216  variable /g x_slice_pos
1217  variable /g y_slice_pos
1218  variable /g z_slice_pos
1219  variable /g slab_thickness
1220  string /g brick_path = getwavesdatafolder(data, 2)
1221  variable /g x_autoinc = 0
1222  variable /g y_autoinc = 0
1223  variable /g z_autoinc = 0
1224 
1225  // axis labels
1226  string labels = note(data)
1227  string xlabel = StringByKey("AxisLabelX", labels, "=", "\r")
1228  if (!strlen(xlabel))
1229  xlabel = "X"
1230  endif
1231  string ylabel = StringByKey("AxisLabelY", labels, "=", "\r")
1232  if (!strlen(ylabel))
1233  ylabel = "Y"
1234  endif
1235  string zlabel = StringByKey("AxisLabelZ", labels, "=", "\r")
1236  if (!strlen(zlabel))
1237  zlabel = "Z"
1238  endif
1239  string dlabel = StringByKey("Dataset", labels, "=", "\r")
1240  if (!strlen(dlabel))
1241  dlabel = NameOfWave(data)
1242  endif
1243 
1244  // this section copied from slicer panel
1245  NewPanel /k=1 /W=(500,600,890,940) /N=SlicerPanel as "Brick Slicer"
1246  string /g slicer_panelname = S_name
1247  string panel = s_name
1248 
1249  GroupBox g_xslice win=$panel,pos={8,8},size={376,96},title=xlabel
1250  Slider sl_xslice_position win=$panel,pos={16,32},size={240,56},proc=PearlAreaDisplay#slp_slice_position
1251  Slider sl_xslice_position win=$panel,limits={0,100,1},variable=x_slice_pos,vert= 0
1252  SetVariable sv_xslice_position win=$panel,pos={20,80},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="X"
1253  SetVariable sv_xslice_position win=$panel,limits={0,100,1},value=x_slice_pos
1254  Button b_xslice_center win=$panel,pos={122,80},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618"
1255  Button b_xslice_center win=$panel,help={"reset to center position"}
1256  Button b_xslice_extract win=$panel,pos={288,80},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice"
1257  Button b_xslice_extract win=$panel,help={"extract this slice to a separate wave"}
1258  //CheckBox cb_xslab_active win=$panel,pos={288,80},size={80,16},title="Display X Slab"
1259  //CheckBox cb_xslab_active win=$panel,value= 0
1260  TitleBox tb_xslice_animation win=$panel,pos={288,32},size={356,16},title="animation",frame=0
1261  TitleBox tb_xslice_animation win=$panel,anchor= MC
1262  Button b_xslice_back win=$panel,pos={288,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646"
1263  Button b_xslice_back win=$panel,help={"animate backwards"}
1264  Button b_xslice_forward win=$panel,pos={312,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649"
1265  Button b_xslice_forward win=$panel,help={"animate forward"}
1266  Button b_xslice_stop win=$panel,pos={336,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
1267  Button b_xslice_stop win=$panel,help={"stop animation"}
1268 
1269  GroupBox g_yslice win=$panel,pos={8,108},size={376,96},title=ylabel
1270  Slider sl_yslice_position win=$panel,pos={16,132},size={240,56},proc=PearlAreaDisplay#slp_slice_position
1271  Slider sl_yslice_position win=$panel,limits={0,100,1},variable=y_slice_pos,vert= 0
1272  SetVariable sv_yslice_position win=$panel,pos={20,180},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Y"
1273  SetVariable sv_yslice_position win=$panel,limits={0,100,1},value=y_slice_pos
1274  Button b_yslice_center win=$panel,pos={122,180},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618"
1275  Button b_yslice_center win=$panel,help={"reset to center position"}
1276  Button b_yslice_extract win=$panel,pos={288,180},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice"
1277  Button b_yslice_extract win=$panel,help={"extract this slice to a separate wave"}
1278  //CheckBox cb_yslab_active win=$panel,pos={288,180},size={80,16},title="Display Y Slab"
1279  //CheckBox cb_yslab_active win=$panel,value= 0
1280  TitleBox tb_yslice_animation win=$panel,pos={288,132},size={356,16},title="animation",frame=0
1281  TitleBox tb_yslice_animation win=$panel,anchor= MC
1282  Button b_yslice_back win=$panel,pos={288,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646"
1283  Button b_yslice_back win=$panel,help={"animate backwards"}
1284  Button b_yslice_forward win=$panel,pos={312,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649"
1285  Button b_yslice_forward win=$panel,help={"animate forward"}
1286  Button b_yslice_stop win=$panel,pos={336,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
1287  Button b_yslice_stop win=$panel,help={"stop animation"}
1288 
1289  GroupBox g_zslice win=$panel,pos={8,208},size={376,96},title=zlabel
1290  Slider sl_zslice_position win=$panel,pos={16,232},size={240,56},proc=PearlAreaDisplay#slp_slice_position
1291  Slider sl_zslice_position win=$panel,limits={0,100,1},variable=z_slice_pos,vert= 0
1292  SetVariable sv_zslice_position win=$panel,pos={20,280},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Z"
1293  SetVariable sv_zslice_position win=$panel,limits={0,100,1},value=z_slice_pos
1294  Button b_zslice_center win=$panel,pos={122,280},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618"
1295  Button b_zslice_center win=$panel,help={"reset to center position"}
1296  Button b_zslice_extract win=$panel,pos={288,280},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice"
1297  Button b_zslice_extract win=$panel,help={"extract this slice to a separate wave"}
1298  //CheckBox cb_zslab_active win=$panel,pos={288,280},size={80,16},title="Display Z Slab"
1299  //CheckBox cb_zslab_active win=$panel,value= 0
1300  TitleBox tb_zslice_animation win=$panel,pos={288,232},size={356,16},title="animation",frame=0
1301  TitleBox tb_zslice_animation win=$panel,anchor= MC
1302  Button b_zslice_back win=$panel,pos={288,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646"
1303  Button b_zslice_back win=$panel,help={"animate backwards"}
1304  Button b_zslice_forward win=$panel,pos={312,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649"
1305  Button b_zslice_forward win=$panel,help={"animate forward"}
1306  Button b_zslice_stop win=$panel,pos={336,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
1307  Button b_zslice_stop win=$panel,help={"stop animation"}
1308 
1309  TitleBox t_slicerpath win=$panel,pos={8,316},size={128,20},disable=2,title=dlabel
1310  //SetVariable setvar0 win=$panel,pos={240,316},size={120,16},title="slab thickness"
1311  //SetVariable setvar0 win=$panel,limits={1,inf,1},value=slab_thickness
1312 
1313  // update control limits and move slicing planes to the center
1314  setwindow $panel, userdata(control_datafolder) = GetDataFolder(1, viewdf)
1315  setwindow $panel, userdata(brick_path) = brick_path
1317  x_slice_pos = dimoffset(data, 0) + dimsize(data, 0) * dimdelta(data, 0) / 2
1318  y_slice_pos = dimoffset(data, 1) + dimsize(data, 1) * dimdelta(data, 1) / 2
1319  z_slice_pos = dimoffset(data, 2) + dimsize(data, 2) * dimdelta(data, 2) / 2
1320 
1321  svar /z /sdfr=viewdf gizmo_graphname
1322  if (svar_exists(gizmo_graphname) && (strlen(gizmo_graphname) > 0) && (wintype(gizmo_graphname) == 13))
1323  ad_gizmo_set_plane(data, 0, x_slice_pos)
1324  ad_gizmo_set_plane(data, 1, y_slice_pos)
1325  ad_gizmo_set_plane(data, 2, z_slice_pos)
1326  endif
1327  svar /z /sdfr=viewdf slice_graphname
1328  if (svar_exists(slice_graphname) && (strlen(slice_graphname) > 0) && (wintype(slice_graphname) == 1))
1329  ad_profiles_set_slice(data, 2, z_slice_pos)
1330  endif
1331 
1333  setdatafolder savedf
1334 };
1335 
1345 string ad_display_slice(wave data){
1346  wave data
1347 
1348  if (WaveDims(data) != 3)
1349  abort "ad_display_slice: data must be three-dimensional."
1350  endif
1351 
1352  dfref savedf = GetDataFolderDFR()
1353  dfref datadf = GetWavesDataFolderDFR(data)
1354  string s_datadf = GetDataFolder(1, datadf)
1355  dfref viewdf = make_view_folder(data)
1356 
1357  setdatafolder viewdf
1358  string dfname = ReplaceString("root:", s_datadf, "")
1359  dfname = dfname[0, strlen(dfname) - 2]
1360  string graphtitle = dfname + " Slice"
1361 
1362  if (exists("slice_graphname") != 2)
1363  string /g slice_graphname = ""
1364  endif
1365  string /g slice_wavename = CleanupName("slice_" + NameOfWave(data), 0)
1366  svar graphname = slice_graphname
1367  svar slicename = slice_wavename
1368 
1369  make /n=(1,1)/o $slicename
1370  wave slice = $slicename
1371  if ((strlen(graphname) == 0) || (wintype(graphname) != 1))
1372  graphname = ad_display_profiles(slice)
1373  endif
1374  variable z_slice_pos = dimoffset(data, 2) + dimsize(data, 2) * dimdelta(data, 2) / 2
1375  ad_profiles_set_slice(data, 2, z_slice_pos)
1376  ad_profiles_set_cursor(slice, "A", -inf, -inf, pscale=1)
1377  ad_profiles_set_cursor(slice, "B", +inf, +inf, pscale=1)
1378 
1379  setdatafolder savedf
1380  return graphname
1381 };
1382 
1386 static variable update_slice_info(){
1387  dfref savedf = GetDataFolderDFR()
1388 
1389  svar brick_path
1390  //svar slicer_panelname
1391  wave brick = $brick_path
1392 
1393  //dowindow /F $slicer_panelname
1394  variable lo, hi, inc
1395  lo = dimoffset(brick, 0)
1396  inc = dimdelta(brick, 0)
1397  hi = lo + inc * (dimsize(brick, 0) - 1)
1398  Slider sl_xslice_position,limits={lo,hi,inc}
1399  SetVariable sv_xslice_position,limits={lo,hi,inc}
1400  lo = dimoffset(brick, 1)
1401  inc = dimdelta(brick, 1)
1402  hi = lo + inc * (dimsize(brick, 1) - 1)
1403  Slider sl_yslice_position,limits={lo,hi,inc}
1404  SetVariable sv_yslice_position,limits={lo,hi,inc}
1405  lo = dimoffset(brick, 2)
1406  inc = dimdelta(brick, 2)
1407  hi = lo + inc * (dimsize(brick, 2) - 1)
1408  Slider sl_zslice_position,limits={lo,hi,inc}
1409  SetVariable sv_zslice_position,limits={lo,hi,inc}
1410 
1411  setdatafolder savedf
1412 };
1413 
1422 variable ad_gizmo_set_plane(wave brick, variable dim, variable value){
1423  wave brick
1424  variable dim
1425  variable value
1426 
1427  dfref savedf = GetDataFolderDFR()
1428  dfref datadf = GetWavesDataFolderDFR(brick)
1429  dfref viewdf = get_view_folder(brick)
1430  svar /z /sdfr=viewdf graphname=gizmo_graphname
1431 
1432  variable pp = round((value - dimoffset(brick, dim)) / dimdelta(brick, dim))
1433  if ((pp < 0) || (pp >= dimsize(brick, dim)))
1434  return -1// requested value out of range
1435  endif
1436 
1437  if (svar_exists(graphname) && (strlen(graphname) > 0) && (wintype(graphname) == 13))
1438  string axes = "xyz"
1439  string obj = "surface_" + axes[dim] + "mid"
1440  string cmd
1441  sprintf cmd, "ModifyGizmo /N=%s ModifyObject=%s, property={plane, %d}", graphname, obj, pp
1442  execute /q cmd
1443  else
1444  return -2// gizmo window not found
1445  endif
1446 
1447  return 0
1448 };
1449 
1458 variable ad_profiles_set_slice(wave brick, variable dim, variable value){
1459  wave brick
1460  variable dim
1461  variable value
1462 
1463  dfref savedf = GetDataFolderDFR()
1464  dfref datadf = GetWavesDataFolderDFR(brick)
1465  dfref viewdf = get_view_folder(brick)
1466  svar /z /sdfr=viewdf graphname = slice_graphname
1467  svar /z /sdfr=viewdf slicename = slice_wavename
1468 
1469  variable pp = round((value - dimoffset(brick, dim)) / dimdelta(brick, dim))
1470  if ((pp < 0) || (pp >= dimsize(brick, dim)))
1471  return -1// requested value out of range
1472  endif
1473 
1474  if (svar_exists(graphname) && (strlen(graphname) > 0) && (wintype(graphname) == 1))
1475  setdatafolder viewdf
1476  switch(dim)
1477  case 0:// X
1478  wave wdest = ad_extract_slab_x(brick, pp, pp, slicename)
1479  ad_update_profiles(wdest)
1480  break
1481  case 1:// Y
1482  wave wdest = ad_extract_slab_y(brick, pp, pp, slicename)
1483  ad_update_profiles(wdest)
1484  break
1485  case 2:// Z
1486  wave wdest = ad_extract_slab_z(brick, pp, pp, slicename)
1487  ad_update_profiles(wdest)
1488  break
1489  endswitch
1490  else
1491  return -2// graph window not found
1492  endif
1493 
1494  setdatafolder savedf
1495  return 0
1496 };
1497 
1498 static variable slp_slice_position(WMSliderAction* sa){
1499  STRUCT WMSliderAction &sa
1500 
1501  dfref savedf = GetDataFolderDFR()
1502 
1503  switch( sa.eventCode )
1504  case -1:// control being killed
1505  break
1506  default:
1507  if( sa.eventCode & 1 )// value set
1508  string control_datafolder = GetUserData(sa.win, "", "control_datafolder")
1509  setdatafolder control_datafolder
1510  string brick_path = GetUserData(sa.win, "", "brick_path")
1511  wave brick = $brick_path
1512 
1513  string axis = StringFromList(1, sa.ctrlName, "_")
1514  variable dim = char2num(axis[0]) - char2num("x")
1515  ad_gizmo_set_plane(brick, dim, sa.curval)
1516  ad_profiles_set_slice(brick, dim, sa.curval)
1517  endif
1518  break
1519  endswitch
1520 
1521  setdatafolder savedf
1522  return 0
1523 };
1524 
1526 static variable svp_slice_position(WMSetVariableAction* sva){
1527  STRUCT WMSetVariableAction &sva
1528 
1529  dfref savedf = GetDataFolderDFR()
1530 
1531  switch( sva.eventCode )
1532  case 1:// mouse up
1533  case 2:// Enter key
1534  case 3:// Live update
1535  string control_datafolder = GetUserData(sva.win, "", "control_datafolder")
1536  setdatafolder control_datafolder
1537  string brick_path = GetUserData(sva.win, "", "brick_path")
1538  wave brick = $brick_path
1539 
1540  string axis = StringFromList(1, sva.ctrlName, "_")
1541  variable dim = char2num(axis[0]) - char2num("x")
1542  ad_gizmo_set_plane(brick, dim, sva.dval)
1543  ad_profiles_set_slice(brick, dim, sva.dval)
1544  break
1545  case -1:// control being killed
1546  break
1547  endswitch
1548 
1549  setdatafolder savedf
1550  return 0
1551 };
1552 
1554 static variable bp_move_slice(WMButtonAction* ba){
1555  STRUCT WMButtonAction &ba
1556 
1557  dfref savedf = GetDataFolderDFR()
1558 
1559  switch( ba.eventCode )
1560  case 2:// mouse up
1561  string control_datafolder = GetUserData(ba.win, "", "control_datafolder")
1562  setdatafolder control_datafolder
1563  string brick_path = GetUserData(ba.win, "", "brick_path")
1564  wave brick = $brick_path
1565 
1566  string axis = StringFromList(1, ba.ctrlName, "_")
1567  string cmd = StringFromList(2, ba.ctrlName, "_")
1568  variable dim = char2num(axis[0]) - char2num("x")
1569  string posvariable = getdatafolder(1) + axis[0] + "_slice_pos"
1570 
1571  nvar pos = $(posvariable)
1572  strswitch (cmd)
1573  case "forward":
1574  ad_slicer_start_bg(brick, dim, posvariable, dimdelta(brick, dim))
1575  break
1576  case "back":
1577  ad_slicer_start_bg(brick, dim, posvariable, -dimdelta(brick, dim))
1578  break
1579  case "center":
1580  ad_slicer_stop_bg(posvariable)
1581  bp_move_slice_center(brick, dim, posvariable)
1582  break
1583  case "stop":
1584  ad_slicer_stop_bg(posvariable)
1585  break
1586  endswitch
1587  break
1588  case -1:// control being killed
1589  break
1590  endswitch
1591 
1592  setdatafolder savedf
1593  return 0
1594 };
1595 
1599 static variable bp_extract_slice(WMButtonAction* ba){
1600  STRUCT WMButtonAction &ba
1601 
1602  dfref savedf = GetDataFolderDFR()
1603 
1604  switch( ba.eventCode )
1605  case 2:// mouse up
1606  string control_datafolder = GetUserData(ba.win, "", "control_datafolder")
1607  setdatafolder control_datafolder
1608  string brick_path = GetUserData(ba.win, "", "brick_path")
1609  wave brick = $brick_path
1610  dfref brickdf = GetWavesDataFolderDFR(brick)
1611 
1612  string axis = StringFromList(1, ba.ctrlName, "_")
1613  string cmd = StringFromList(2, ba.ctrlName, "_")
1614  variable dim = char2num(axis[0]) - char2num("x")
1615  string posvariable = getdatafolder(1) + axis[0] + "_slice_pos"
1616 
1617  nvar pos = $(posvariable)
1618  variable pp = round((pos - dimoffset(brick, dim)) / dimdelta(brick, dim))
1619  if ((pp < 0) || (pp >= dimsize(brick, dim)))
1620  return -1// requested value out of range
1621  endif
1622 
1623  variable dig = ceil(log(dimsize(brick, dim)))
1624  string slicename
1625  sprintf slicename, "%s_%s%0*u", NameOfWave(brick), axis[0], dig, pp
1626  setdatafolder brickdf
1627  switch(dim)
1628  case 0:// X
1629  wave wdest = ad_extract_slab_x(brick, pp, pp, slicename)
1630  break
1631  case 1:// Y
1632  wave wdest = ad_extract_slab_y(brick, pp, pp, slicename)
1633  break
1634  case 2:// Z
1635  wave wdest = ad_extract_slab_z(brick, pp, pp, slicename)
1636  break
1637  endswitch
1638 
1639  string msg
1640  sprintf msg, "%s=%g", axis[0], pos
1641  note wdest, msg
1642 
1643  break
1644  case -1:// control being killed
1645  break
1646  endswitch
1647 
1648  setdatafolder savedf
1649  return 0
1650 };
1651 
1653 static variable bp_move_slice_center(wave brick, variable dim, string posvariable){
1654  wave brick
1655  variable dim
1656  string posvariable
1657 
1658  nvar pos = $posvariable
1659  pos = dimoffset(brick, dim) + dimdelta(brick, dim) * dimsize(brick, dim) / 2
1660  ad_gizmo_set_plane(brick, dim, pos)
1661  ad_profiles_set_slice(brick, dim, pos)
1662 };
1663 
1665 static variable ad_slicer_move_bg(WMBackgroundStruct* s){
1666  STRUCT WMBackgroundStruct &s
1667 
1668  dfref savedf = GetDataFolderDFR()
1669  setdatafolder root:pearl_area:slicer
1670  wave /t bg_brickpaths
1671  wave /t bg_graphnames
1672  wave /t bg_variablepaths
1673  wave bg_dimensions
1674  wave bg_increments
1675 
1676  variable ii
1677  variable nn = numpnts(bg_brickpaths)
1678  variable dim
1679  variable pp
1680 
1681  for (ii = 0; ii < nn; ii += 1)
1682  wave /z brick = $bg_brickpaths[ii]
1683  nvar /z pos = $bg_variablepaths[ii]
1684  dim = bg_dimensions[0]
1685  pos += bg_increments[ii]
1686  // wrap around at limits
1687  pp = round((pos - dimoffset(brick, dim)) / dimdelta(brick, dim))
1688  if (pp <= -0.5)
1689  pos = dimoffset(brick, dim) + dimdelta(brick, dim) * (dimsize(brick, dim) - 1)
1690  else if (pp >= dimsize(brick, dim) - 0.5)
1691  pos = dimoffset(brick, dim)
1692  endif
1693  if (waveexists(brick))
1694  ad_gizmo_set_plane(brick, dim, pos)
1695  ad_profiles_set_slice(brick, dim, pos)
1696  endif
1697  endfor
1698 
1699  setdatafolder savedf
1700  return 0
1701 };
1702 
1705  dfref savedf = GetDataFolderDFR()
1706  setdatafolder root:
1707  newdatafolder /o/s pearl_area
1708  newdatafolder /o/s slicer
1709 
1710  make /n=0/o/t bg_brickpaths
1711  make /n=0/o/t bg_variablepaths
1712  make /n=0/o/i/u bg_dimensions
1713  make /n=0/o bg_increments
1714 
1715  CtrlNamedBackground ad_slicer, period = 30, proc = PearlAreaDisplay#ad_slicer_move_bg
1716 
1717  setdatafolder savedf
1718  return 0
1719 };
1720 
1728 variable ad_slicer_start_bg(wave brick, variable dimension, string posvariable, variable delta){
1729  wave brick// 3D data wave
1730  variable dimension// dimension to animate, 0, 1, or 2
1731  string posvariable// full path to the global position variable
1732  variable delta// step increment, should be +/- dimdelta
1733 
1734  dfref savedf = GetDataFolderDFR()
1735  setdatafolder root:pearl_area:slicer
1736  wave /t bg_brickpaths
1737  wave /t bg_variablepaths
1738  wave bg_dimensions
1739  wave bg_increments
1740 
1741  // create entry in ad_slicer background task table
1742  variable idx
1743  FindValue /TEXT=posvariable /TXOP=4 /Z bg_variablepaths
1744  if (v_value >= 0)
1745  idx = v_value
1746  else
1747  idx = numpnts(bg_variablepaths)
1748  InsertPoints idx, 1, bg_brickpaths, bg_variablepaths, bg_dimensions, bg_increments
1749  endif
1750 
1751  // set background task
1752  bg_brickpaths[idx] = GetWavesDataFolder(brick, 2)
1753  bg_variablepaths[idx] = posvariable
1754  bg_dimensions[idx] = dimension
1755  bg_increments[idx] = delta
1756 
1757  // start background task
1758  if (numpnts(bg_variablepaths) > 0)
1759  CtrlNamedBackground ad_slicer, start
1760  endif
1761 
1762  setdatafolder savedf
1763  return 0
1764 };
1765 
1770 variable ad_slicer_stop_bg(string posvariable){
1771  string posvariable
1772 
1773  dfref savedf = GetDataFolderDFR()
1774  setdatafolder root:pearl_area:slicer
1775  wave /t bg_brickpaths
1776  wave /t bg_variablepaths
1777  wave bg_dimensions
1778  wave bg_increments
1779 
1780  // find entry in ad_slicer background task table
1781  FindValue /TEXT=posvariable /TXOP=4 /Z bg_variablepaths
1782  if (v_value >= 0)
1783  DeletePoints v_value, 1, bg_brickpaths, bg_variablepaths, bg_dimensions, bg_increments
1784  endif
1785 
1786  // stop background task if task table is empty
1787  if (numpnts(bg_variablepaths) == 0)
1788  CtrlNamedBackground ad_slicer, stop
1789  endif
1790 
1791  setdatafolder savedf
1792  return 0
1793 };
1794 
threadsafe wave ad_extract_slab_x(wave dataset, variable p1, variable p2, string destname, variable noavg=defaultValue)
+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 = PearlAreaDisplay
4 #pragma version = 1.04
5 
19 // 3D data is handled by 3 windows. they don't have to be visible all at the same time.
48 
54 
56 static string graphname_from_dfref(dfref df, string prefix){
57  dfref df
58  string prefix
59 
60  string name
61 
62  name = GetDataFolder(1, df)
63  name = ReplaceString("root:", name, "")
64  name = name[0, strlen(name) - 2]
65  name = ReplaceString(" ", name, "")
66  name = CleanupName(prefix + name, 0)
67  if (CheckName(name, 6))
68  name = UniqueName(name, 6, 0)
69  endif
70 
71  return name
72 };
73 
84 string ad_display(wave image){
85  wave image// wave which contains the image data from the detector
86  // returns the name of the graph window
87 
88  dfref savedf = GetDataFolderDFR()
89  dfref imagedf = GetWavesDataFolderDFR(image)
90  setdatafolder imagedf
91 
92  string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
93  string graphtitle = dfname + " View"
94  string /g view_graphname = graphname_from_dfref(imagedf, "view_")
95  svar graphname = view_graphname
96  display /k=1/n=$graphname as graphtitle
97  graphname = s_name
98  appendimage /w=$graphname image
99 
100  setdatafolder savedf
101  return graphname
102 };
103 
114 string ad_display_histogram(wave image){
115  wave image
116 
117  dfref savedf = GetDataFolderDFR()
118  dfref imagedf = GetWavesDataFolderDFR(image)
119  string s_imagedf = GetDataFolder(1, imagedf)
120  setdatafolder imagedf
121 
122  make /n=(1)/o hist// histogram
123 
124  string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
125  string graphtitle = dfname + " Histogram"
126  string /g hist_graphname = graphname_from_dfref(imagedf, "hist_")
127  svar graphname = hist_graphname
128  display /k=1/n=$graphname as graphtitle
129  graphname = s_name
130  appendtograph /w=$graphname hist
131 
132  ModifyGraph /w=$graphname rgb(hist)=(39168,0,0)
133  ModifyGraph /w=$graphname mode=6
134  ModifyGraph /w=$graphname mirror=1
135  ModifyGraph /w=$graphname minor=1
136  ModifyGraph /w=$graphname axThick=0.5
137  ModifyGraph /w=$graphname lblPosMode=1,lblPos=30,lblMargin=0
138  ModifyGraph /w=$graphname btLen=4
139  ModifyGraph /w=$graphname margin(left)=45,margin(bottom)=35,margin(top)=10,margin(right)=10
140  ModifyGraph /w=$graphname gfSize=10
141  Label /w=$graphname bottom "value"
142  Label /w=$graphname left "# pixels"
143 
144  ad_calc_histogram(image)
145 
146  setdatafolder savedf
147  return graphname
148 };
149 
165 string ad_display_profiles(wave image, string filter = defaultValue){
166  wave image
167  string filter
168  variable show_legend = 0// currently not supported
169 
170  if (WaveDims(image) != 2)
171  abort "ad_display_profiles: image wave must be two-dimensional."
172  endif
173  if (ParamIsDefault(filter))
174  filter = "ad_box_filter"
175  endif
176 
177  // data folders and references
178  dfref savedf = GetDataFolderDFR()
179  dfref imagedf = GetWavesDataFolderDFR(image)
180  string s_imagedf = GetDataFolder(1, imagedf)
181  setdatafolder imagedf
182  string s_viewdf = CleanupName("view_" + NameOfWave(image), 0)
183  newdatafolder /o/s $s_viewdf
184  dfref viewdf = GetDataFolderDFR()
185  s_viewdf = GetDataFolder(1, viewdf)
186 
187  // data structures
188  string /g sourcepath = GetWavesDataFolder(image, 2)
189  string viewname = "view_image"
190  duplicate /o image, $viewname /wave=view
191  make /n=(3,3)/o xprofiles// NX x 3 wave with 3 one-dimensional profiles along Y dimension
192  make /n=(3,3)/o yprofiles// NY x 3 wave with 3 one-dimensional profiles along X dimension
193  string /g view_filter
194  string /g view_filter_options
195  view_filter = filter
196  view_filter_options = ""
197  variable /g view_filter_smoothing_x = 1
198  variable /g view_filter_smoothing_y = 1
199  variable /g view_cursor_mode = 0
200  string dfname = ReplaceString("root:", GetDataFolder(1, imagedf), "")
201  string graphtitle = dfname + NameOfWave(image) + " Profiles"
202  string /g prof_graphname = graphname_from_dfref(imagedf, "prof_")
203  svar graphname = prof_graphname
204  variable /g graph_avg// average value in ROI (ROI is defined by the crosshairs A and B)
205  variable /g graph_min// minimum value in ROI
206  variable /g graph_max// maximum value in ROI
207  variable /g graph_sum// sum of all values in ROI
208  variable /g graph_sdev// standard deviation of all values in ROI
209 
210  // graph setup
211  display /k=1 /n=$graphname /w=(100,100,500,400) as graphtitle
212  graphname = s_name
213  AppendToGraph /w=$graphname /L=xprofiles xprofiles[*][0],xprofiles[*][1],xprofiles[*][2]
214  AppendToGraph /w=$graphname /VERT/B=yprofiles yprofiles[*][0],yprofiles[*][1],yprofiles[*][2]
215  AppendImage /w=$graphname view
216  string imgname = StringFromList(0, ImageNameList(graphname, ";"))
217  ModifyImage /w=$graphname $imgname ctab= {*,*,BlueGreenOrange,0}
218  ModifyGraph /w=$graphname rgb(xprofiles)=(39168,0,0),rgb(yprofiles)=(39168,0,0)
219  ModifyGraph /w=$graphname rgb(xprofiles#1)=(0,26112,0),rgb(yprofiles#1)=(0,26112,0)
220  ModifyGraph /w=$graphname rgb(xprofiles#2)=(0,9472,39168),rgb(yprofiles#2)=(0,9472,39168)
221  ModifyGraph /w=$graphname mirror(xprofiles)=2,mirror(bottom)=3,mirror(yprofiles)=2,mirror(left)=3
222  ModifyGraph /w=$graphname nticks=3
223  ModifyGraph /w=$graphname minor=1
224  ModifyGraph /w=$graphname axThick=0.5
225  ModifyGraph /w=$graphname lblPosMode=1,lblPos=30,lblMargin=0
226  ModifyGraph /w=$graphname btLen=4
227  ModifyGraph /w=$graphname freePos(xprofiles)=0
228  ModifyGraph /w=$graphname freePos(yprofiles)=0
229  ModifyGraph /w=$graphname axisEnab(xprofiles)={0.64,1}
230  ModifyGraph /w=$graphname axisEnab(bottom)={0,0.6}
231  ModifyGraph /w=$graphname axisEnab(yprofiles)={0.64,1}
232  ModifyGraph /w=$graphname axisEnab(left)={0,0.6}
233  ModifyGraph /w=$graphname zero(left)=8
234  ModifyGraph /w=$graphname margin(left)=40,margin(bottom)=30,margin(top)=20,margin(right)=40
235  ModifyGraph /w=$graphname gfSize=10
236 
237  // axis labels
238  string labels = note(image)
239  string lab
240  lab = StringByKey("AxisLabelX", labels, "=", "\r")
241  if (!strlen(lab))
242  lab = "X"
243  endif
244  Label /w=$graphname bottom lab + " (\\U)"
245  lab = StringByKey("AxisLabelY", labels, "=", "\r")
246  if (!strlen(lab))
247  lab = "Y"
248  endif
249  Label /w=$graphname left lab + " (\\U)"
250  lab = StringByKey("AxisLabelD", labels, "=", "\r")
251  if (!strlen(lab))
252  lab = "value"
253  endif
254  Label /w=$graphname xprofiles lab + " (\\U)"
255  Label /w=$graphname yprofiles lab + " (\\U)"
256 
257  // legend
258  if (show_legend)
259  Legend /w=$graphname/C/N=text0/J/F=2/D=0.5/T={28}/A=RT/X=0.00/Y=0.00 "\\s(xprofiles)\tprofile A"
260  AppendText /w=$graphname "\\s(xprofiles#1)\tprofile B"
261  AppendText /w=$graphname "\\s(xprofiles#2)\tROI average"
262  AppendText /w=$graphname "min\t\\{" + s_viewdf + "graph_min}"
263  AppendText /w=$graphname "max\t\\{" + s_viewdf + "graph_max}"
264  AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
265  AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
266  AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
267  else
268  TextBox /w=$graphname /C/N=text0 /F=0 /B=1 /X=1.00 /Y=1.00
269  lab = StringByKey("Dataset", labels, "=", "\r")
270  if (strlen(lab))
271  AppendText /w=$graphname lab
272  endif
273  AppendText /w=$graphname "sum\t\\{" + s_viewdf + "graph_sum}"
274  AppendText /w=$graphname "avg\t\\{" + s_viewdf + "graph_avg}"
275  AppendText /w=$graphname "sdev\t\\{" + s_viewdf + "graph_sdev}"
276  endif
277 
278  // interactive elements
279  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A $imgname 0,0
280  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B $imgname DimSize(view, 0)-1, DimSize(view, 1)-1
281  variable pcurs
282  pcurs = floor(DimSize(xprofiles, 0) / 3)
283  Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs
284  pcurs = floor(DimSize(xprofiles, 0) * 2 / 3)
285  Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs
286  pcurs = floor(DimSize(yprofiles, 0) / 3)
287  Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs
288  pcurs = floor(DimSize(yprofiles, 0) * 2 / 3)
289  Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs
290  ShowInfo /w=$graphname /CP=0
291 
292  SetWindow $graphname, hook(ad_profiles_hook)=ad_profiles_hook
293  ControlBar /w=$graphname 21
294  Button b_reset_cursors win=$graphname, title="reset cursors",pos={0,0},size={70,20},proc=PearlAreaDisplay#bp_reset_cursors
295  Button b_reset_cursors win=$graphname, fColor=(65535,65535,65535),fSize=10
296 
297  SetVariable sv_smoothing_x win=$graphname, title="X smoothing",pos={130,2},bodyWidth=40
298  SetVariable sv_smoothing_x win=$graphname, value=view_filter_smoothing_x,limits={1,100,1}
299  SetVariable sv_smoothing_x win=$graphname, proc=PearlAreaDisplay#svp_smoothing
300  SetVariable sv_smooting_y win=$graphname, title="Y smoothing",pos={240,2},bodyWidth=40
301  SetVariable sv_smooting_y win=$graphname, value=view_filter_smoothing_y,limits={1,100,1}
302  SetVariable sv_smooting_y win=$graphname, proc=PearlAreaDisplay#svp_smoothing
303 
304  PopupMenu pm_export win=$graphname, mode=0,title="Export"
305  PopupMenu pm_export win=$graphname, value="X profile;Y profile;X profile (collate);Y profile (collate)"
306  PopupMenu pm_export win=$graphname, pos={308,0},bodyWidth=60,proc=PearlAreaDisplay#pmp_export
307  PopupMenu pm_export win=$graphname, help={"Export profile of selected area and display in graph. Collate mode = display all profiles in same graph."}
308 
309  // data processing
310  ad_update_profiles(image)
311 
312  setdatafolder savedf
313  return graphname
314 };
315 
321 variable ad_update_profiles(wave image){
322  wave image
323 
324  // data folders and references
325  dfref viewdf = get_view_folder(image)
326  if (DataFolderRefStatus(viewdf) == 0)
327  return -1// data folder not found
328  endif
329  dfref savedf = GetDataFolderDFR()
330  setdatafolder viewdf
331 
332  // data structures
333  string viewname = "view_image"
334  duplicate /o image, $viewname /wave=view
335 
336  // data processing
337  svar view_filter
338  svar view_filter_options
339  nvar smoothing_x = view_filter_smoothing_x
340  nvar smoothing_y = view_filter_smoothing_y
341  funcref ad_default_image_filter filterfunc = $view_filter
342  view_filter_options = ReplaceNumberByKey("SmoothingX", view_filter_options, smoothing_x, "=", ";")
343  view_filter_options = ReplaceNumberByKey("SmoothingY", view_filter_options, smoothing_y, "=", ";")
344  filterfunc(view, view_filter_options)
345 
347 
348  setdatafolder savedf
349  return 0
350 };
351 
368 variable ad_profiles_cursor_mode(wave image, variable mode){
369  wave image
370  variable mode
371 
372  dfref savedf = GetDataFolderDFR()
373  wave view_image = get_view_image(image)
374  dfref viewdf = GetWavesDataFolderDFR(view_image)
375  svar /sdfr=viewdf graphname = prof_graphname
376  nvar /sdfr=viewdf cursor_mode = view_cursor_mode
377  wave /sdfr=viewdf xprofiles, yprofiles
378 
379  variable dx = DimSize(view_image, 0)
380  variable dy = DimSize(view_image, 1)
381  switch(mode)
382  case 1:// background selection
383  Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 A view_image 0, 0
384  Cursor /w=$graphname /A=0 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1
385  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 C view_image round(0.2 * dx) -1, 0
386  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 D view_image round(0.8 * dx) -1, 0
387  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 E view_image round(0.4 * dx) -1, 0
388  Cursor /w=$graphname /A=0 /P /I /S=2 /H=2 /L=1 F view_image round(0.6 * dx) -1, 0
389 
390  ShowInfo /w=$graphname /CP=0
391  cursor_mode = mode
392  break
393  default:
394  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 A view_image 0,0
395  Cursor /w=$graphname /A=1 /P /I /S=2 /H=1 /L=1 B view_image dx-1, dy-1
396  variable pcurs
397  pcurs = floor(DimSize(xprofiles, 0) / 3)
398  Cursor /w=$graphname /A=0 /P /S=1 /H=0 C xprofiles#2 pcurs
399  pcurs = floor(DimSize(xprofiles, 0) * 2 / 3)
400  Cursor /w=$graphname /A=0 /P /S=1 /H=0 D xprofiles#2 pcurs
401  pcurs = floor(DimSize(yprofiles, 0) / 3)
402  Cursor /w=$graphname /A=0 /P /S=1 /H=0 E yprofiles#2 pcurs
403  pcurs = floor(DimSize(yprofiles, 0) * 2 / 3)
404  Cursor /w=$graphname /A=0 /P /S=1 /H=0 F yprofiles#2 pcurs
405  ShowInfo /w=$graphname /CP=0
406  cursor_mode = 0
407  endswitch
408 
409  setdatafolder savedf
410  return 0
411 };
412 
429 variable ad_profiles_set_cursor(wave image, string cursorname, variable xa, variable ya, variable pscale = defaultValue){
430  wave image
431  string cursorname
432  variable xa, ya
433  variable pscale
434 
435  if (ParamIsDefault(pscale))
436  pscale = 0
437  endif
438 
439  // data folders and references
440  dfref savedf = GetDataFolderDFR()
441  wave view_image = get_view_image(image)
442  dfref viewdf = GetWavesDataFolderDFR(view_image)
443  svar /sdfr=viewdf graphname = prof_graphname
444 
445  variable pa, qa
446  if (pscale)
447  pa = xa
448  qa = ya
449  else
450  pa = round((xa - DimOffset(view_image, 0)) / DimDelta(view_image, 0))
451  qa = round((ya - DimOffset(view_image, 1)) / DimDelta(view_image, 1))
452  endif
453 
454  pa = min(pa, DimSize(view_image, 0) - 1)
455  pa = max(pa, 0)
456  qa = min(qa, DimSize(view_image, 1) - 1)
457  qa = max(qa, 0)
458  Cursor /i /p /w=$graphname $cursorname view_image pa, qa
459 
460  setdatafolder savedf
461  return 0
462 };
463 
474 // the lines can be removed manually using the draw toolbox, or by calling this function with @c clean=1.
481 variable ad_profiles_crosshairs(wave image, variable clear = defaultValue){
482  wave image
483  variable clear
484 
485  if (ParamIsDefault(clear))
486  clear = 0
487  endif
488 
489  // data folders and references
490  wave view_image = get_view_image(image)
491  dfref viewdf = GetWavesDataFolderDFR(view_image)
492  svar /sdfr=viewdf graphname = prof_graphname
493 
494  string cursors = "A;B"
495  string colors = "39168,0,0;0,26112,0"
496  string color
497  variable ncursors
498  variable icursor
499  string cursorname
500  string groupname = "crosshairs"
501  variable xx, yy
502  struct RGBColor rgb
503 
504  if (clear == 0)
505  SetDrawEnv /W=$graphname push
506  DrawAction /w=$graphname getgroup=$groupname, delete, begininsert
507  SetDrawEnv /w=$graphname gstart, gname=$groupname
508 
509  SetDrawEnv /W=$graphname dash=4
510  SetDrawEnv /W=$graphname linethick=0.5
511 
512  ncursors = ItemsInList(cursors, ";")
513  for (icursor=0; icursor < ncursors; icursor += 1)
514  cursorname = StringFromList(icursor, cursors, ";")
515  color = StringFromList(icursor, colors, ";")
516  rgb.red = str2num(StringFromList(0, color, ","))
517  rgb.green = str2num(StringFromList(1, color, ","))
518  rgb.blue = str2num(StringFromList(2, color, ","))
519  if (strlen(CsrInfo($cursorname, graphname)) > 0)
520  xx = hcsr($cursorname, graphname)
521  yy = vcsr($cursorname, graphname)
522  SetDrawEnv /W=$graphname linefgc=(rgb.red, rgb.green, rgb.blue)
523  SetDrawEnv /W=$graphname save
524  SetDrawEnv /W=$graphname xcoord=bottom, ycoord=prel
525  DrawLine /W=$graphname xx, 0, xx, 1
526  SetDrawEnv /W=$graphname xcoord=prel, ycoord=left
527  DrawLine /W=$graphname 0, yy, 1, yy
528  endif
529  endfor
530 
531  SetDrawEnv /w=$graphname gstop
532  DrawAction /w=$graphname endinsert
533  SetDrawEnv /W=$graphname pop
534  SetDrawEnv /W=$graphname save
535  else
536  DrawAction /w=$graphname getgroup=$groupname, delete
537  endif
538 
539  return 0
540 };
541 
547 static wave get_source_image(wave view){
548  wave view// image wave displayed in a profiles window
549 
550  dfref viewdf = GetWavesDataFolderDFR(view)
551  svar /z /sdfr=viewdf sourcepath
552  if (svar_exists(sourcepath))
553  wave /z img = $sourcepath
554  else
555  wave /z img = $""
556  endif
557  return img
558 };
559 
561 static dfr make_view_folder(wave source){
562  wave source// wave which contains the raw data from the detector.
563 
564  // data folders and references
565  dfref savedf = GetDataFolderDFR()
566  dfref imagedf = GetWavesDataFolderDFR(source)
567  string s_imagedf = GetDataFolder(1, imagedf)
568  setdatafolder imagedf
569  string s_viewdf = CleanupName("view_" + NameOfWave(source), 0)
570  newdatafolder /o/s $s_viewdf
571  dfref viewdf = GetDataFolderDFR()
572 
573  setdatafolder savedf
574  return viewdf
575 };
576 
585 static dfr get_view_folder(wave source){
586  wave source
587 
588  // data folders and references
589  dfref savedf = GetDataFolderDFR()
590  dfref imagedf = GetWavesDataFolderDFR(source)
591  dfref viewdf
592  setdatafolder imagedf
593  string s_viewdf = CleanupName("view_" + NameOfWave(source), 0)
594  if (DataFolderExists(s_viewdf))
595  setdatafolder $s_viewdf
596  viewdf = GetDataFolderDFR()
597  endif
598 
599  setdatafolder savedf
600  return viewdf
601 };
602 
608 static wave get_view_image(wave source){
609  wave source
610 
611  dfref viewdf = get_view_folder(source)
612  string viewname = "view_image"
613  wave /sdfr=viewdf view = $viewname
614 
615  return view
616 };
617 
618 static variable bp_reset_cursors(WMButtonAction* ba){
619  STRUCT WMButtonAction &ba
620 
621  switch( ba.eventCode )
622  case 2:// mouse up
623  string imgname = StringFromList(0, ImageNameList(ba.win, ";"))
624  wave /z image = ImageNameToWaveRef(ba.win, imgname)
625  if (waveexists(image))
626  Cursor /i/p A $imgname 0,0
627  Cursor /i/p B $imgname DimSize(image, 0)-1, DimSize(image, 1)-1
628  endif
629  break
630  case -1:// control being killed
631  break
632  endswitch
633 
634  return 0
635 };
636 
637 static variable svp_smoothing(WMSetVariableAction* sva){
638  STRUCT WMSetVariableAction &sva
639 
640  string imglist
641 
642  switch( sva.eventCode )
643  case 1:// mouse up
644  case 2:// Enter key
645  case 3:// Live update
646  imglist = ImageNameList(sva.win, ";")
647  wave /z img = ImageNameToWaveRef(sva.win, StringFromList(0, imglist))
648  if (WaveExists(img))
649  wave source = get_source_image(img)
650  if (WaveExists(source))
651  ad_update_profiles(source)
652  endif
653  endif
654  break
655  case -1:// control being killed
656  break
657  endswitch
658 
659  return 0
660 };
661 
662 static variable pmp_export(WMPopupAction* pa){
663  STRUCT WMPopupAction &pa
664 
665  switch( pa.eventCode )
666  case 2:// mouse up
667  variable popNum = pa.popNum
668 
669  string imgname = StringFromList(0, ImageNameList(pa.win, ";"))
670  wave /z image = ImageNameToWaveRef(pa.win, imgname)
671  if (waveexists(image) && (popNum >= 1) && (popNum <= 2))
672  ad_export_profile(image, popNum - 1, show=1)
673  else if (waveexists(image) && (popNum >= 3) && (popNum <= 4))
674  ad_export_profile(image, popNum - 3, show=2)
675  endif
676 
677  break
678  case -1:// control being killed
679  break
680  endswitch
681 
682  return 0
683 };
684 
686 variable ad_profiles_hook(WMWinHookStruct* s){
687  struct WMWinHookStruct &s
688  variable hookresult = 0
689  string imglist
690  string cmd
691  dfref viewdf
692 
693  switch(s.eventCode)
694  case 2:// delete data folder after window is killed
695  imglist = ImageNameList(s.winName, ";")
696  wave /z img = ImageNameToWaveRef(s.winName, StringFromList(0, imglist))
697  if (WaveExists(img))
698  viewdf = GetWavesDataFolderDFR(img)
699  cmd = "killdatafolder /z " + GetDataFolder(1, viewdf)
700  Execute /P/Q/Z cmd
701  endif
702  break
703  case 7:// update profiles when cursor is moved
704  imglist = ImageNameList(s.winName, ";")
705  wave /z img = ImageNameToWaveRef(s.winName, StringFromList(0, imglist))
706  if (WaveExists(img))
708  hookresult = 1
709  else
710  hookresult = 0
711  endif
712  break
713  endswitch
714 
715  return hookresult
716 };
717 
726 variable ad_calc_cursor_profiles(wave image){
727  wave image
728 
729  dfref savedf = GetDataFolderDFR()
730  dfref imagedf = GetWavesDataFolderDFR(image)
731  setdatafolder imagedf
732 
733  svar graphname = prof_graphname
734 
735  variable pa, qa// point coordinates cursor A
736  if (strlen(CsrInfo(A, graphname)) > 0)
737  pa = pcsr(A, graphname)
738  qa = qcsr(A, graphname)
739  else
740  pa = 0
741  qa = 0
742  endif
743 
744  variable pb, qb// point coordinates cursor B
745  if (strlen(CsrInfo(B, graphname)) > 0)
746  pb = pcsr(B, graphname)
747  qb = qcsr(B, graphname)
748  else
749  pb = DimSize(image, 0) - 1
750  qb = DimSize(image, 1) - 1
751  endif
752 
753  ad_calc_profiles(image, pa, qa, pb, qb)
754  setdatafolder savedf
755 };
756 
773 variable ad_calc_profiles(wave image, variable pa, variable qa, variable pb, variable qb){
774  wave image
775  variable pa, qa
776  variable pb, qb
777 
778  dfref savedf = GetDataFolderDFR()
779  dfref imagedf = GetWavesDataFolderDFR(image)
780  setdatafolder imagedf
781 
782  wave xprofiles
783  wave yprofiles
784  nvar graph_avg
785  nvar graph_min
786  nvar graph_max
787  nvar graph_sum
788  nvar graph_sdev
789 
790  // horizontal profiles at crosshairs
791  redimension /n=(dimsize(image,0), 3) xprofiles
792  setscale /p x dimoffset(image,0), dimdelta(image,0), WaveUnits(image,0), xprofiles
793  setscale d 0, 0, waveunits(image,-1), xprofiles
794  xprofiles[][0] = image[p][qa]
795  xprofiles[][1] = image[p][qb]
796 
797  note /k xprofiles
798  note xprofiles, "SourceWave=" + nameofwave(image)
799  note xprofiles, "SourceDimension=0"
800  note xprofiles, "SourceIndex0=" + num2str(qa)
801  note xprofiles, "SourceIndex1=" + num2str(qb)
802 
803  // average horizontal profile between crosshairs
804  variable qq, q0, q1
805  q0 = min(qa, qb)
806  q1 = max(qa, qb)
807  xprofiles[][2] = 0
808  for (qq = q0; qq <= q1; qq += 1)
809  xprofiles[][2] += image[p][qq]
810  endfor
811  xprofiles[][2] /= q1 - q0 + 1
812 
813  // vertical profiles at crosshairs
814  redimension /n=(dimsize(image,1), 3) yprofiles
815  setscale /p x dimoffset(image,1), dimdelta(image,1), WaveUnits(image,1), yprofiles
816  setscale d 0, 0, waveunits(image,-1), yprofiles
817  yprofiles[][0] = image[pa][p]
818  yprofiles[][1] = image[pb][p]
819 
820  note /k yprofiles
821  note yprofiles, "SourceWave=" + nameofwave(image)
822  note yprofiles, "SourceDimension=1"
823  note yprofiles, "SourceIndex0=" + num2str(pa)
824  note yprofiles, "SourceIndex1=" + num2str(pb)
825 
826  // average vertical profile between crosshairs
827  variable pp, p0, p1
828  p0 = min(pa, pb)
829  p1 = max(pa, pb)
830  yprofiles[][2] = 0
831  for (pp = p0; pp <= p1; pp += 1)
832  yprofiles[][2] += image[pp][p]
833  endfor
834  yprofiles[][2] /= p1 - p0 + 1
835 
836  // statistics between crosshairs
837  Duplicate /r=[p0,p1][q0,q1]/o image, roi_image
838  WaveStats /Q roi_image
839  graph_avg = v_avg
840  graph_min = v_min
841  graph_max = v_max
842  graph_sum = v_avg * v_npnts
843  graph_sdev = v_sdev
844 
845  // histogram
846  wave /z hist
847  if (waveexists(hist))
848  Histogram /B=3 roi_image, hist
849  endif
850 
851  setdatafolder savedf
852 };
853 
875 variable ad_export_profile(wave view_image, variable dim, variable trace = defaultValue, variable show = defaultValue, variable overwrite = defaultValue){
876  wave view_image
877  variable dim
878  variable trace
879  variable show
880  variable overwrite
881 
882  dfref savedf = GetDataFolderDFR()
883 
884  if (ParamIsDefault(trace))
885  trace = 2
886  endif
887  if (ParamIsDefault(show))
888  show = 0
889  endif
890  if (ParamIsDefault(overwrite))
891  overwrite = 0
892  endif
893 
894  // view folder
895  dfref imagedf = GetWavesDataFolderDFR(view_image)
896  string dim_label
897  switch(dim)
898  case 0:
899  wave /sdfr=imagedf profiles=xprofiles
900  dim_label = "x"
901  break
902  case 1:
903  wave /sdfr=imagedf profiles=yprofiles
904  dim_label = "y"
905  break
906  default:
907  return -1// invalid argument
908  endswitch
909  string graphname_string = "export_graph_" + dim_label
910  svar /z /sdfr=imagedf linked_graphname = $graphname_string
911 
912  // source folder
913  wave /z source_image = get_source_image(view_image)
914  if (WaveExists(source_image))
915  dfref sourcedf = GetWavesDataFolderDFR(source_image)
916  setdatafolder sourcedf
917  else
918  return -2// invalid source data folder
919  endif
920 
921  // format dest wave name
922  string profile_note = note(profiles)
923  string name_base
924  string name_dim
925  string name_index
926  string profile_name
927  variable index_width = ceil(log(DimSize(view_image, 1 - dim)))
928  variable index0 = NumberByKey("SourceIndex0", profile_note, "=", "\r")
929  variable index1 = NumberByKey("SourceIndex1", profile_note, "=", "\r")
930  name_dim = "_" + dim_label
931  sprintf name_index, "%0*u_%0*u", index_width, index0, index_width, index1
932  name_base = NameOfWave(source_image)
933  name_base = name_base[0, min(strlen(name_base), 31 - strlen(name_index) - strlen(name_dim) - 1)]
934  profile_name = name_base + name_dim + name_index
935  if ((overwrite == 0) && (CheckName(profile_name, 1)))
936  profile_name = UniqueName(profile_name + "_", 1, 0)
937  endif
938 
939  // create dest wave
940  duplicate /o /r=[][trace] profiles, $profile_name /wave=dest_profile
941  redimension /n=(dimsize(profiles, 0)) dest_profile
942  profile_note = ReplaceStringByKey("SourceWave", profile_note, NameOfWave(source_image), "=", "\r")
943  note /k dest_profile
944  note dest_profile, profile_note
945  print "created", GetWavesDataFolder(dest_profile, 2)
946 
947  if (show)
948  string graphname
949  string graphtitle
950  if (show == 2)
951  // common graph for all profiles of a dimension
952  graphname = "export_profiles_" + dim_label
953  graphtitle = UpperStr(dim_label) + " Profiles"
954  else
955  // one graph per source image
956  if (svar_exists(linked_graphname) && (ItemsInList(WinList(linked_graphname, ";", "WIN:1"), ";") >= 1))
957  graphname = linked_graphname
958  else
959  graphname = GetWavesDataFolder(source_image, 0) + name_dim
960  endif
961  graphtitle = UpperStr(dim_label) + " Profiles: " + GetWavesDataFolder(source_image, 2)
962  endif
963 
964  if ((ItemsInList(WinList(graphname, ";", "WIN:1"), ";") >= 1))
965  appendtograph /w=$graphname dest_profile
966  else
967  setdatafolder imagedf
968  display /k=1 /n=$graphname dest_profile as graphtitle
969  graphname = s_name
970  ModifyGraph /w=$graphname mirror=1,nticks=3,minor=1
971  ModifyGraph /w=$graphname axThick=0.5,btLen=4
972  ModifyGraph /w=$graphname gfSize=10
973  ModifyGraph /w=$graphname grid=2,gridHair=0,gridRGB=(52224,52224,52224)
974  Legend /w=$graphname /C/N=legend0/F=0/B=1/A=LT/X=0.00/Y=0.00
975 
976  if (show != 2)
977  string /g $graphname_string = graphname
978  endif
979  endif
980  endif
981 
982  setdatafolder savedf
983  return 0
984 };
985 
986 static variable set_trace_colors(string graphname){
987  string graphname
988 
989  ModifyGraph /w=$graphname /z rgb[0]=(0, 0, 0)
990  ModifyGraph /w=$graphname /z rgb[1]=(65535, 16385, 16385)
991  ModifyGraph /w=$graphname /z rgb[2]=(2, 39321, 1)
992  ModifyGraph /w=$graphname /z rgb[3]=(0, 0, 65535)
993  ModifyGraph /w=$graphname /z rgb[4]=(39321, 1, 31457)
994  ModifyGraph /w=$graphname /z rgb[5]=(48059, 48059, 48059)
995  ModifyGraph /w=$graphname /z rgb[6]=(65535, 32768, 32768)
996  ModifyGraph /w=$graphname /z rgb[7]=(0, 65535, 0)
997  ModifyGraph /w=$graphname /z rgb[8]=(16385,65535,65535)
998  ModifyGraph /w=$graphname /z rgb[9]=(65535, 32768, 58981)
999 };
1000 
1007 variable ad_calc_histogram(wave image){
1008  wave image
1009 
1010  dfref savedf = GetDataFolderDFR()
1011  dfref imagedf = GetWavesDataFolderDFR(image)
1012  setdatafolder imagedf
1013 
1014  wave hist
1015  Histogram /B=3 image, hist
1016 
1017  setdatafolder savedf
1018 };
1019 
1030 variable ad_default_image_filter(wave image, string options){
1031  wave image
1032  string options
1033 };
1034 
1044 variable ad_box_filter(wave image, string options){
1045  wave image
1046  string options
1047 
1048  variable xsmoothing = NumberByKey("SmoothingX", options, "=", ";")
1049  variable ysmoothing = NumberByKey("SmoothingY", options, "=", ";")
1050 
1051  if ((NumType(xsmoothing) == 0) && (xsmoothing >= 2))
1052  Smooth /B /DIM=0 /E=3 xsmoothing, image
1053  endif
1054  if ((NumType(ysmoothing) == 0) && (ysmoothing >= 2))
1055  Smooth /B /DIM=1 /E=3 ysmoothing, image
1056  endif
1057 };
1058 
1066 variable ad_transpose_filter(wave image, string options){
1067  wave image
1068  string options
1069 
1070  MatrixTranspose image
1071 };
1072 
1073 
1074 // ################### 3D DATA ##################
1075 
1082 string ad_display_brick(wave data){
1083  wave data
1084 
1085  if(exists("NewGizmo") != 4)
1086  abort "Gizmo XOP must be installed."
1087  endif
1088  if (WaveDims(data) != 3)
1089  abort "ad_display_brick: data must be three-dimensional."
1090  endif
1091 
1092  dfref savedf = GetDataFolderDFR()
1093  dfref datadf = GetWavesDataFolderDFR(data)
1094  string s_datadf = GetDataFolder(1, datadf)
1095  dfref viewdf = make_view_folder(data)
1096 
1097  setdatafolder viewdf
1098  string dfname = ReplaceString("root:", s_datadf, "")
1099  string graphtitle = dfname + " Gizmo"
1100  string /g gizmo_graphname = graphname_from_dfref(datadf, "giz_")
1101  svar graphname = gizmo_graphname
1102 
1103  if ((strlen(graphname) > 0) && (wintype(graphname) == 13))
1104  setdatafolder savedf
1105  return graphname// gizmo window exists
1106  endif
1107 
1108  variable nx = dimsize(data, 0)
1109  variable ny = dimsize(data, 1)
1110  variable nz = dimsize(data, 2)
1111 
1112  variable pp
1113  string obj
1114  string cmd
1115 
1116  // igor does not allow calling gizmo functions directly
1117  setdatafolder datadf
1118  sprintf cmd, "NewGizmo /k=1 /n=%s /w=(100,100,500,400) /t=\"%s\"", graphname, graphtitle
1119  execute /q cmd
1120  cmd = "AppendToGizmo /D Axes=BoxAxes, name=axes0"
1121  execute /q cmd
1122 
1123  obj = "surface_xmid"
1124  pp = round(nx / 2 - 1)
1125  sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj
1126  execute /q cmd
1127  sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 128}", obj
1128  execute /q cmd
1129  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp
1130  execute /q cmd
1131  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj
1132  execute /q cmd
1133  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj
1134  execute /q cmd
1135  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj
1136  execute /q cmd
1137 
1138  obj = "surface_ymid"
1139  pp = round(ny / 2 - 1)
1140  sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj
1141  execute /q cmd
1142  sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 64}", obj
1143  execute /q cmd
1144  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp
1145  execute /q cmd
1146  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj
1147  execute /q cmd
1148  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj
1149  execute /q cmd
1150  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj
1151  execute /q cmd
1152 
1153  obj = "surface_zmid"
1154  pp = round(nz / 2 - 1)
1155  sprintf cmd, "AppendToGizmo /D surface=%s, name=%s", nameofwave(data), obj
1156  execute /q cmd
1157  sprintf cmd, "ModifyGizmo modifyObject=%s, property={srcMode, 32}", obj
1158  execute /q cmd
1159  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={plane, %d}", obj, pp
1160  execute /q cmd
1161  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCtab, BlueGreenOrange}", obj
1162  execute /q cmd
1163  sprintf cmd, "ModifyGizmo ModifyObject=%s, property={SurfaceCTABScaling,128}", obj
1164  execute /q cmd
1165  sprintf cmd, "ModifyGizmo modifyObject=%s, property={surfaceCTABAlpha, 1.0}", obj
1166  execute /q cmd
1167 
1168  obj = "axes0"
1169  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={-1,axisScalingMode,1}", obj
1170  execute /q cmd
1171  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={-1,axisColor,0,0,0,1}", obj
1172  execute /q cmd
1173  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={0,ticks,3}", obj
1174  execute /q cmd
1175  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={1,ticks,3}", obj
1176  execute /q cmd
1177  sprintf cmd, "ModifyGizmo ModifyObject=%s,property={2,ticks,3}", obj
1178  execute /q cmd
1179  sprintf cmd, "ModifyGizmo modifyObject=%s property={Clipped,0}", obj
1180  execute /q cmd
1181  sprintf cmd, "ModifyGizmo modifyObject=%s property={-1,fontScaleFactor,2}", obj
1182  execute /q cmd
1183 
1184  sprintf cmd, "ModifyGizmo showAxisCue=1"
1185  execute /q cmd
1186 
1187  setdatafolder savedf
1188  return graphname
1189 };
1190 
1197 variable ad_brick_slicer(wave data){
1198  wave data
1199 
1200  // data folders and references
1201  dfref savedf = GetDataFolderDFR()
1202  dfref datadf = GetWavesDataFolderDFR(data)
1203  string s_datadf = GetDataFolder(1, datadf)
1204  dfref viewdf = make_view_folder(data)
1205 
1206  setdatafolder viewdf
1207  svar /z ex_panel = slicer_panelname
1208  if (svar_exists(ex_panel))
1209  string panels = WinList("SlicerPanel*", ";", "WIN:64")
1210  if (WhichListItem(ex_panel, panels, ";") >= 0)
1211  dowindow /f $(StringFromList(0, panels, ";"))
1212  return 0
1213  endif
1214  endif
1215 
1216  variable /g x_slice_pos
1217  variable /g y_slice_pos
1218  variable /g z_slice_pos
1219  variable /g slab_thickness
1220  string /g brick_path = getwavesdatafolder(data, 2)
1221  variable /g x_autoinc = 0
1222  variable /g y_autoinc = 0
1223  variable /g z_autoinc = 0
1224 
1225  // axis labels
1226  string labels = note(data)
1227  string xlabel = StringByKey("AxisLabelX", labels, "=", "\r")
1228  if (!strlen(xlabel))
1229  xlabel = "X"
1230  endif
1231  string ylabel = StringByKey("AxisLabelY", labels, "=", "\r")
1232  if (!strlen(ylabel))
1233  ylabel = "Y"
1234  endif
1235  string zlabel = StringByKey("AxisLabelZ", labels, "=", "\r")
1236  if (!strlen(zlabel))
1237  zlabel = "Z"
1238  endif
1239  string dlabel = StringByKey("Dataset", labels, "=", "\r")
1240  if (!strlen(dlabel))
1241  dlabel = NameOfWave(data)
1242  endif
1243 
1244  // this section copied from slicer panel
1245  NewPanel /k=1 /W=(500,600,890,940) /N=SlicerPanel as "Brick Slicer"
1246  string /g slicer_panelname = S_name
1247  string panel = s_name
1248 
1249  GroupBox g_xslice win=$panel,pos={8,8},size={376,96},title=xlabel
1250  Slider sl_xslice_position win=$panel,pos={16,32},size={240,56},proc=PearlAreaDisplay#slp_slice_position
1251  Slider sl_xslice_position win=$panel,limits={0,100,1},variable=x_slice_pos,vert= 0
1252  SetVariable sv_xslice_position win=$panel,pos={20,80},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="X"
1253  SetVariable sv_xslice_position win=$panel,limits={0,100,1},value=x_slice_pos
1254  Button b_xslice_center win=$panel,pos={122,80},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618"
1255  Button b_xslice_center win=$panel,help={"reset to center position"}
1256  Button b_xslice_extract win=$panel,pos={288,80},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice"
1257  Button b_xslice_extract win=$panel,help={"extract this slice to a separate wave"}
1258  //CheckBox cb_xslab_active win=$panel,pos={288,80},size={80,16},title="Display X Slab"
1259  //CheckBox cb_xslab_active win=$panel,value= 0
1260  TitleBox tb_xslice_animation win=$panel,pos={288,32},size={356,16},title="animation",frame=0
1261  TitleBox tb_xslice_animation win=$panel,anchor= MC
1262  Button b_xslice_back win=$panel,pos={288,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646"
1263  Button b_xslice_back win=$panel,help={"animate backwards"}
1264  Button b_xslice_forward win=$panel,pos={312,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649"
1265  Button b_xslice_forward win=$panel,help={"animate forward"}
1266  Button b_xslice_stop win=$panel,pos={336,48},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
1267  Button b_xslice_stop win=$panel,help={"stop animation"}
1268 
1269  GroupBox g_yslice win=$panel,pos={8,108},size={376,96},title=ylabel
1270  Slider sl_yslice_position win=$panel,pos={16,132},size={240,56},proc=PearlAreaDisplay#slp_slice_position
1271  Slider sl_yslice_position win=$panel,limits={0,100,1},variable=y_slice_pos,vert= 0
1272  SetVariable sv_yslice_position win=$panel,pos={20,180},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Y"
1273  SetVariable sv_yslice_position win=$panel,limits={0,100,1},value=y_slice_pos
1274  Button b_yslice_center win=$panel,pos={122,180},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618"
1275  Button b_yslice_center win=$panel,help={"reset to center position"}
1276  Button b_yslice_extract win=$panel,pos={288,180},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice"
1277  Button b_yslice_extract win=$panel,help={"extract this slice to a separate wave"}
1278  //CheckBox cb_yslab_active win=$panel,pos={288,180},size={80,16},title="Display Y Slab"
1279  //CheckBox cb_yslab_active win=$panel,value= 0
1280  TitleBox tb_yslice_animation win=$panel,pos={288,132},size={356,16},title="animation",frame=0
1281  TitleBox tb_yslice_animation win=$panel,anchor= MC
1282  Button b_yslice_back win=$panel,pos={288,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646"
1283  Button b_yslice_back win=$panel,help={"animate backwards"}
1284  Button b_yslice_forward win=$panel,pos={312,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649"
1285  Button b_yslice_forward win=$panel,help={"animate forward"}
1286  Button b_yslice_stop win=$panel,pos={336,148},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
1287  Button b_yslice_stop win=$panel,help={"stop animation"}
1288 
1289  GroupBox g_zslice win=$panel,pos={8,208},size={376,96},title=zlabel
1290  Slider sl_zslice_position win=$panel,pos={16,232},size={240,56},proc=PearlAreaDisplay#slp_slice_position
1291  Slider sl_zslice_position win=$panel,limits={0,100,1},variable=z_slice_pos,vert= 0
1292  SetVariable sv_zslice_position win=$panel,pos={20,280},size={92,16},proc=PearlAreaDisplay#svp_slice_position,title="Z"
1293  SetVariable sv_zslice_position win=$panel,limits={0,100,1},value=z_slice_pos
1294  Button b_zslice_center win=$panel,pos={122,280},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W618"
1295  Button b_zslice_center win=$panel,help={"reset to center position"}
1296  Button b_zslice_extract win=$panel,pos={288,280},size={68,20},proc=PearlAreaDisplay#bp_extract_slice,title="extract slice"
1297  Button b_zslice_extract win=$panel,help={"extract this slice to a separate wave"}
1298  //CheckBox cb_zslab_active win=$panel,pos={288,280},size={80,16},title="Display Z Slab"
1299  //CheckBox cb_zslab_active win=$panel,value= 0
1300  TitleBox tb_zslice_animation win=$panel,pos={288,232},size={356,16},title="animation",frame=0
1301  TitleBox tb_zslice_animation win=$panel,anchor= MC
1302  Button b_zslice_back win=$panel,pos={288,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W646"
1303  Button b_zslice_back win=$panel,help={"animate backwards"}
1304  Button b_zslice_forward win=$panel,pos={312,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W649"
1305  Button b_zslice_forward win=$panel,help={"animate forward"}
1306  Button b_zslice_stop win=$panel,pos={336,248},size={20,20},proc=PearlAreaDisplay#bp_move_slice,title="\\W616"
1307  Button b_zslice_stop win=$panel,help={"stop animation"}
1308 
1309  TitleBox t_slicerpath win=$panel,pos={8,316},size={128,20},disable=2,title=dlabel
1310  //SetVariable setvar0 win=$panel,pos={240,316},size={120,16},title="slab thickness"
1311  //SetVariable setvar0 win=$panel,limits={1,inf,1},value=slab_thickness
1312 
1313  // update control limits and move slicing planes to the center
1314  setwindow $panel, userdata(control_datafolder) = GetDataFolder(1, viewdf)
1315  setwindow $panel, userdata(brick_path) = brick_path
1317  x_slice_pos = dimoffset(data, 0) + dimsize(data, 0) * dimdelta(data, 0) / 2
1318  y_slice_pos = dimoffset(data, 1) + dimsize(data, 1) * dimdelta(data, 1) / 2
1319  z_slice_pos = dimoffset(data, 2) + dimsize(data, 2) * dimdelta(data, 2) / 2
1320 
1321  svar /z /sdfr=viewdf gizmo_graphname
1322  if (svar_exists(gizmo_graphname) && (strlen(gizmo_graphname) > 0) && (wintype(gizmo_graphname) == 13))
1323  ad_gizmo_set_plane(data, 0, x_slice_pos)
1324  ad_gizmo_set_plane(data, 1, y_slice_pos)
1325  ad_gizmo_set_plane(data, 2, z_slice_pos)
1326  endif
1327  svar /z /sdfr=viewdf slice_graphname
1328  if (svar_exists(slice_graphname) && (strlen(slice_graphname) > 0) && (wintype(slice_graphname) == 1))
1329  ad_profiles_set_slice(data, 2, z_slice_pos)
1330  endif
1331 
1333  setdatafolder savedf
1334 };
1335 
1345 string ad_display_slice(wave data){
1346  wave data
1347 
1348  if (WaveDims(data) != 3)
1349  abort "ad_display_slice: data must be three-dimensional."
1350  endif
1351 
1352  dfref savedf = GetDataFolderDFR()
1353  dfref datadf = GetWavesDataFolderDFR(data)
1354  string s_datadf = GetDataFolder(1, datadf)
1355  dfref viewdf = make_view_folder(data)
1356 
1357  setdatafolder viewdf
1358  string dfname = ReplaceString("root:", s_datadf, "")
1359  dfname = dfname[0, strlen(dfname) - 2]
1360  string graphtitle = dfname + " Slice"
1361 
1362  if (exists("slice_graphname") != 2)
1363  string /g slice_graphname = ""
1364  endif
1365  string /g slice_wavename = CleanupName("slice_" + NameOfWave(data), 0)
1366  svar graphname = slice_graphname
1367  svar slicename = slice_wavename
1368 
1369  make /n=(1,1)/o $slicename
1370  wave slice = $slicename
1371  if ((strlen(graphname) == 0) || (wintype(graphname) != 1))
1372  graphname = ad_display_profiles(slice)
1373  endif
1374  variable z_slice_pos = dimoffset(data, 2) + dimsize(data, 2) * dimdelta(data, 2) / 2
1375  ad_profiles_set_slice(data, 2, z_slice_pos)
1376  ad_profiles_set_cursor(slice, "A", -inf, -inf, pscale=1)
1377  ad_profiles_set_cursor(slice, "B", +inf, +inf, pscale=1)
1378 
1379  setdatafolder savedf
1380  return graphname
1381 };
1382 
1386 static variable update_slice_info(){
1387  dfref savedf = GetDataFolderDFR()
1388 
1389  svar brick_path
1390  //svar slicer_panelname
1391  wave brick = $brick_path
1392 
1393  //dowindow /F $slicer_panelname
1394  variable lo, hi, inc
1395  lo = dimoffset(brick, 0)
1396  inc = dimdelta(brick, 0)
1397  hi = lo + inc * (dimsize(brick, 0) - 1)
1398  Slider sl_xslice_position,limits={lo,hi,inc}
1399  SetVariable sv_xslice_position,limits={lo,hi,inc}
1400  lo = dimoffset(brick, 1)
1401  inc = dimdelta(brick, 1)
1402  hi = lo + inc * (dimsize(brick, 1) - 1)
1403  Slider sl_yslice_position,limits={lo,hi,inc}
1404  SetVariable sv_yslice_position,limits={lo,hi,inc}
1405  lo = dimoffset(brick, 2)
1406  inc = dimdelta(brick, 2)
1407  hi = lo + inc * (dimsize(brick, 2) - 1)
1408  Slider sl_zslice_position,limits={lo,hi,inc}
1409  SetVariable sv_zslice_position,limits={lo,hi,inc}
1410 
1411  setdatafolder savedf
1412 };
1413 
1422 variable ad_gizmo_set_plane(wave brick, variable dim, variable value){
1423  wave brick
1424  variable dim
1425  variable value
1426 
1427  dfref savedf = GetDataFolderDFR()
1428  dfref datadf = GetWavesDataFolderDFR(brick)
1429  dfref viewdf = get_view_folder(brick)
1430  svar /z /sdfr=viewdf graphname=gizmo_graphname
1431 
1432  variable pp = round((value - dimoffset(brick, dim)) / dimdelta(brick, dim))
1433  if ((pp < 0) || (pp >= dimsize(brick, dim)))
1434  return -1// requested value out of range
1435  endif
1436 
1437  if (svar_exists(graphname) && (strlen(graphname) > 0) && (wintype(graphname) == 13))
1438  string axes = "xyz"
1439  string obj = "surface_" + axes[dim] + "mid"
1440  string cmd
1441  sprintf cmd, "ModifyGizmo /N=%s ModifyObject=%s, property={plane, %d}", graphname, obj, pp
1442  execute /q cmd
1443  else
1444  return -2// gizmo window not found
1445  endif
1446 
1447  return 0
1448 };
1449 
1458 variable ad_profiles_set_slice(wave brick, variable dim, variable value){
1459  wave brick
1460  variable dim
1461  variable value
1462 
1463  dfref savedf = GetDataFolderDFR()
1464  dfref datadf = GetWavesDataFolderDFR(brick)
1465  dfref viewdf = get_view_folder(brick)
1466  svar /z /sdfr=viewdf graphname = slice_graphname
1467  svar /z /sdfr=viewdf slicename = slice_wavename
1468 
1469  variable pp = round((value - dimoffset(brick, dim)) / dimdelta(brick, dim))
1470  if ((pp < 0) || (pp >= dimsize(brick, dim)))
1471  return -1// requested value out of range
1472  endif
1473 
1474  if (svar_exists(graphname) && (strlen(graphname) > 0) && (wintype(graphname) == 1))
1475  setdatafolder viewdf
1476  switch(dim)
1477  case 0:// X
1478  wave wdest = ad_extract_slab_x(brick, pp, pp, slicename)
1479  ad_update_profiles(wdest)
1480  break
1481  case 1:// Y
1482  wave wdest = ad_extract_slab_y(brick, pp, pp, slicename)
1483  ad_update_profiles(wdest)
1484  break
1485  case 2:// Z
1486  wave wdest = ad_extract_slab_z(brick, pp, pp, slicename)
1487  ad_update_profiles(wdest)
1488  break
1489  endswitch
1490  else
1491  return -2// graph window not found
1492  endif
1493 
1494  setdatafolder savedf
1495  return 0
1496 };
1497 
1499 static variable slp_slice_position(WMSliderAction* sa){
1500  STRUCT WMSliderAction &sa
1501 
1502  dfref savedf = GetDataFolderDFR()
1503 
1504  switch( sa.eventCode )
1505  case -1:// control being killed
1506  break
1507  default:
1508  if( sa.eventCode & 1 )// value set
1509  string control_datafolder = GetUserData(sa.win, "", "control_datafolder")
1510  setdatafolder control_datafolder
1511  string brick_path = GetUserData(sa.win, "", "brick_path")
1512  string axis = StringFromList(1, sa.ctrlName, "_")
1513  variable dim = char2num(axis[0]) - char2num("x")
1514 
1515  wave /z brick = $brick_path
1516  if (WaveExists(brick))
1517  ad_gizmo_set_plane(brick, dim, sa.curval)
1518  ad_profiles_set_slice(brick, dim, sa.curval)
1519  else
1520  Abort "can't find original wave " + brick_path
1521  endif
1522  endif
1523  break
1524  endswitch
1525 
1526  setdatafolder savedf
1527  return 0
1528 };
1529 
1531 static variable svp_slice_position(WMSetVariableAction* sva){
1532  STRUCT WMSetVariableAction &sva
1533 
1534  dfref savedf = GetDataFolderDFR()
1535 
1536  switch( sva.eventCode )
1537  case 1:// mouse up
1538  case 2:// Enter key
1539  case 3:// Live update
1540  string control_datafolder = GetUserData(sva.win, "", "control_datafolder")
1541  setdatafolder control_datafolder
1542  string brick_path = GetUserData(sva.win, "", "brick_path")
1543  string axis = StringFromList(1, sva.ctrlName, "_")
1544  variable dim = char2num(axis[0]) - char2num("x")
1545 
1546  wave /z brick = $brick_path
1547  if (WaveExists(brick))
1548  ad_gizmo_set_plane(brick, dim, sva.dval)
1549  ad_profiles_set_slice(brick, dim, sva.dval)
1550  else
1551  Abort "can't find original wave " + brick_path
1552  endif
1553  break
1554  case -1:// control being killed
1555  break
1556  endswitch
1557 
1558  setdatafolder savedf
1559  return 0
1560 };
1561 
1563 static variable bp_move_slice(WMButtonAction* ba){
1564  STRUCT WMButtonAction &ba
1565 
1566  dfref savedf = GetDataFolderDFR()
1567 
1568  switch( ba.eventCode )
1569  case 2:// mouse up
1570  string control_datafolder = GetUserData(ba.win, "", "control_datafolder")
1571  setdatafolder control_datafolder
1572  string brick_path = GetUserData(ba.win, "", "brick_path")
1573  string axis = StringFromList(1, ba.ctrlName, "_")
1574  string cmd = StringFromList(2, ba.ctrlName, "_")
1575  variable dim = char2num(axis[0]) - char2num("x")
1576  string posvariable = getdatafolder(1) + axis[0] + "_slice_pos"
1577  nvar pos = $(posvariable)
1578 
1579  wave /z brick = $brick_path
1580  if (WaveExists(brick))
1581  strswitch (cmd)
1582  case "forward":
1583  ad_slicer_start_bg(brick, dim, posvariable, dimdelta(brick, dim))
1584  break
1585  case "back":
1586  ad_slicer_start_bg(brick, dim, posvariable, -dimdelta(brick, dim))
1587  break
1588  case "center":
1589  ad_slicer_stop_bg(posvariable)
1590  bp_move_slice_center(brick, dim, posvariable)
1591  break
1592  case "stop":
1593  ad_slicer_stop_bg(posvariable)
1594  break
1595  endswitch
1596  else
1597  ad_slicer_stop_bg(posvariable)
1598  Abort "can't find original wave " + brick_path
1599  endif
1600  break
1601  case -1:// control being killed
1602  break
1603  endswitch
1604 
1605  setdatafolder savedf
1606  return 0
1607 };
1608 
1612 static variable bp_extract_slice(WMButtonAction* ba){
1613  STRUCT WMButtonAction &ba
1614 
1615  dfref savedf = GetDataFolderDFR()
1616 
1617  switch( ba.eventCode )
1618  case 2:// mouse up
1619  string control_datafolder = GetUserData(ba.win, "", "control_datafolder")
1620  setdatafolder control_datafolder
1621  string brick_path = GetUserData(ba.win, "", "brick_path")
1622  wave brick = $brick_path
1623  dfref brickdf = GetWavesDataFolderDFR(brick)
1624 
1625  string axis = StringFromList(1, ba.ctrlName, "_")
1626  string cmd = StringFromList(2, ba.ctrlName, "_")
1627  variable dim = char2num(axis[0]) - char2num("x")
1628  string posvariable = getdatafolder(1) + axis[0] + "_slice_pos"
1629 
1630  nvar pos = $(posvariable)
1631  variable pp = round((pos - dimoffset(brick, dim)) / dimdelta(brick, dim))
1632  if ((pp < 0) || (pp >= dimsize(brick, dim)))
1633  return -1// requested value out of range
1634  endif
1635 
1636  variable dig = ceil(log(dimsize(brick, dim)))
1637  string slicename
1638  sprintf slicename, "%s_%s%0*u", NameOfWave(brick), axis[0], dig, pp
1639  setdatafolder brickdf
1640  switch(dim)
1641  case 0:// X
1642  wave wdest = ad_extract_slab_x(brick, pp, pp, slicename)
1643  break
1644  case 1:// Y
1645  wave wdest = ad_extract_slab_y(brick, pp, pp, slicename)
1646  break
1647  case 2:// Z
1648  wave wdest = ad_extract_slab_z(brick, pp, pp, slicename)
1649  break
1650  endswitch
1651 
1652  string msg
1653  sprintf msg, "%s=%g", axis[0], pos
1654  note wdest, msg
1655 
1656  break
1657  case -1:// control being killed
1658  break
1659  endswitch
1660 
1661  setdatafolder savedf
1662  return 0
1663 };
1664 
1666 static variable bp_move_slice_center(wave brick, variable dim, string posvariable){
1667  wave brick
1668  variable dim
1669  string posvariable
1670 
1671  nvar pos = $posvariable
1672  pos = dimoffset(brick, dim) + dimdelta(brick, dim) * dimsize(brick, dim) / 2
1673  ad_gizmo_set_plane(brick, dim, pos)
1674  ad_profiles_set_slice(brick, dim, pos)
1675 };
1676 
1678 static variable ad_slicer_move_bg(WMBackgroundStruct* s){
1679  STRUCT WMBackgroundStruct &s
1680 
1681  dfref savedf = GetDataFolderDFR()
1682  setdatafolder root:pearl_area:slicer
1683  wave /t bg_brickpaths
1684  wave /t bg_graphnames
1685  wave /t bg_variablepaths
1686  wave bg_dimensions
1687  wave bg_increments
1688 
1689  variable ii
1690  variable nn = numpnts(bg_brickpaths)
1691  variable dim
1692  variable pp
1693 
1694  for (ii = 0; ii < nn; ii += 1)
1695  wave /z brick = $bg_brickpaths[ii]
1696  nvar /z pos = $bg_variablepaths[ii]
1697  dim = bg_dimensions[0]
1698  pos += bg_increments[ii]
1699  // wrap around at limits
1700  pp = round((pos - dimoffset(brick, dim)) / dimdelta(brick, dim))
1701  if (pp <= -0.5)
1702  pos = dimoffset(brick, dim) + dimdelta(brick, dim) * (dimsize(brick, dim) - 1)
1703  else if (pp >= dimsize(brick, dim) - 0.5)
1704  pos = dimoffset(brick, dim)
1705  endif
1706  if (waveexists(brick))
1707  ad_gizmo_set_plane(brick, dim, pos)
1708  ad_profiles_set_slice(brick, dim, pos)
1709  endif
1710  endfor
1711 
1712  setdatafolder savedf
1713  return 0
1714 };
1715 
1718  dfref savedf = GetDataFolderDFR()
1719  setdatafolder root:
1720  newdatafolder /o/s pearl_area
1721  newdatafolder /o/s slicer
1722 
1723  make /n=0/o/t bg_brickpaths
1724  make /n=0/o/t bg_variablepaths
1725  make /n=0/o/i/u bg_dimensions
1726  make /n=0/o bg_increments
1727 
1728  CtrlNamedBackground ad_slicer, period = 30, proc = PearlAreaDisplay#ad_slicer_move_bg
1729 
1730  setdatafolder savedf
1731  return 0
1732 };
1733 
1741 variable ad_slicer_start_bg(wave brick, variable dimension, string posvariable, variable delta){
1742  wave brick// 3D data wave
1743  variable dimension// dimension to animate, 0, 1, or 2
1744  string posvariable// full path to the global position variable
1745  variable delta// step increment, should be +/- dimdelta
1746 
1747  dfref savedf = GetDataFolderDFR()
1748  setdatafolder root:pearl_area:slicer
1749  wave /t bg_brickpaths
1750  wave /t bg_variablepaths
1751  wave bg_dimensions
1752  wave bg_increments
1753 
1754  // create entry in ad_slicer background task table
1755  variable idx
1756  FindValue /TEXT=posvariable /TXOP=4 /Z bg_variablepaths
1757  if (v_value >= 0)
1758  idx = v_value
1759  else
1760  idx = numpnts(bg_variablepaths)
1761  InsertPoints idx, 1, bg_brickpaths, bg_variablepaths, bg_dimensions, bg_increments
1762  endif
1763 
1764  // set background task
1765  bg_brickpaths[idx] = GetWavesDataFolder(brick, 2)
1766  bg_variablepaths[idx] = posvariable
1767  bg_dimensions[idx] = dimension
1768  bg_increments[idx] = delta
1769 
1770  // start background task
1771  if (numpnts(bg_variablepaths) > 0)
1772  CtrlNamedBackground ad_slicer, start
1773  endif
1774 
1775  setdatafolder savedf
1776  return 0
1777 };
1778 
1783 variable ad_slicer_stop_bg(string posvariable){
1784  string posvariable
1785 
1786  dfref savedf = GetDataFolderDFR()
1787  setdatafolder root:pearl_area:slicer
1788  wave /t bg_brickpaths
1789  wave /t bg_variablepaths
1790  wave bg_dimensions
1791  wave bg_increments
1792 
1793  // find entry in ad_slicer background task table
1794  FindValue /TEXT=posvariable /TXOP=4 /Z bg_variablepaths
1795  if (v_value >= 0)
1796  DeletePoints v_value, 1, bg_brickpaths, bg_variablepaths, bg_dimensions, bg_increments
1797  endif
1798 
1799  // stop background task if task table is empty
1800  if (numpnts(bg_variablepaths) == 0)
1801  CtrlNamedBackground ad_slicer, stop
1802  endif
1803 
1804  setdatafolder savedf
1805  return 0
1806 };
1807 
threadsafe wave ad_extract_slab_x(wave dataset, variable p1, variable p2, string destname, variable noavg=defaultValue)
variable ad_profiles_cursor_mode(wave image, variable mode)
switch cursors on a profiles graph
-
static variable ad_slicer_move_bg(WMBackgroundStruct *s)
move a slice by one step (background task).
+
static variable ad_slicer_move_bg(WMBackgroundStruct *s)
move a slice by one step (background task).
static variable set_trace_colors(string graphname)
-
static variable slp_slice_position(WMSliderAction *sa)
-
variable ad_slicer_start_bg(wave brick, variable dimension, string posvariable, variable delta)
start the animation.
+
static variable slp_slice_position(WMSliderAction *sa)
set slice coordinate (slider procedure).
+
variable ad_slicer_start_bg(wave brick, variable dimension, string posvariable, variable delta)
start the animation.
variable ad_profiles_crosshairs(wave image, variable clear=defaultValue)
draw permanent crosshairs in a profiles graph.
variable ad_update_profiles(wave image)
update a profiles graph with new data.
-
variable ad_slicer_stop_bg(string posvariable)
stop the animation.
+
variable ad_slicer_stop_bg(string posvariable)
stop the animation.
variable ad_default_image_filter(wave image, string options)
abstract filter function for image display.
static variable svp_smoothing(WMSetVariableAction *sva)
variable ad_brick_slicer(wave data)
open a slicer panel for 3D data.
@@ -131,7 +131,7 @@ $(document).ready(function(){initNavTree('pearl-area-display_8ipf_source.html','
variable ad_profiles_set_cursor(wave image, string cursorname, variable xa, variable ya, variable pscale=defaultValue)
move a cursor to the specified position in a profiles graph.
static wave get_view_image(wave source)
find the view image wave corresponding to the given source.
instant visualization of angle scan and manipulator position.
-
static variable bp_extract_slice(WMButtonAction *ba)
export a slice (button procedure).
+
static variable bp_extract_slice(WMButtonAction *ba)
export a slice (button procedure).
static variable pmp_export(WMPopupAction *pa)
static wave get_source_image(wave view)
find the source image wave corresponding to the given view.
string ad_display_histogram(wave image)
display the histogram of a 2D image.
@@ -140,16 +140,16 @@ $(document).ready(function(){initNavTree('pearl-area-display_8ipf_source.html','
static string graphname_from_dfref(dfref df, string prefix)
compose a valid and unique graph name from a data folder reference
variable ad_calc_cursor_profiles(wave image)
calculate profiles, statistics, and histogram of a cross-hair delimited region of interest...
static variable update_slice_info()
update controls with data scale limits.
-
variable ad_slicer_init_bg()
initialize the slice animation background task.
+
variable ad_slicer_init_bg()
initialize the slice animation background task.
string ad_display_profiles(wave image, string filter=defaultValue)
open a new profiles graph window.
-
static variable svp_slice_position(WMSetVariableAction *sva)
set slice coordinate (button procedure).
+
static variable svp_slice_position(WMSetVariableAction *sva)
set slice coordinate (button procedure).
static variable bp_reset_cursors(WMButtonAction *ba)
variable ad_export_profile(wave view_image, variable dim, variable trace=defaultValue, variable show=defaultValue, variable overwrite=defaultValue)
export a profile from a profiles graph to the source data folder.
variable ad_gizmo_set_plane(wave brick, variable dim, variable value)
set the position of a slicing plane of a 3D brick in a Gizmo window.
variable ad_transpose_filter(wave image, string options)
transpose image filter.
string ad_display_slice(wave data)
display three-dimensional data by 2D slice.
-
static variable bp_move_slice_center(wave brick, variable dim, string posvariable)
move the slice to the center of the dimension (button procedure).
-
static variable bp_move_slice(WMButtonAction *ba)
move slice (button procedure).
+
static variable bp_move_slice_center(wave brick, variable dim, string posvariable)
move the slice to the center of the dimension (button procedure).
+
static variable bp_move_slice(WMButtonAction *ba)
move slice (button procedure).
variable ad_box_filter(wave image, string options)
boxcar smoothing filter.
string ad_display_brick(wave data)
open a new "gizmo" window with three-dimensional data.
variable ad_profiles_hook(WMWinHookStruct *s)
hook function for user events in the profiles window.
@@ -159,7 +159,7 @@ $(document).ready(function(){initNavTree('pearl-area-display_8ipf_source.html','
-

Definition at line 1612 of file pearl-data-explorer.ipf.

+

Definition at line 1624 of file pearl-data-explorer.ipf.

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

Definition at line 1586 of file pearl-data-explorer.ipf.

+

Definition at line 1598 of file pearl-data-explorer.ipf.

@@ -435,7 +435,7 @@ Variables
-

Definition at line 1632 of file pearl-data-explorer.ipf.

+

Definition at line 1644 of file pearl-data-explorer.ipf.

@@ -461,7 +461,7 @@ Variables
-

Definition at line 1659 of file pearl-data-explorer.ipf.

+

Definition at line 1671 of file pearl-data-explorer.ipf.

@@ -487,7 +487,7 @@ Variables
-

Definition at line 1473 of file pearl-data-explorer.ipf.

+

Definition at line 1485 of file pearl-data-explorer.ipf.

@@ -513,7 +513,7 @@ Variables
-

Definition at line 1505 of file pearl-data-explorer.ipf.

+

Definition at line 1517 of file pearl-data-explorer.ipf.

@@ -539,7 +539,7 @@ Variables
-

Definition at line 1445 of file pearl-data-explorer.ipf.

+

Definition at line 1457 of file pearl-data-explorer.ipf.

@@ -565,7 +565,7 @@ Variables
-

Definition at line 1459 of file pearl-data-explorer.ipf.

+

Definition at line 1471 of file pearl-data-explorer.ipf.

@@ -591,7 +591,7 @@ Variables
-

Definition at line 1379 of file pearl-data-explorer.ipf.

+

Definition at line 1391 of file pearl-data-explorer.ipf.

@@ -617,7 +617,7 @@ Variables
-

Definition at line 1393 of file pearl-data-explorer.ipf.

+

Definition at line 1405 of file pearl-data-explorer.ipf.

@@ -643,7 +643,7 @@ Variables
-

Definition at line 1572 of file pearl-data-explorer.ipf.

+

Definition at line 1584 of file pearl-data-explorer.ipf.

@@ -669,7 +669,7 @@ Variables
-

Definition at line 1431 of file pearl-data-explorer.ipf.

+

Definition at line 1443 of file pearl-data-explorer.ipf.

@@ -695,7 +695,7 @@ Variables
-

Definition at line 753 of file pearl-data-explorer.ipf.

+

Definition at line 765 of file pearl-data-explorer.ipf.

@@ -731,7 +731,7 @@ Variables
-

Definition at line 910 of file pearl-data-explorer.ipf.

+

Definition at line 922 of file pearl-data-explorer.ipf.

@@ -767,7 +767,7 @@ Variables
-

Definition at line 465 of file pearl-data-explorer.ipf.

+

Definition at line 478 of file pearl-data-explorer.ipf.

@@ -835,7 +835,7 @@ Variables
-

Definition at line 1229 of file pearl-data-explorer.ipf.

+

Definition at line 1241 of file pearl-data-explorer.ipf.

@@ -861,7 +861,7 @@ Variables
-

Definition at line 1686 of file pearl-data-explorer.ipf.

+

Definition at line 1698 of file pearl-data-explorer.ipf.

@@ -887,7 +887,7 @@ Variables
-

Definition at line 1537 of file pearl-data-explorer.ipf.

+

Definition at line 1549 of file pearl-data-explorer.ipf.

@@ -923,7 +923,7 @@ Variables
-

Definition at line 967 of file pearl-data-explorer.ipf.

+

Definition at line 979 of file pearl-data-explorer.ipf.

@@ -959,7 +959,7 @@ Variables
-

Definition at line 1113 of file pearl-data-explorer.ipf.

+

Definition at line 1125 of file pearl-data-explorer.ipf.

@@ -995,7 +995,7 @@ Variables
-

Definition at line 1163 of file pearl-data-explorer.ipf.

+

Definition at line 1175 of file pearl-data-explorer.ipf.

@@ -1033,7 +1033,7 @@ Variables

load a matrix (STM) data file

-

Definition at line 1206 of file pearl-data-explorer.ipf.

+

Definition at line 1218 of file pearl-data-explorer.ipf.

@@ -1094,7 +1094,7 @@ Variables
-

Definition at line 1061 of file pearl-data-explorer.ipf.

+

Definition at line 1073 of file pearl-data-explorer.ipf.

@@ -1120,7 +1120,7 @@ Variables
-

Definition at line 943 of file pearl-data-explorer.ipf.

+

Definition at line 955 of file pearl-data-explorer.ipf.

@@ -1168,7 +1168,7 @@ Variables
-

Definition at line 832 of file pearl-data-explorer.ipf.

+

Definition at line 844 of file pearl-data-explorer.ipf.

@@ -1239,7 +1239,7 @@ Variables
-

Definition at line 1288 of file pearl-data-explorer.ipf.

+

Definition at line 1300 of file pearl-data-explorer.ipf.

@@ -1293,7 +1293,7 @@ Variables
-

Definition at line 618 of file pearl-data-explorer.ipf.

+

Definition at line 631 of file pearl-data-explorer.ipf.

@@ -1318,7 +1318,7 @@ Variables
-

Definition at line 547 of file pearl-data-explorer.ipf.

+

Definition at line 560 of file pearl-data-explorer.ipf.

@@ -1344,7 +1344,7 @@ Variables
-

Definition at line 504 of file pearl-data-explorer.ipf.

+

Definition at line 517 of file pearl-data-explorer.ipf.

@@ -1407,7 +1407,7 @@ Variables
Returns
wave reference of the preview image
-

Definition at line 350 of file pearl-data-explorer.ipf.

+

Definition at line 363 of file pearl-data-explorer.ipf.

@@ -1433,7 +1433,7 @@ Variables
-

Definition at line 382 of file pearl-data-explorer.ipf.

+

Definition at line 395 of file pearl-data-explorer.ipf.

@@ -1471,7 +1471,7 @@ Variables
Returns
wave reference of the preview image. empty wave reference if the function failed.
-

Definition at line 422 of file pearl-data-explorer.ipf.

+

Definition at line 435 of file pearl-data-explorer.ipf.

@@ -1544,7 +1544,7 @@ Variables
-

Definition at line 588 of file pearl-data-explorer.ipf.

+

Definition at line 601 of file pearl-data-explorer.ipf.

@@ -1567,7 +1567,7 @@ Variables

prompt functions must have the same name as the corresponding reduction function with the prefix "prompt_". be aware of the limited length of function names in Igor.

this function is a prototype. it does nothing but returns OK.

-

Definition at line 1041 of file pearl-data-explorer.ipf.

+

Definition at line 1053 of file pearl-data-explorer.ipf.

@@ -1595,7 +1595,7 @@ Variables
-

Definition at line 1047 of file pearl-data-explorer.ipf.

+

Definition at line 1059 of file pearl-data-explorer.ipf.

@@ -1621,7 +1621,7 @@ Variables
-

Definition at line 1002 of file pearl-data-explorer.ipf.

+

Definition at line 1014 of file pearl-data-explorer.ipf.

@@ -1682,7 +1682,7 @@ Variables
-

Definition at line 859 of file pearl-data-explorer.ipf.

+

Definition at line 871 of file pearl-data-explorer.ipf.

@@ -1699,7 +1699,7 @@ Variables
-

Definition at line 786 of file pearl-data-explorer.ipf.

+

Definition at line 798 of file pearl-data-explorer.ipf.

@@ -1895,7 +1895,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.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  setdatafolder $package_path
312  svar s_preview_file
313  svar s_preview_source
314  psh5_load_preview("preview_image", "pearl_explorer_filepath", filename)
315  s_preview_file = filename
316  s_preview_source = ""
317  wave /z preview_image
318 
319  svar /z s_file_info
320  if (! svar_exists(s_file_info))
321  string /g s_file_info
322  endif
323  if (strlen(s_preview_file) > 0)
324  s_file_info = psh5_load_info("pearl_explorer_filepath", filename)
325  else
326  s_file_info = ""
327  endif
328 
329  if (DataFolderExists("attr"))
330  setdatafolder attr
331  preview_attributes(GetDataFolderDFR())
332  setdatafolder ::
333  endif
334 
335  setdatafolder saveDF
336  return preview_image
337 };
338 
350 static wave preview_hdf_file(string filename){
351  string filename
352 
353  dfref saveDF = GetDataFolderDFR()
354  setdatafolder $package_path
355  svar s_preview_file
356  svar s_preview_source
357  adh5_load_preview("preview_image", "pearl_explorer_filepath", filename)
358  s_preview_file = filename
359  s_preview_source = ""
360  wave /z preview_image
361 
362  svar /z s_file_info
363  if (! svar_exists(s_file_info))
364  string /g s_file_info
365  endif
366  if (strlen(s_preview_file) > 0)
367  s_file_info = adh5_load_info("pearl_explorer_filepath", filename)
368  else
369  s_file_info = ""
370  endif
371 
372  if (DataFolderExists("attr"))
373  setdatafolder attr
374  preview_attributes(GetDataFolderDFR())
375  setdatafolder ::
376  endif
377 
378  setdatafolder saveDF
379  return preview_image
380 };
381 
382 static wave preview_itx_file(string filename){
383  string filename
384 
385  dfref saveDF = GetDataFolderDFR()
386  setdatafolder $package_path
387  svar s_preview_file
388  svar s_preview_source
389  wave preview_image
390 
391  // note: some versions of PEARL data files save data to a new data folder,
392  // and leave the newly created folder as the current folder.
393  // the free data folder is used by those files which don't create their own data folder.
394  // this is the new recommended behaviour
395  dfref dataDF = newfreedatafolder()
396  setdatafolder dataDF
397  LoadWave /t/p=pearl_explorer_filepath/q filename
398  s_preview_file = s_filename
399  s_preview_source = ""
400 
402  preview_attributes(dataDF, include_datawaves=0)
403 
404  setdatafolder saveDF
405  return preview_image
406 };
407 
422 static wave preview_mtrx_file(string filename){
423  string filename
424 
425 #if exists("MFR_OpenResultFile")
426  dfref saveDF = GetDataFolderDFR()
427  setdatafolder $package_path
428  variable /g V_MatrixFileReaderOverwrite = 1
429  variable /g V_MatrixFileReaderFolder = 0
430  variable /g V_MatrixFileReaderDouble = 0
431  svar s_preview_file
432  svar s_preview_source
433  string datanames
434  string dataname
435  datanames = mtrx_load_preview("preview", "pearl_explorer_filepath", filename)
436  if (strlen(datanames) > 0)
437  s_preview_file = filename
438 
439  dataname = StringFromList(0, datanames)
440  wave data = $dataname
441  duplicate /o $dataname, preview_image
442  s_preview_source = StringByKey("Dataset", note(data), "=", "\r")
443 
444  svar /z s_file_info
445  if (svar_exists(s_file_info))
446  s_file_info = ""
447  endif
448 
449  variable i
450  variable n = ItemsInList(datanames)
451  string s
452  for (i = 0; i < n; i += 1)
453  s = StringFromList(i, datanames)
454  killwaves /z $s
455  endfor
456  endif
457  wave /z preview_image
458  setdatafolder saveDF
459 #else
460  wave /z preview_image = $""
461 #endif
462  return preview_image
463 };
464 
465 static variable extract_preview_image(wave data, wave preview){
466  // extracts a preview image from a wave of arbitrary dimension
467  wave data
468  wave preview
469 
470  variable z1, z2
471 
472  // extract image
473  switch (WaveDims(data))
474  case 1:
475  redimension /n=(numpnts(data)) preview
476  preview = data[p]
477  break
478  case 2:
479  redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview
480  preview = data
481  break
482  case 3:
483  redimension /n=(dimsize(data, 0), dimsize(data, 1)) preview
484  z1 = floor(DimSize(data, 2) / 2)
485  z2 = z1
486  wave slab = ad_extract_slab(data, nan, nan, nan, nan, z1, z2, "", pscale=1)
487  preview = slab
488  break
489  case 4:
490  // not implemented
491  endswitch
492 
493  switch (WaveDims(data))
494  case 4:
495  case 3:
496  case 2:
497  setscale /p y dimoffset(data, 1), dimdelta(data, 1), waveunits(data, 1), preview
498  case 1:
499  setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), preview
500  setscale d 0, 0, waveunits(data, -1), preview
501  endswitch
502 };
503 
504 static variable preview_dataset(string datasetname){
505  string datasetname// name of a data folder under root
506 
507  dfref saveDF = GetDataFolderDFR()
508 
509  if (!DataFolderExists("root:" + datasetname))
510  return -1
511  endif
512  setdatafolder root:
513  setdatafolder $datasetname
514  dfref datadf = GetDataFolderDFR()
515  wave /z data
516 
517  setdatafolder $package_path
518  svar s_preview_file
519  svar s_preview_source
520  wave preview_image
521  if (WaveExists(data))
522  s_preview_file = datasetname
523  s_preview_source = ""
524  extract_preview_image(data, preview_image)
525  show_preview_graph(preview_image)
526  else
527  preview_image = nan
528  s_preview_file = datasetname
529  setdatafolder datadf
531  show_preview_graph(preview_image)
532  endif
533 
534  // attributes
535  setdatafolder datadf
536  if (DataFolderExists("attr"))
537  setdatafolder attr
538  preview_attributes(GetDataFolderDFR())
539  else
540  preview_attributes(GetDataFolderDFR(), include_datawaves=0)
541  endif
542 
543  setdatafolder saveDF
544  return 0
545 };
546 
547 static variable preview_datafolder(){
548  // preview data in the current data folder
549  dfref saveDF = GetDataFolderDFR()
550 
551  setdatafolder $package_path
552  svar s_preview_file
553  svar s_preview_source
554  svar s_preview_pvs
555  wave preview_image
556 
557  setdatafolder saveDF
558 
559  // select a wave to display
560  // consider only double-precision waves, i.e. ignore text and other special waves
561  // filter by matching PV name to s_preview_pvs
562  string d_names = WaveList("*", ";", "DP:1")
563  variable nw = ItemsInList(d_names, ";")
564  variable npv = ItemsInList(s_preview_pvs, ";")
565  variable iw, ipv
566  string wname, wnote, pv_name, pv_match
567  for (iw = 0; iw < nw; iw += 1)
568  wname = StringFromList(iw, d_names, ";")
569  wnote = note($wname)
570  pv_name = StringByKey("PV", wnote, "=", "\r")
571  // find matching data wave by PV name
572  for (ipv = 0; ipv < npv; ipv += 1)
573  pv_match = StringFromList(ipv, s_preview_pvs)
574  if (StringMatch(pv_name, pv_match))
575  wave data = $wname
576  s_preview_source = pv_name
577  extract_preview_image(data, preview_image)
578  preview_setscale_x(data, preview_image)
579  npv = 0
580  nw = 0
581  endif
582  endfor
583  endfor
584 
585  setdatafolder saveDF
586 };
587 
588 static variable preview_setscale_x(wave data, wave preview){
589  // sets the approximate x scale of OTF data.
590  // requires an Axis1 tag with name of x wave in the wave note.
591  // if any of these conditions is true, the function does not change the scaling:
592  // 1) Axis1 tag or referenced wave is missing.
593  // 2) preview wave is not set to point scaling.
594  // 3) x wave is not monotonic (90% of the steps in the same direction).
595  wave data
596  wave preview
597 
598  if ((DimOffset(preview, 0) == 0) && (DimDelta(preview, 0) == 1))
599  string xname = StringByKey("Axis1", note(data), "=", "\r")
600  wave /z xwave = $xname
601  if (WaveExists(xwave))
602  // check for monotonicity
603  variable monotonic = 0
604  duplicate /free xwave, xdiff
605  differentiate /p xwave /D=xdiff
606  duplicate /free xdiff, xflag
607  xflag = xdiff > 0
608  monotonic = sum(xflag) > numpnts(xwave) * 0.9
609  xflag = xdiff < 0
610  monotonic = monotonic || (sum(xflag) > numpnts(xwave) * 0.9)
611  if (monotonic)
612  setscale /i x xwave[0], xwave[numpnts(xwave)-1], waveunits(xwave, -1), preview
613  endif
614  endif
615  endif
616 };
617 
618 static variable preview_attributes(dfref attr_folder, dfref dest_folder = defaultValue, wave attr_filter = defaultValue, variable include_datawaves = defaultValue, variable include_infowaves = defaultValue){
619  // copies the first elements of attributes in the specified folder to the preview waves
620  // by default, all existing attributes are copied
621  // if a text wave attr_filter exists in the pear_explorer folder, only the attributes referenced therein are copied
622  // to set up a filter, duplicate the attr_names wave of a template dataset, and remove unwanted items
623  dfref attr_folder// data folder which contains the attribute waves
624  dfref dest_folder// destination folder. the output is written to the attr_names and attr_values waves
625  // default = package folder
626  wave /t attr_filter// list of attributes allowed in the output
627  // default = use attr_filter of package folder
628  variable include_datawaves// 1 (default) = include data waves (any numeric wave which has a PV=name note)
629  // 0 = don't include attributes from data waves
630  variable include_infowaves// 1 (default) = include attributes from info waves (IN, ID, IV, IU)
631  // 0 = don't include attributes from info waves
632 
633  dfref saveDF = GetDataFolderDFR()
634  setdatafolder $package_path
635 
636  if (ParamIsDefault(dest_folder))
637  dest_folder = GetDataFolderDFR()// package folder
638  endif
639  if (ParamIsDefault(attr_filter))
640  wave /t /z attr_filter
641  endif
642  if (ParamIsDefault(include_datawaves))
643  include_datawaves = 1
644  endif
645  if (ParamIsDefault(include_infowaves))
646  include_infowaves = 1
647  endif
648 
649  setdatafolder dest_folder
650  wave /t /z attr_names, attr_values
651  if (!WaveExists(attr_names) || !WaveExists(attr_values))
652  make /n=(1) /o /t attr_names, attr_values
653  endif
654  attr_names = ""
655  attr_values = ""
656 
657  string /g s_attr_folder = GetDataFolder(1, attr_folder)
658  setdatafolder attr_folder
659  wave /t /z IN
660  wave /t /z ID
661  wave /t /z IV
662  wave /t /z IU
663 
664  // compile list of attributes
665  variable nattr// destination attributes
666  variable iattr
667  variable ninfo// info wave elements
668  variable iinfo
669  variable nw// attribute waves
670  variable iw
671  string sw
672  string ss
673 
674  if (WaveExists(IN) && include_infowaves)
675  ninfo = numpnts(IN)
676  else
677  ninfo = 0
678  endif
679  if (include_datawaves)
680  string waves = WaveList("*", ";", "")
681  string exceptions = "ID;IN;IU;IV"
682  waves = RemoveFromList(exceptions, waves)
683  nw = ItemsInList(waves, ";")
684  else
685  nw = 0
686  endif
687 
688  if (WaveExists(attr_filter) && (numpnts(attr_filter) >= 1))
689  nattr = numpnts(attr_filter)
690  redimension /n=(nattr) attr_names
691  attr_names = attr_filter
692  else
693  if(ninfo > 0)
694  redimension /n=(ninfo) attr_names
695  attr_names = SelectString(strlen(ID[p]) >= 0, IN[p], ID[p])// use ID unless empty
696  endif
697 
698  nattr = ninfo + nw
699  iattr = ninfo
700  redimension /n=(nattr) attr_names
701  for (iw = 0; iw < nw; iw +=1 )
702  sw = StringFromList(iw, waves, ";")
703  ss = StringByKey("PV", note($sw), "=", "\r")
704  FindValue /text=sw attr_names
705  if ((v_value < 0) && (strlen(ss) >= 0))
706  attr_names[iattr] = sw
707  iattr += 1
708  endif
709  endfor
710  nattr = iattr
711  endif
712  redimension /n=(nattr) attr_names, attr_values
713  sort attr_names, attr_names
714 
715  // look up attribute values
716  for (iattr = 0; iattr < nattr; iattr += 1)
717  sw = attr_names[iattr]
718  // try info waves
719  if (ninfo > 0)
720  FindValue /text=sw ID
721  if (v_value >= 0)
722  attr_values[iattr] = IV[v_value]
723  endif
724  FindValue /text=sw IN
725  if (v_value >= 0)
726  attr_values[iattr] = IV[v_value]
727  endif
728  endif
729 
730  // override from attribute wave if existent
731  if (nw > 0)
732  switch (WaveType($sw, 1))
733  case 1:// numeric
734  wave /z w = $sw
735  if (WaveExists(w) && (numpnts(w) >= 1))
736  sprintf ss, "%g", w[0]
737  attr_values[iattr] = ss
738  endif
739  break
740  case 2:// text
741  wave /t/z wt = $sw
742  if (WaveExists(wt) && (numpnts(wt) >= 1))
743  attr_values[iattr] = wt[0]
744  endif
745  break
746  endswitch
747  endif
748  endfor
749 
750  setdatafolder saveDF
751 };
752 
753 static variable display_dataset(string datasetname){
754  // displays the graph of a loaded dataset in its own window
755  string datasetname// name of a data folder under root
756 
757  dfref saveDF = GetDataFolderDFR()
758 
759  if (!DataFolderExists("root:" + datasetname))
760  return -1
761  endif
762  setdatafolder root:
763  setdatafolder $datasetname
764  dfref datadf = GetDataFolderDFR()
765  wave /z data
766  if (!WaveExists(data))
767  wave /z data = data1
768  endif
769 
770  if (WaveExists(data))
771  switch(WaveDims(data))
772  case 2:
773  ad_display_profiles(data)
774  break
775  case 3:
776  ad_display_slice(data)
777  ad_brick_slicer(data)
778  break
779  endswitch
780  endif
781 
782  setdatafolder saveDF
783  return 0
784 };
785 
787  dfref df = GetDataFolderDFR()
788  wave /t /sdfr=df attr_names
789  wave /t /sdfr=df attr_values
790  attributes_notebook(attr_names, attr_values, GetDataFolder(0))
791 };
792 
793 static variable attributes_notebook(wave attr_names, wave attr_values, string title){
794  wave /t attr_names
795  wave /t attr_values
796  string title
797 
798  dfref saveDF = GetDataFolderDFR()
799  setdatafolder $package_path
800  wave /t/z attr_filter, attr_filter_summary
801 
802  string name = CleanupName("nb_" + title[0,28], 0)
803  if (WinType(name) == 5)
804  Notebook $name selection={startOfFile, endOfFile}
805  Notebook $name text=""
806  else
807  NewNotebook /F=1 /K=1 /N=$name as title
808  GetWindow $name wsize
809  v_right = v_left + 260
810  v_bottom = v_top + 360
811  MoveWindow /W=$name v_left, v_top, v_right, v_bottom
812  Notebook $name tabs={2*72}
813  endif
814 
815  // summary
816  if (WaveExists(attr_filter_summary) && (numpnts(attr_filter_summary) >= 1))
817  notebook $name fStyle=1, text="Summary\r\r"
818  notebook $name fStyle=0
819  notebook_add_attributes(name, attr_filter_summary, attr_names, attr_values)
820  notebook $name text="\r"
821  endif
822 
823  // all attributes
824  notebook $name fStyle=1, text="All Attributes\r\r"
825  notebook $name fStyle=0
826  notebook_add_attributes(name, $"", attr_names, attr_values)
827  notebook $name selection={startOfFile,startOfFile}, findText={"",1}
828 
829  setdatafolder saveDF
830 };
831 
832 static variable notebook_add_attributes(string notebook_name, wave attr_filter, wave attr_names, wave attr_values){
833  string notebook_name
834  wave /t /z attr_filter
835  wave /t attr_names
836  wave /t attr_values
837 
838  variable nw = numpnts(attr_names)
839  variable iw
840  string sw
841  string ss
842 
843  variable do_filter = WaveExists(attr_filter)
844 
845  for (iw = 0; iw < nw; iw += 1)
846  if (do_filter)
847  sw = attr_names[iw]
848  FindValue /text=sw attr_filter
849  else
850  v_value = 0
851  endif
852  if (v_value >= 0)
853  sprintf ss, "%s\t%s\r", attr_names[iw], attr_values[iw]
854  notebook $notebook_name text=ss
855  endif
856  endfor
857 };
858 
859 static string show_preview_graph(wave data, wave xdata = defaultValue){
860  // displays a preview of one- or two-dimensional data
861  wave data// data to be displayed. must either one-dimensional or two-dimensional
862  wave xdata// positions on x axis
863 
864  dfref saveDF = GetDataFolderDFR()
865  setdatafolder $package_path
866 
867  svar s_profiles_graph
868  svar s_preview_file
869  svar s_preview_source
870  svar s_preview_trace_graph
871 
872  if ((strlen(s_profiles_graph) > 0) && (WinType(s_profiles_graph) == 1))
873  KillWindow $s_profiles_graph
874  endif
875  if ((strlen(s_preview_trace_graph) > 0) && (WinType(s_preview_trace_graph) == 1))
876  KillWindow $s_preview_trace_graph
877  endif
878 
879  string graphname
880  if (wavedims(data) == 2)
881  s_profiles_graph = ad_display_profiles(data)
882  ModifyGraph /w=$s_profiles_graph /z wbRGB=(48640,56832,60160)
883  graphname = s_profiles_graph
884  else if (wavedims(data) == 1)
885  duplicate /o data, preview_trace
886  if (!ParamIsDefault(xdata))
887  duplicate /o xdata, preview_trace_x
888  else
889  duplicate /o data, preview_trace_x
890  preview_trace_x = x
891  setscale d 0, 0, WaveUnits(data, 0), preview_trace_x
892  endif
893  s_preview_trace_graph = display_preview_trace(preview_trace_x, preview_trace)
894  ModifyGraph /w=$s_preview_trace_graph wbRGB=(48640,56832,60160)
895  graphname = s_preview_trace_graph
896  else
897  return ""
898  endif
899 
900  string title = "Preview " + s_preview_file
901  if (strlen(s_preview_source) > 0)
902  title = title + " (" + s_preview_source[0,31] + ")"
903  endif
904  dowindow /f/t $graphname, title
905 
906  setdatafolder saveDF
907  return graphname
908 };
909 
910 static string display_preview_trace(wave xtrace, wave ytrace){
911  wave xtrace
912  wave ytrace
913 
914  display /n=pearl_explorer_1d /k=1 ytrace vs xtrace as "Preview"
915  string graphname = s_name
916  ModifyGraph /w=$graphname rgb[0]=(0,0,0)
917  ModifyGraph /w=$graphname grid=2
918  ModifyGraph /w=$graphname mirror=1
919  ModifyGraph /w=$graphname minor=1
920  ModifyGraph /w=$graphname axThick=0.5
921  ModifyGraph /w=$graphname gridRGB=(52224,52224,52224)
922  ModifyGraph /w=$graphname gridHair=0
923  ModifyGraph /w=$graphname tick=0
924  ModifyGraph /w=$graphname btLen=4
925 
926  // axis labels
927  string labels = note(ytrace)
928  string lab
929  lab = StringByKey("AxisLabelX", labels, "=", "\r")
930  if (!strlen(lab))
931  lab = "X"
932  endif
933  Label /w=$graphname bottom lab + " (\\U)"
934  lab = StringByKey("AxisLabelD", labels, "=", "\r")
935  if (!strlen(lab))
936  lab = "value"
937  endif
938  Label /w=$graphname left lab + " (\\U)"
939 
940  return s_name
941 };
942 
943 static variable load_selected_files(string options = defaultValue){
944  string options
945 
946  dfref saveDF = GetDataFolderDFR()
947  setdatafolder $package_path
948 
949  wave wSelectedFiles
950  wave/t wtFiles
951  variable nn = numpnts(wSelectedFiles)
952  variable ii
953  for (ii = 0; ii < nn; ii += 1)
954  if (wSelectedFiles[ii])
955  if (ParamIsDefault(options))
956  load_file(wtFiles[ii])
957  else
958  load_file(wtFiles[ii], options=options)
959  endif
960  endif
961  endfor
962 
964  setdatafolder saveDF
965 };
966 
967 static variable load_file(string filename, string options = defaultValue){
968  string filename
969  string options
970 
971  dfref saveDF = GetDataFolderDFR()
972 
973  variable ft = pearl_file_type(filename)
974  switch(ft)
975  case 1:
976  if (ParamIsDefault(options))
977  load_pshell_file(filename)
978  else
979  load_pshell_file(filename, options=options)
980  endif
981  break
982  case 2:
983  if (ParamIsDefault(options))
984  load_hdf_file(filename)
985  else
986  load_hdf_file(filename, options=options)
987  endif
988  break
989  case 3:
990  load_itx_file(filename)
991  break
992  case 4:
993  load_mtrx_file(filename)
994  break
995  default:
996  break
997  endswitch
998 
999  setdatafolder saveDF
1000 };
1001 
1002 static variable prompt_hdf_options(string* options){
1003  string &options
1004 
1005  string mode = StringByKey("mode", options, ":", ";")
1006  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1007 
1008  string modes = "load_reduced"
1009  string reduction_functions = adh5_list_reduction_funcs()
1010 
1011  if (strlen(mode) == 0)
1012  mode = StringFromList(0, modes, ";")
1013  endif
1014  if (strlen(reduction_func) == 0)
1015  reduction_func = StringFromList(0, reduction_functions, ";")
1016  endif
1017 
1018  prompt mode, "Mode", popup, modes
1019  prompt reduction_func, "Reduction Function", popup, reduction_functions
1020  doprompt "HDF5 Loading Options", mode, reduction_func
1021 
1022  if (v_flag == 0)
1023  options = ReplaceStringByKey("mode", options, mode, ":", ";")
1024  options = ReplaceStringByKey("reduction_func", options, reduction_func, ":", ";")
1025  endif
1026  return v_flag// 0 = OK, 1 = cancel
1027 };
1028 
1041 variable prompt_default_process(string* param){
1042  string &param
1043 
1044  return 0
1045 };
1046 
1047 variable prompt_func_params(string func_name, string* func_param){
1048  string func_name
1049  string &func_param
1050 
1051  string prompt_name = "prompt_" + func_name
1052  if (exists(prompt_name) == 6)
1053  funcref prompt_default_process prompt_func = $prompt_name
1054  return prompt_func(func_param)
1055  else
1056  // ignore missing prompt function
1057  return 0
1058  endif
1059 };
1060 
1061 static dfr load_pshell_file(string filename, string options = defaultValue){
1062  string filename
1063  string options
1064 
1065  dfref saveDF = GetDataFolderDFR()
1066  string nickname = ad_suggest_foldername(filename)
1067  string loaded_filename = ""
1068 
1069  if (ParamIsDefault(options))
1070  loaded_filename = psh5_load_complete(nickname, "pearl_explorer_filepath", filename)
1071  else
1072  if (strlen(options) == 0)
1073  svar pref_options = $(package_path + "s_hdf_options")
1074  options = pref_options
1075  if (prompt_hdf_options(options) == 0)
1076  // OK
1077  pref_options = options
1078  else
1079  // cancel
1080  options = ""
1081  endif
1082  endif
1083 
1084  string mode = StringByKey("mode", options, ":", ";")
1085 
1086  strswitch(mode)
1087  case "load_reduced":
1088  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1089  svar pref_params = $(package_path + "s_reduction_params")
1090  string reduction_params = pref_params
1091  if (prompt_func_params(reduction_func, reduction_params) == 0)
1092  pref_params = reduction_params
1093  print reduction_func, reduction_params
1094  psh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
1095  svar s_filepath
1096  loaded_filename = s_filepath
1097  endif
1098  break
1099  endswitch
1100  endif
1101 
1102  dfref dataDF
1103  if (strlen(loaded_filename) > 0)
1104  setdatafolder $("root:" + nickname)
1105  dataDF = GetDataFolderDFR()
1106  string /g pearl_explorer_import = "load_pshell_file"
1107  endif
1108 
1109  setdatafolder saveDF
1110  return dataDF
1111 };
1112 
1113 static dfr load_hdf_file(string filename, string options = defaultValue){
1114  string filename
1115  string options
1116 
1117  dfref saveDF = GetDataFolderDFR()
1118  string nickname = ad_suggest_foldername(filename)
1119  string loaded_filename = ""
1120 
1121  if (ParamIsDefault(options))
1122  loaded_filename = adh5_load_complete(nickname, "pearl_explorer_filepath", filename)
1123  else
1124  if (strlen(options) == 0)
1125  svar pref_options = $(package_path + "s_hdf_options")
1126  options = pref_options
1127  if (prompt_hdf_options(options) == 0)
1128  // OK
1129  pref_options = options
1130  else
1131  // cancel
1132  options = ""
1133  endif
1134  endif
1135 
1136  string mode = StringByKey("mode", options, ":", ";")
1137 
1138  strswitch(mode)
1139  case "load_reduced":
1140  string reduction_func = StringByKey("reduction_func", options, ":", ";")
1141  svar pref_params = $(package_path + "s_reduction_params")
1142  string reduction_params = pref_params
1143  if (prompt_func_params(reduction_func, reduction_params) == 0)
1144  pref_params = reduction_params
1145  print reduction_func, reduction_params
1146  loaded_filename = adh5_load_reduced(nickname, "pearl_explorer_filepath", filename, $reduction_func, reduction_params)
1147  endif
1148  break
1149  endswitch
1150  endif
1151 
1152  dfref dataDF
1153  if (strlen(loaded_filename) > 0)
1154  setdatafolder $("root:" + nickname)
1155  dataDF = GetDataFolderDFR()
1156  string /g pearl_explorer_import = "load_hdf_file"
1157  endif
1158 
1159  setdatafolder saveDF
1160  return dataDF
1161 };
1162 
1163 static dfr load_itx_file(string filename, string options = defaultValue){
1164  string filename
1165  string options
1166 
1167  dfref saveDF = GetDataFolderDFR()
1168  string nickname = itx_suggest_foldername(filename)
1169 
1170  if (ParamIsDefault(options))
1171  options = ""
1172  endif
1173 
1174  setdatafolder root:
1175  newdatafolder /s/o $("root:" + nickname)
1176  dfref dataDF = GetDataFolderDFR()
1177 
1178  // note: some versions of PEARL data files save data to a new data folder,
1179  // and leave the newly created folder as the current folder.
1180  // the free data folder is used by those files which don't create their own data folder.
1181  // this is the new recommended behaviour
1182 
1183  LoadWave /t/p=pearl_explorer_filepath/q filename
1184  svar waves = s_wavenames
1185  dfref actDF = GetDataFolderDFR()
1186  if (v_flag > 0)
1187  string /g pearl_explorer_import = "load_itx_file"
1188  endif
1189 
1190  if (!DataFolderRefsEqual(actDF, dataDF))
1191  // the file created its own data folder.
1192  // let's kill the pre-allocated folder
1193  setdatafolder dataDF
1194  if (ItemsInList(WaveList("*", ";", ""), ";") == 0)
1195  killdatafolder /z dataDF
1196  endif
1197  endif
1198 
1199  setdatafolder saveDF
1200  return actDF
1201 };
1202 
1206 static dfr load_mtrx_file(string filename, string options = defaultValue){
1207  string filename
1208  string options
1209 
1210  dfref saveDF = GetDataFolderDFR()
1211  dfref dataDF = $""
1212 
1213 #if exists("MFR_OpenResultFile")
1214  setdatafolder root:
1215  string datasets = ""
1216  datasets = mtrx_load_file("pearl_explorer_filepath", filename)
1217  if (strlen(datasets) > 0)
1218  string /g pearl_explorer_import = "load_mtrx_file"
1219  string s1 = StringFromList(0, datasets)
1220  wave w1 = $s1
1221  dataDF = GetWavesDataFolderDFR(w1)
1222  endif
1223 #endif
1224 
1225  setdatafolder saveDF
1226  return dataDF
1227 };
1228 
1229 string itx_suggest_foldername(string filename, variable ignoredate = defaultValue, string sourcename = defaultValue, variable unique = defaultValue){
1230  // suggests the name of a data folder based on a file name
1231  // if the file name follows the naming convention source-date-index.extension,
1232  // the function tries to generate the nick name as source_date_index.
1233  // otherwise it's just a cleaned up version of the file name.
1234  string filename// file name, including extension. can also include a folder path (which is ignored)
1235  // the extension is currently ignored, but may be used later to select the parent folder
1236  variable ignoredate// if non-zero, the nick name will not include the date part
1237  // defaults to zero
1238  string sourcename// nick name of the data source
1239  // the function tries to detect the source from the file name
1240  // this option can be used to override auto-detection
1241  // allowed values: sscan, otf
1242  variable unique// if non-zero, the resulting name is made a unique data folder name in the current data folder
1243  // defaults to zero
1244 
1245  if (ParamIsDefault(ignoredate))
1246  ignoredate = 0
1247  endif
1248  if (ParamIsDefault(unique))
1249  unique = 0
1250  endif
1251 
1252  string basename = ParseFilePath(3, filename, ":", 0, 0)
1253  string extension = ParseFilePath(4, filename, ":", 0, 0)
1254  string nickname
1255 
1256  string autosource
1257  if (strsearch(basename, "X03DA_PC", 0, 2) >= 0)
1258  autosource = "sscan"
1259  basename = ReplaceString("_", basename, "-")
1260  ignoredate = 1
1261  else if (strsearch(basename, "otf", 0, 2) >= 0)
1262  autosource = "otf"
1263  endif
1264  if (ParamIsDefault(sourcename))
1265  sourcename = autosource
1266  endif
1267 
1268  variable nparts = ItemsInList(basename, "-")
1269  if (nparts >= 3)
1270  string datepart = StringFromList(nparts - 2, basename, "-")
1271  string indexpart = StringFromList(nparts - 1, basename, "-")
1272  if (ignoredate)
1273  sprintf nickname, "%s_%s", sourcename, indexpart
1274  else
1275  sprintf nickname, "%s_%s_%s", sourcename, datepart, indexpart
1276  endif
1277  else
1278  nickname = CleanupName(basename, 0)
1279  endif
1280 
1281  if (unique && CheckName(nickname, 11))
1282  nickname = UniqueName(nickname + "_", 11, 0)
1283  endif
1284 
1285  return nickname
1286 };
1287 
1289  PauseUpdate; Silent 1// building window...
1290  NewPanel /K=1 /W=(800,0,1530,444) as "PEARL Data Explorer"
1291  ModifyPanel cbRGB=(48640,56832,60160)
1292 
1293  GroupBox gb_filepath,pos={8,4},size={224,52},title="file system folder"
1294  TitleBox tb_filepath,pos={20,24},size={174,20},frame=2
1295  TitleBox tb_filepath,variable=root:packages:pearl_explorer:s_filepath,fixedSize=1
1296  Button b_browse_filepath,pos={200,24},size={20,20},proc=PearlDataExplorer#bp_browse_filepath,title="..."
1297  Button b_browse_filepath,fColor=(65280,48896,32768)
1298 
1299  GroupBox gb_prefs,pos={240,4},size={58,52},title="prefs",help={"explorer package preferences"}
1300  Button b_save_prefs,pos={252,20},size={32,17},proc=PearlDataExplorer#bp_save_prefs,title="save"
1301  Button b_save_prefs,help={"save preferences of the data explorer package (data file path, attributes filter)"}
1302  Button b_save_prefs,fColor=(65280,48896,32768)
1303  Button b_load_prefs,pos={252,36},size={32,17},proc=PearlDataExplorer#bp_load_prefs,title="load"
1304  Button b_load_prefs,help={"load preferences of the data explorer package"}
1305  Button b_load_prefs,fColor=(65280,48896,32768)
1306 
1307  GroupBox gb_filelist,pos={8,64},size={224,372},title="data files"
1308  ListBox lb_files,pos={20,84},size={200,212},proc=PearlDataExplorer#lbp_filelist
1309  ListBox lb_files,listWave=root:packages:pearl_explorer:wtFiles
1310  ListBox lb_files,selWave=root:packages:pearl_explorer:wSelectedFiles,row= 11,mode= 4
1311  TitleBox tb_file_info,pos={20,300},size={198,78},frame=2,fixedSize=1
1312  TitleBox tb_file_info,variable= root:packages:pearl_explorer:s_file_info
1313 
1314  Button b_update_filelist,pos={20,386},size={60,20},proc=PearlDataExplorer#bp_update_filelist,title="update list"
1315  Button b_update_filelist,fColor=(65280,48896,32768)
1316  CheckBox cb_file_preview,pos={84,390},size={60,20},title="preview"
1317  CheckBox cb_file_preview,help={"enable/disable automatic preview window when selecting a data file"}
1318  CheckBox cb_file_preview,value=1
1319  Button b_file_prev,pos={176,386},size={20,20},proc=PearlDataExplorer#bp_file_prev,title="\\W646"
1320  Button b_file_prev,help={"previous file"}
1321  Button b_file_prev,fColor=(65280,48896,32768)
1322  Button b_file_next,pos={200,386},size={20,20},proc=PearlDataExplorer#bp_file_next,title="\\W649"
1323  Button b_file_next,help={"next file"}
1324  Button b_file_next,fColor=(65280,48896,32768)
1325 
1326  Button b_load_files,pos={20,410},size={76,20},proc=PearlDataExplorer#bp_load_files,title="load complete"
1327  Button b_load_files,help={"load the complete contents from the selected files"}
1328  Button b_load_files,fColor=(65280,48896,32768)
1329  Button b_load_files_opt,pos={100,410},size={76,20},proc=PearlDataExplorer#bp_load_files_opt,title="load reduced"
1330  Button b_load_files_opt,help={"load data from the selected files with options (reduced dimensions)"}
1331  Button b_load_files_opt,fColor=(65280,48896,32768)
1332 
1333  // datasets group
1334  GroupBox gb_datasets,pos={240,64},size={224,372},title="datasets"
1335  ListBox lb_datasets,pos={252,84},size={200,300},proc=PearlDataExplorer#lbp_datasets,help={"list of loaded datasets"}
1336  ListBox lb_datasets,listWave=root:packages:pearl_explorer:wtDatasets
1337  ListBox lb_datasets,selWave=root:packages:pearl_explorer:wSelectedDatasets,mode= 1
1338  ListBox lb_datasets,selRow= -1
1339 
1340  Button b_update_datasets,pos={252,386},size={60,20},proc=PearlDataExplorer#bp_update_datasets,title="update list"
1341  Button b_update_datasets,help={"update the list of datasets"}
1342  Button b_update_datasets,fColor=(65280,48896,32768)
1343  CheckBox cb_dataset_preview,pos={316,390},size={60,20},title="preview"
1344  CheckBox cb_dataset_preview,help={"enable/disable automatic preview window when selecting a dataset"}
1345  CheckBox cb_dataset_preview,value=0
1346  Button b_dataset_prev,pos={408,386},size={20,20},proc=PearlDataExplorer#bp_dataset_prev,title="\\W646"
1347  Button b_dataset_prev,help={"goto previous dataset"}
1348  Button b_dataset_prev,fColor=(65280,48896,32768)
1349  Button b_dataset_next,pos={432,386},size={20,20},proc=PearlDataExplorer#bp_dataset_next,title="\\W649"
1350  Button b_dataset_next,help={"goto next dataset"}
1351  Button b_dataset_next,fColor=(65280,48896,32768)
1352 
1353  Button b_dataset_folder,pos={252,410},size={50,20},proc=PearlDataExplorer#bp_dataset_folder,title="goto DF"
1354  Button b_dataset_folder,help={"set the current data folder of the selected dataset"}
1355  Button b_dataset_folder,fColor=(65280,48896,32768)
1356  Button b_dataset_display,pos={306,410},size={50,20},proc=PearlDataExplorer#bp_dataset_display,title="display"
1357  Button b_dataset_display,help={"display the selected dataset in its own window"}
1358  Button b_dataset_display,fColor=(65280,48896,32768)
1359 
1360  GroupBox gb_preview,pos={472,4},size={250,52},title="preview"
1361  TitleBox tb_preview_file,pos={484,24},size={226,20},frame=2
1362  TitleBox tb_preview_file,variable=root:packages:pearl_explorer:s_preview_file,fixedSize=1
1363 
1364  GroupBox gb_attributes,pos={472,64},size={250,372},title="attributes"
1365  Button b_attr_notebook,pos={484,386},size={60,20},proc=PearlDataExplorer#bp_attr_notebook,title="notebook"
1366  Button b_attr_notebook,help={"show attribute list in a notebook"}
1367  Button b_attr_notebook,fColor=(65280,48896,32768)
1368 
1369  String fldrSav0= GetDataFolder(1)
1370  SetDataFolder root:packages:pearl_explorer:
1371  Edit/W=(484,84,710,384)/HOST=# attr_names,attr_values
1372  ModifyTable format(Point)=1,width(Point)=0,width(attr_names)=103,width(attr_values)=103
1373  ModifyTable statsArea=85
1374  SetDataFolder fldrSav0
1375  RenameWindow #,T0
1376  SetActiveSubwindow ##
1377 };
1378 
1379 static variable bp_load_prefs(WMButtonAction* ba){
1380  STRUCT WMButtonAction &ba
1381 
1382  switch( ba.eventCode )
1383  case 2:// mouse up
1384  load_prefs()
1385  break
1386  case -1:// control being killed
1387  break
1388  endswitch
1389 
1390  return 0
1391 };
1392 
1393 static variable bp_save_prefs(WMButtonAction* ba){
1394  STRUCT WMButtonAction &ba
1395 
1396  switch( ba.eventCode )
1397  case 2:// mouse up
1398  save_prefs()
1399  break
1400  case -1:// control being killed
1401  break
1402  endswitch
1403 
1404  return 0
1405 };
1406 
1407 static variable bp_browse_filepath(WMButtonAction* ba){
1408  STRUCT WMButtonAction &ba
1409 
1410  dfref saveDF = GetDataFolderDFR()
1411 
1412  switch( ba.eventCode )
1413  case 2:// mouse up
1414  PathInfo /S pearl_explorer_filepath
1415  NewPath /M="select data file folder" /O/Z pearl_explorer_filepath
1416  if (v_flag == 0)
1417  PathInfo /S pearl_explorer_filepath
1418  svar filepath = $(package_path + "s_filepath")
1419  filepath = s_path
1420  update_filelist()
1421  endif
1422  break
1423  case -1:// control being killed
1424  break
1425  endswitch
1426 
1427  setdatafolder saveDF
1428  return 0
1429 };
1430 
1431 static variable bp_update_filelist(WMButtonAction* ba){
1432  STRUCT WMButtonAction &ba
1433 
1434  switch( ba.eventCode )
1435  case 2:// mouse up
1436  update_filelist()
1437  break
1438  case -1:// control being killed
1439  break
1440  endswitch
1441 
1442  return 0
1443 };
1444 
1445 static variable bp_load_files(WMButtonAction* ba){
1446  STRUCT WMButtonAction &ba
1447 
1448  switch( ba.eventCode )
1449  case 2:// mouse up
1451  break
1452  case -1:// control being killed
1453  break
1454  endswitch
1455 
1456  return 0
1457 };
1458 
1459 static variable bp_load_files_opt(WMButtonAction* ba){
1460  STRUCT WMButtonAction &ba
1461 
1462  switch( ba.eventCode )
1463  case 2:// mouse up
1464  load_selected_files(options="")
1465  break
1466  case -1:// control being killed
1467  break
1468  endswitch
1469 
1470  return 0
1471 };
1472 
1473 static variable bp_file_next(WMButtonAction* ba){
1474  STRUCT WMButtonAction &ba
1475 
1476  dfref saveDF = GetDataFolderDFR()
1477 
1478  switch( ba.eventCode )
1479  case 2:// mouse up
1480  setdatafolder $package_path
1481  wave /t wtFiles
1482  wave wSelectedFiles
1483  FindValue /i=1 wSelectedFiles
1484  v_value += 1
1485  if (v_value >= numpnts(wtFiles))
1486  v_value = min(numpnts(wtFiles) - 1, 0)
1487  endif
1488  wSelectedFiles = p == v_value
1489  if (v_value >= 0)
1490  variable ifile = v_value
1491  ControlInfo /W=PearlDataExplorer cb_file_preview
1492  if (v_value)
1493  preview_file(wtFiles[ifile])
1494  endif
1495  endif
1496  break
1497  case -1:// control being killed
1498  break
1499  endswitch
1500 
1501  setdatafolder saveDF
1502  return 0
1503 };
1504 
1505 static variable bp_file_prev(WMButtonAction* ba){
1506  STRUCT WMButtonAction &ba
1507 
1508  dfref saveDF = GetDataFolderDFR()
1509 
1510  switch( ba.eventCode )
1511  case 2:// mouse up
1512  setdatafolder $package_path
1513  wave /t wtFiles
1514  wave wSelectedFiles
1515  FindValue /i=1 wSelectedFiles
1516  v_value -= 1
1517  if (v_value < 0)
1518  v_value = numpnts(wtFiles) - 1
1519  endif
1520  wSelectedFiles = p == v_value
1521  if (v_value >= 0)
1522  variable ifile = v_value
1523  ControlInfo /W=PearlDataExplorer cb_file_preview
1524  if (v_value)
1525  preview_file(wtFiles[ifile])
1526  endif
1527  endif
1528  break
1529  case -1:// control being killed
1530  break
1531  endswitch
1532 
1533  setdatafolder saveDF
1534  return 0
1535 };
1536 
1537 static variable lbp_filelist(WMListboxAction* lba){
1538  STRUCT WMListboxAction &lba
1539 
1540  Variable row = lba.row
1541  Variable col = lba.col
1542  WAVE/T/Z listWave = lba.listWave
1543  WAVE/Z selWave = lba.selWave
1544 
1545  switch( lba.eventCode )
1546  case -1:// control being killed
1547  break
1548  case 1:// mouse down
1549  if (selWave[row])
1550  ControlInfo /W=PearlDataExplorer cb_file_preview
1551  if (v_value)
1552  preview_file(listWave[row])
1553  endif
1554  endif
1555  break
1556  case 3:// double click
1557  break
1558  case 4:// cell selection
1559  case 5:// cell selection plus shift key
1560  break
1561  case 6:// begin edit
1562  break
1563  case 7:// finish edit
1564  break
1565  case 13:// checkbox clicked (Igor 6.2 or later)
1566  break
1567  endswitch
1568 
1569  return 0
1570 };
1571 
1572 static variable bp_update_datasets(WMButtonAction* ba){
1573  STRUCT WMButtonAction &ba
1574 
1575  switch( ba.eventCode )
1576  case 2:// mouse up
1577  update_datasets()
1578  break
1579  case -1:// control being killed
1580  break
1581  endswitch
1582 
1583  return 0
1584 };
1585 
1586 static variable bp_dataset_folder(WMButtonAction* ba){
1587  STRUCT WMButtonAction &ba
1588 
1589  switch( ba.eventCode )
1590  case 2:// mouse up
1591  ControlInfo /W=PearlDataExplorer lb_datasets
1592  if (v_value >= 0)
1593  setdatafolder $package_path
1594  wave /t wtDatasets
1595  string dataset = wtDatasets[v_value]
1596  string cmd
1597  sprintf cmd, "setdatafolder root:%s", PossiblyQuoteName(dataset)
1598  execute /q /z cmd
1599  cmd = "setdatafolder :scan1"
1600  execute /q /z cmd
1601  sprintf cmd, "setdatafolder %s", GetDataFolder(1)
1602  print cmd
1603  endif
1604  break
1605  case -1:// control being killed
1606  break
1607  endswitch
1608 
1609  return 0
1610 };
1611 
1612 static variable bp_dataset_display(WMButtonAction* ba){
1613  STRUCT WMButtonAction &ba
1614 
1615  switch( ba.eventCode )
1616  case 2:// mouse up
1617  ControlInfo /W=PearlDataExplorer lb_datasets
1618  if (v_value >= 0)
1619  setdatafolder $package_path
1620  wave /t wtDatasets
1621  string dataset = wtDatasets[v_value]
1622  display_dataset(dataset)
1623  endif
1624  break
1625  case -1:// control being killed
1626  break
1627  endswitch
1628 
1629  return 0
1630 };
1631 
1632 static variable bp_dataset_next(WMButtonAction* ba){
1633  STRUCT WMButtonAction &ba
1634 
1635  switch( ba.eventCode )
1636  case 2:// mouse up
1637  ControlInfo /W=PearlDataExplorer lb_datasets
1638  wave /t wtDatasets = $(s_datafolder + s_value)
1639  v_value += 1
1640  if (v_value >= numpnts(wtDatasets))
1641  v_value = min(0, numpnts(wtDatasets) - 1)
1642  endif
1643  ListBox lb_datasets win=PearlDataExplorer, selRow=v_value
1644  if (v_value >= 0)
1645  variable ids = v_value
1646  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1647  if (v_value)
1648  preview_dataset(wtDatasets[ids])
1649  endif
1650  endif
1651  break
1652  case -1:// control being killed
1653  break
1654  endswitch
1655 
1656  return 0
1657 };
1658 
1659 static variable bp_dataset_prev(WMButtonAction* ba){
1660  STRUCT WMButtonAction &ba
1661 
1662  switch( ba.eventCode )
1663  case 2:// mouse up
1664  ControlInfo /W=PearlDataExplorer lb_datasets
1665  wave /t wtDatasets = $(s_datafolder + s_value)
1666  v_value -= 1
1667  if (v_value < 0)
1668  v_value = max(-1, numpnts(wtDatasets) - 1)
1669  endif
1670  ListBox lb_datasets win=PearlDataExplorer, selRow=v_value
1671  if (v_value >= 0)
1672  variable ids = v_value
1673  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1674  if (v_value)
1675  preview_dataset(wtDatasets[ids])
1676  endif
1677  endif
1678  break
1679  case -1:// control being killed
1680  break
1681  endswitch
1682 
1683  return 0
1684 };
1685 
1686 static variable lbp_datasets(WMListboxAction* lba){
1687  STRUCT WMListboxAction &lba
1688 
1689  Variable row = lba.row
1690  Variable col = lba.col
1691  WAVE/T/Z listWave = lba.listWave
1692  WAVE/Z selWave = lba.selWave
1693 
1694  switch( lba.eventCode )
1695  case -1:// control being killed
1696  break
1697  case 1:// mouse down
1698  if (row >= 0)
1699  ControlInfo /W=PearlDataExplorer cb_dataset_preview
1700  if (v_value)
1701  preview_dataset(listWave[row])
1702  endif
1703  endif
1704  break
1705  case 3:// double click
1706  break
1707  case 4:// cell selection
1708  case 5:// cell selection plus shift key
1709  break
1710  case 6:// begin edit
1711  break
1712  case 7:// finish edit
1713  break
1714  case 13:// checkbox clicked (Igor 6.2 or later)
1715  break
1716  endswitch
1717 
1718  return 0
1719 };
1720 
1721 static variable bp_attr_notebook(WMButtonAction* ba){
1722  STRUCT WMButtonAction &ba
1723 
1724  dfref saveDF = GetDataFolderDFR()
1725 
1726  switch( ba.eventCode )
1727  case 2:// mouse up
1728  setdatafolder $package_path
1729  svar s_preview_file
1730  wave /t /z attr_names
1731  wave /t /z attr_values
1732  if (WaveExists(attr_names))
1733  attributes_notebook(attr_names, attr_values, s_preview_file)
1734  endif
1735  break
1736  case -1:// control being killed
1737  break
1738  endswitch
1739 
1740  setdatafolder saveDF
1741  return 0
1742 };
1743 
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 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.
static variable update_datasets()
-
static variable bp_browse_filepath(WMButtonAction *ba)
+
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.
+
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.
-
static variable bp_dataset_prev(WMButtonAction *ba)
-
static string display_preview_trace(wave xtrace, wave ytrace)
-
static variable bp_file_prev(WMButtonAction *ba)
+
static variable bp_dataset_prev(WMButtonAction *ba)
+
static string display_preview_trace(wave xtrace, wave ytrace)
+
static variable bp_file_prev(WMButtonAction *ba)
variable ad_brick_slicer(wave data)
open a slicer panel for 3D data.
-
static variable lbp_datasets(WMListboxAction *lba)
-
void PearlDataExplorer()
-
static variable bp_load_files_opt(WMButtonAction *ba)
-
static variable load_selected_files(string options=defaultValue)
-
static variable bp_load_files(WMButtonAction *ba)
-
static variable preview_datafolder()
-
static variable bp_file_next(WMButtonAction *ba)
-
static variable lbp_filelist(WMListboxAction *lba)
-
static variable prompt_hdf_options(string *options)
-
static variable bp_update_datasets(WMButtonAction *ba)
+
static variable lbp_datasets(WMListboxAction *lba)
+
void PearlDataExplorer()
+
static variable bp_load_files_opt(WMButtonAction *ba)
+
static variable load_selected_files(string options=defaultValue)
+
static variable bp_load_files(WMButtonAction *ba)
+
static variable preview_datafolder()
+
static variable bp_file_next(WMButtonAction *ba)
+
static variable lbp_filelist(WMListboxAction *lba)
+
static variable prompt_hdf_options(string *options)
+
static variable bp_update_datasets(WMButtonAction *ba)
static const string ks_filematch_pshell
static const string ks_filematch_adh5
-
static wave preview_mtrx_file(string filename)
load the preview of a Matrix STM file.
-
string psh5_load_preview(string ANickName, 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 wave preview_mtrx_file(string filename)
load the preview of a Matrix STM file.
static variable init_package()
initialize the global variables of the data explorer.
static wave preview_pshell_file(string filename)
load the preview of a PShell HDF5 file.
-
static variable bp_dataset_folder(WMButtonAction *ba)
-
static variable preview_dataset(string datasetname)
+
static variable bp_dataset_folder(WMButtonAction *ba)
+
static variable preview_dataset(string datasetname)
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)
-
static variable bp_attr_notebook(WMButtonAction *ba)
-
static variable load_file(string filename, string options=defaultValue)
+
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.
+
static variable bp_attr_notebook(WMButtonAction *ba)
+
static variable load_file(string filename, string options=defaultValue)
preview and import panel for PEARL data
-
static variable bp_load_prefs(WMButtonAction *ba)
-
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)
+
static variable bp_load_prefs(WMButtonAction *ba)
+
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.
-
static wave preview_hdf_file(string filename)
load the preview of a PEARL HDF5 file.
+
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 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.
-
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.
+
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 ad_display_profiles(wave image, string filter=defaultValue)
open a new profiles graph window.
-
static variable bp_update_filelist(WMButtonAction *ba)
+
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 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.
static variable load_prefs()
-
variable prompt_func_params(string func_name, string *func_param)
-
static wave preview_itx_file(string filename)
-
static variable display_dataset(string datasetname)
-
static dfr load_pshell_file(string filename, string options=defaultValue)
+
variable prompt_func_params(string func_name, string *func_param)
+
static wave preview_itx_file(string filename)
+
static variable display_dataset(string datasetname)
+
static dfr load_pshell_file(string filename, string options=defaultValue)
static variable save_prefs()
-
variable test_attributes_notebook()
-
static string show_preview_graph(wave data, wave xdata=defaultValue)
+
variable test_attributes_notebook()
+
static string show_preview_graph(wave data, wave xdata=defaultValue)
string mtrx_load_preview(string destName, string pathName, string fileName, string traces=defaultValue)
load a preview image from a Matrix data file.
string ad_display_slice(wave data)
display three-dimensional data by 2D slice.
static const string ks_filematch_mtrx
-
static variable attributes_notebook(wave attr_names, wave attr_values, string title)
+
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)
+
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.
-
static variable notebook_add_attributes(string notebook_name, wave attr_filter, wave attr_names, wave attr_values)
+
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',
-

Definition at line 1558 of file pearl-elog.ipf.

+

Definition at line 1634 of file pearl-elog.ipf.

@@ -450,7 +453,7 @@ Variables

select/deselect all graph windows for attachment

-

Definition at line 1537 of file pearl-elog.ipf.

+

Definition at line 1613 of file pearl-elog.ipf.

@@ -478,7 +481,7 @@ Variables

select top graph window for attachment

-

Definition at line 1521 of file pearl-elog.ipf.

+

Definition at line 1597 of file pearl-elog.ipf.

@@ -506,7 +509,7 @@ Variables

button procedure for the attachment up and down buttons

-

Definition at line 1442 of file pearl-elog.ipf.

+

Definition at line 1518 of file pearl-elog.ipf.

@@ -532,7 +535,7 @@ Variables
-

Definition at line 1619 of file pearl-elog.ipf.

+

Definition at line 1695 of file pearl-elog.ipf.

@@ -558,7 +561,7 @@ Variables
-

Definition at line 1635 of file pearl-elog.ipf.

+

Definition at line 1711 of file pearl-elog.ipf.

@@ -584,7 +587,7 @@ Variables
-

Definition at line 1653 of file pearl-elog.ipf.

+

Definition at line 1729 of file pearl-elog.ipf.

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

Definition at line 1591 of file pearl-elog.ipf.

+

Definition at line 1667 of file pearl-elog.ipf.

@@ -638,7 +641,7 @@ Variables

button procedure for the Submit and Reply buttons

-

Definition at line 1474 of file pearl-elog.ipf.

+

Definition at line 1550 of file pearl-elog.ipf.

@@ -664,10 +667,10 @@ Variables

delete temporary files created by the ELOG module.

-

this deletes all temporary graph files that are referenced by the volatile temp_graph_files list. temp_graph_files is a semicolon-delimited string. items are added by create_graph_file().

+

this deletes all temporary graph files that are referenced by the volatile temp_graph_files list. temp_graph_files is a semicolon-delimited string. items are added by create_graph_file().

this function should be called before a new experiment is loaded or igor quits.

-

Definition at line 1039 of file pearl-elog.ipf.

+

Definition at line 1115 of file pearl-elog.ipf.

@@ -693,7 +696,11 @@ Variables
-

Definition at line 1001 of file pearl-elog.ipf.

+

write the command line to a file.

+

the command script changes the working directory to the Temporary directory. it also deletes a previous elog.log file.

+
Note
somewhere the command line (even inside command files) is limited to 1024 bytes. for this reason all files should now be in the Temporary directory assigned by igor.
+ +

Definition at line 1059 of file pearl-elog.ipf.

@@ -729,7 +736,20 @@ Variables
-

Definition at line 976 of file pearl-elog.ipf.

+

save a graph to a temporary graphics file

+

the file is saved to the Temporary directory returned by igor's SpecialDirPath function. the file name contains a time stamp and the specified file index to make it unique. the function returns the name of the file (excluding path!)

+

the full path is added to the temp_graph_files global list. a hook function will delete the files listed there when igor quits.

+
Parameters
+ + + +
graphnameobject name of the graph to save.
fileindexincrememtal index of the file within one submission. the file name is made unique by a time stamp and this file index. submissions within the same second must have a unique file index.
+
+
+
Returns
(string) name of the created file. empty string if unsuccessful.
+
Version
1.41 the return value has changed from full path to file name only due to the limited length of the command line (1024 bytes).
+ +

Definition at line 1023 of file pearl-elog.ipf.

@@ -755,7 +775,19 @@ Variables
-

Definition at line 957 of file pearl-elog.ipf.

+

save the message to a temporary text file

+

the file is saved to the Temporary directory returned by igor's SpecialDirPath function under the file name "elog_temp_message.txt". the function returns the name of the file (excluding path!)

+
Note
percent characters (%) cannot be passed to elog. they are removed silently from the message.
+
Parameters
+ + +
messagetext message to save to the file.
+
+
+
Returns
(string) name of the created file. empty string if unsuccessful.
+
Version
1.41 the return value has changed from full path to file name only due to the limited length of the command line (1024 bytes).
+ +

Definition at line 982 of file pearl-elog.ipf.

@@ -800,7 +832,7 @@ Variables
Warning
this will delete all existing attachments of the entry!
-

Definition at line 788 of file pearl-elog.ipf.

+

Definition at line 792 of file pearl-elog.ipf.

@@ -1072,7 +1104,7 @@ Variables
-

Definition at line 1318 of file pearl-elog.ipf.

+

Definition at line 1394 of file pearl-elog.ipf.

@@ -1091,7 +1123,7 @@ Variables

prompt to open or create a logbook

-

Definition at line 1108 of file pearl-elog.ipf.

+

Definition at line 1184 of file pearl-elog.ipf.

@@ -1111,7 +1143,7 @@ Variables

prompt the user for login to a logbook

-

Definition at line 1138 of file pearl-elog.ipf.

+

Definition at line 1214 of file pearl-elog.ipf.

@@ -1177,7 +1209,7 @@ Variables -

Definition at line 894 of file pearl-elog.ipf.

+

Definition at line 902 of file pearl-elog.ipf.

@@ -1202,7 +1234,7 @@ Variables
-

Definition at line 1670 of file pearl-elog.ipf.

+

Definition at line 1746 of file pearl-elog.ipf.

@@ -1279,7 +1311,7 @@ Variables
-

Definition at line 1019 of file pearl-elog.ipf.

+

Definition at line 1095 of file pearl-elog.ipf.

@@ -1314,7 +1346,7 @@ Variables
Returns
list of attributes to in the format "key1=value1;key2=value2".
-

Definition at line 1683 of file pearl-elog.ipf.

+

Definition at line 1759 of file pearl-elog.ipf.

@@ -1349,7 +1381,7 @@ Variables
Returns
a semicolon-separated list, or the empty string if the selection is not valid.
-

Definition at line 1838 of file pearl-elog.ipf.

+

Definition at line 1914 of file pearl-elog.ipf.

@@ -1384,7 +1416,7 @@ Variables
Returns
message text
-

Definition at line 1792 of file pearl-elog.ipf.

+

Definition at line 1868 of file pearl-elog.ipf.

@@ -1410,7 +1442,7 @@ Variables
-

Definition at line 949 of file pearl-elog.ipf.

+

Definition at line 958 of file pearl-elog.ipf.

@@ -1642,7 +1674,7 @@ Variables

move an attachment item in the list of attachments

-

Definition at line 1418 of file pearl-elog.ipf.

+

Definition at line 1494 of file pearl-elog.ipf.

@@ -1670,7 +1702,7 @@ Variables

parse the result file from an elog invokation.

Returns
the ID of the generated message, or a value <= 0 if an error occurred.
-

Definition at line 1065 of file pearl-elog.ipf.

+

Definition at line 1141 of file pearl-elog.ipf.

@@ -1724,7 +1756,7 @@ Variables -

Definition at line 1165 of file pearl-elog.ipf.

+

Definition at line 1241 of file pearl-elog.ipf.

@@ -1759,7 +1791,7 @@ Variables -

Definition at line 845 of file pearl-elog.ipf.

+

Definition at line 853 of file pearl-elog.ipf.

@@ -1786,7 +1818,7 @@ Variables

prepare screenshots of graph windows for attachments

-

prepares the attachment files from Igor graph windows and returns the arguments to the elog command to attach the files. the result string does not include leading or trailing space

+

prepares the attachment files from Igor graph windows and returns the arguments to the elog command to attach the files. file names are returned without path. the result string does not include leading or trailing space.

Parameters
@@ -1794,7 +1826,7 @@ Variables -

Definition at line 930 of file pearl-elog.ipf.

+

Definition at line 939 of file pearl-elog.ipf.

@@ -1878,7 +1910,7 @@ Variables -

Definition at line 1730 of file pearl-elog.ipf.

+

Definition at line 1806 of file pearl-elog.ipf.

@@ -1923,7 +1955,7 @@ Variables -

Definition at line 1878 of file pearl-elog.ipf.

+

Definition at line 1954 of file pearl-elog.ipf.

@@ -1969,7 +2001,7 @@ Variables
Returns
original message (unchanged)
-

Definition at line 1818 of file pearl-elog.ipf.

+

Definition at line 1894 of file pearl-elog.ipf.

@@ -1997,7 +2029,7 @@ Variables

update the list of attachments

-

Definition at line 1357 of file pearl-elog.ipf.

+

Definition at line 1433 of file pearl-elog.ipf.

@@ -2020,7 +2052,7 @@ Variables
graphsnames of graph windows to be added as attachments, semicolon separated
-

Definition at line 1058 of file pearl-elog.ipf.

+

Definition at line 1134 of file pearl-elog.ipf.

@@ -2042,7 +2074,7 @@ Variables
-

Definition at line 1057 of file pearl-elog.ipf.

+

Definition at line 1133 of file pearl-elog.ipf.

@@ -2064,7 +2096,7 @@ Variables
-

Definition at line 1354 of file pearl-elog.ipf.

+

Definition at line 1430 of file pearl-elog.ipf.

@@ -2086,7 +2118,7 @@ Variables
-

Definition at line 1352 of file pearl-elog.ipf.

+

Definition at line 1428 of file pearl-elog.ipf.

@@ -2108,7 +2140,7 @@ Variables
-

Definition at line 1353 of file pearl-elog.ipf.

+

Definition at line 1429 of file pearl-elog.ipf.

@@ -2250,7 +2282,7 @@ Variables
-Go to the documentation of this file.
1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
2 #pragma version = 1.40
3 #pragma IgorVersion = 6.2
4 #pragma ModuleName = PearlElog
5 
6 // author: matthias.muntwiler@psi.ch
7 // Copyright (c) 2013-16 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 
79 
84 
85 static const string package_name = "pearl_elog";
86 static const string package_path = "root:packages:pearl_elog:";
87 
97 variable pearl_elog(string logbook){
98  string logbook
99 
100  if (init_package() == 0)
101  load_prefs()
102  string templates = list_logbooks(templates=1)
103  if (ItemsInList(templates) < 1)
105  endif
106  endif
107 
108  if (strlen(logbook) == 0)
109  logbook = elog_prompt_logbook()
110  endif
111 
112  string win_name = logbook + "ElogPanel"
113  if (strlen(logbook) > 0)
114  if (strlen(WinList(win_name, ";", "")) > 0)
115  DoWindow /F $win_name
116  else
117  win_name = PearlElogPanel(logbook)
118  STRUCT WMWinHookStruct s
119  s.eventCode = 0
120  s.winName = win_name
121  elog_panel_hook(s)
122  endif
123  endif
124 };
125 
127 static variable IgorBeforeNewHook(string igorApplicationNameStr){
128  string igorApplicationNameStr
129  save_prefs()
131  return 0
132 };
133 
135 static variable IgorQuitHook(string igorApplicationNameStr){
136  string igorApplicationNameStr
137  save_prefs()
139  return 0
140 };
141 
143 static variable AfterFileOpenHook(variable refNum, string file, string pathName, string type, string creator, variable kind){
144  Variable refNum,kind
145  String file,pathName,type,creator
146  if( (kind >= 1) && (kind <= 2))
147  init_package(clean=1)
148  load_prefs()
149  endif
150  return 0
151 };
152 
153 static const variable kdfRoot = 0;
154 static const variable kdfVolatile = 1;
155 static const variable kdfPersistent = 2;
156 static const variable kdfTemplates = 3;
157 
170 static dfr get_elog_df(string name, variable category){
171  string name
172  variable category
173 
174  dfref df_package = $package_path
175  dfref df_persistent = df_package:persistent
176  dfref df_volatile = df_package:volatile
177 
178  switch(category)
179  case kdfRoot:
180  dfref df_parent = df_package
181  break
182  case kdfPersistent:
183  dfref df_parent = df_persistent
184  break
185  case kdfTemplates:
186  dfref df_parent = df_persistent:templates
187  break
188  case kdfVolatile:
189  dfref df_parent = df_volatile
190  break
191  default:
192  Abort "get_elog_df: undefined data folder category."
193  endswitch
194 
195  if ((strlen(name) > 0) && (category >= 1))
196  if (category == kdfTemplates)
197  dfref df_logbooks = df_parent
198  else
199  dfref df_logbooks = df_parent:logbooks
200  endif
201  dfref df_logbook = df_logbooks:$name
202  return df_logbook
203  else
204  return df_parent
205  endif
206 };
207 
217 static variable init_package(variable clean = defaultValue){
218  variable clean
219 
220  if (ParamIsDefault(clean))
221  clean = 0
222  endif
223 
224  dfref savedf = getdatafolderdfr()
225  dfref df_root = get_elog_df("", kdfRoot)
226  if ((clean == 0) && (DataFolderRefStatus(df_root) == 1))
227  return 1
228  endif
229 
230  setdatafolder root:
231  newdatafolder /o/s packages
232  newdatafolder /o/s $package_name
233  dfref df_package_root = getdatafolderdfr()
234  newdatafolder /o/s volatile
235  dfref df_volatile = getdatafolderdfr()
236  newdatafolder /o logbooks
237  setdatafolder df_package_root
238  newdatafolder /o/s persistent
239  dfref df_persistent = getdatafolderdfr()
240  newdatafolder /o logbooks
241  newdatafolder /o templates
242 
243  // common configuration
244  setdatafolder df_persistent
245  string /g elog_path = "c:\\program files (x86)\\ELOG\\elog.exe"
246  string /g hostname = "localhost"
247  variable /g port = 0// 0 = unspecified (default)
248  variable /g ssl = 0// 0 = plain text (incl. passwords), 1 = secure connection
249  string /g subdir = ""
250  variable /g loglevel = 3
251 
252  setdatafolder savedf
253  return 0
254 };
255 
263  dfref savedf = getdatafolderdfr()
264 
265  dfref df_root = get_elog_df("", kdfRoot)
266  dfref df_persistent = get_elog_df("", kdfPersistent)
267  dfref df_templates = get_elog_df("", kdfTemplates)
268 
269  // Experiments template
270  setdatafolder df_templates
271  newdatafolder /o/s Experiments
272 
273  // attributes (persistent)
274  // available attributes
275  string /g attributes = "author;project;sample;source;task;technique;file;valid;"
276  // controls corresponding to attributes
277  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
278  string /g controls = "sv_author;sv_project;sv_sample;pm_source;pm_task;pm_technique;sv_file;cb_valid;"
279  // attributes with fixed options, value item declares the options string
280  string /g options = "source=sources;task=tasks;technique=techniques"
281  // attributes which must be defined
282  string /g required_attributes = "author;project;sample;source;task;technique;valid"
283 
284  // option lists
285  string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
286  string /g tasks = "Measurement;Optimization;Analysis;Sample Preparation;Sample Storage;Comment;Development;Maintenance;Test;Other"
287  string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;STM;STS;LEED;AES;QMS;MBE;Sputter/Anneal;Test;Other"
288 
289  // Calculations template
290  setdatafolder df_templates
291  newdatafolder /o/s Calculations
292 
293  // attributes (persistent)
294  // available attributes
295  string /g attributes = "author;project;sample;program;revision;machine;job;experiment;source path;result path;valid"
296  // controls corresponding to attributes
297  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
298  string /g controls = "sv_author;sv_project;sv_sample;pm_program;sv_revision;pm_machine;sv_job;sv_experiment;sv_sourcepath;sv_resultpath;cb_valid"
299  // attributes with fixed options, value item declares the options string
300  string /g options = "program=programs;machine=machines"
301  // attributes which must be defined
302  string /g required_attributes = "author;project;sample"
303 
304  // option lists
305  string /g programs = "PMSCO;EDAC;MSC;SSC;MUFPOT;DMSUP;Other"
306  string /g machines = "PC;VM;Ra;Merlin;llcx;Other"
307 
308  // System template
309  setdatafolder df_templates
310  newdatafolder /o/s System
311 
312  // attributes (persistent)
313  // available attributes
314  string /g attributes = "author;type;system;source;file"
315  // controls corresponding to attributes
316  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
317  string /g controls = "sv_author;pm_type;pm_system;pm_source;sv_file"
318  // attributes with fixed options, value item declares the options string
319  string /g options = "type=types;system=systems;source=sources"
320  // attributes which must be defined
321  string /g required_attributes = "author;type;system"
322 
323  // option lists
324  string /g types = "Installation;Repair;Maintenance;Test;Commissioning;Bakeout;Incident;Cool-down;Warm-up;Storage;Other"
325  string /g systems = "Vacuum;Control System;BL;XA;XP;SA;SP;T;LL;Monochromator;Carving;Scienta;STM;PC-Scienta;PC-Matrix;PC-Console;PC-Console-Win;PC-XP;EPS;LAC;Desiccator"
326  string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
327 
328  setdatafolder savedf
329  return 0
330 };
331 
340 static variable init_volatile_vars(){
341  dfref savedf = GetDataFolderDFR()
342 
343  dfref df_volatile_root = get_elog_df("", kdfVolatile)
344  dfref df_volatile_parent = df_volatile_root:logbooks
345 
346  string logbooks = list_logbooks()
347  string logbook
348  variable nlb = ItemsInList(logbooks)
349  variable ilb
350 
351  SetDataFolder df_volatile_root
352  if (exists("temp_graph_files") != 2)
353  string /g temp_graph_files = ""
354  endif
355 
356  for (ilb = 0; ilb < nlb; ilb += 1)
357  logbook = StringFromList(ilb, logbooks)
358 
359  SetDataFolder df_volatile_parent
360  if (DataFolderExists(logbook))
361  SetDataFolder $logbook
362  else
363  NewDataFolder /o/s $logbook
364  endif
365 
366  if (exists("username") != 2)
367  string /g username = ""
368  endif
369  if (exists("password") != 2)
370  string /g password = ""
371  endif
372  if (exists("msg_id") != 2)
373  variable /g msg_id = 0
374  endif
375  if (exists("att_list") != 1)
376  make /n=(0,3) /t /o attach_list
377  make /n=(0,3) /i /o attach_sel
378  endif
379  if (exists("url") != 2)
380  string /g url = ""
381  endif
382  endfor
383 
384  SetDataFolder savedf
385  return 0
386 };
387 
401 
414 variable elog_create_logbook(string name, string template = defaultValue){
415  string name
416  string template
417 
418  if (ParamIsDefault(template))
419  template = ""
420  endif
421 
422  dfref savedf = getdatafolderdfr()
423  dfref df_root = get_elog_df("", kdfRoot)
424  dfref df_persistent_root = get_elog_df("", kdfPersistent)
425  dfref df_persistent_parent = df_persistent_root:logbooks
426  dfref df_volatile_root = get_elog_df("", kdfVolatile)
427  dfref df_volatile_parent = df_volatile_root:logbooks
428 
429  setdatafolder df_persistent_parent
430  if (CheckName(name, 11) != 0)
431  setdatafolder savedf
432  Abort "invalid logbook name"
433  return -1
434  endif
435 
436  if (strlen(template) > 0)
437  dfref df_template = get_elog_df(template, kdfTemplates)
438  dfref df_existing = get_elog_df(name, kdfPersistent)
439  if (DataFolderRefStatus(df_existing))
440  KillDataFolder /Z df_existing
441  endif
442  DuplicateDataFolder df_template, df_persistent_parent:$name
443  else
444  NewDataFolder /o/s df_persistent_parent:$name
445 
446  // ELOG logbook name
447  string /g logbook = name
448  // attributes (persistent)
449  // available attributes
450  string /g attributes = ""
451  // controls corresponding to attributes
452  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
453  string /g controls = ""
454  // attributes with fixed options, value item declares the options string
455  string /g options = ""
456  // attributes which must be defined
457  string /g required_attributes = ""
458  endif
459 
460  // usage data (persistent)
461  setdatafolder get_elog_df(name, kdfPersistent)
462  string /g recent = ""
463  string /g recent_message = ""
464 
466 
467  setdatafolder savedf
468  return 0
469 };
470 
473 variable elog_config(string elog_path = defaultValue, string hostname = defaultValue, variable port = defaultValue, string subdir = defaultValue){
474  string elog_path
475  string hostname
476  variable port
477  string subdir
478 
479  dfref df = get_elog_df("", kdfPersistent)
480 
481  if (!ParamIsDefault(elog_path))
482  svar /sdfr=df g_elog_path = elog_path
483  g_elog_path = elog_path
484  endif
485  if (!ParamIsDefault(hostname))
486  svar /sdfr=df g_hostname = hostname
487  g_hostname = hostname
488  endif
489  if (!ParamIsDefault(port))
490  nvar /sdfr=df g_port = port
491  g_port = port
492  endif
493  if (!ParamIsDefault(subdir))
494  svar /sdfr=df g_subdir = subdir
495  g_subdir = subdir
496  endif
497 };
498 
513 variable elog_login(string logbook, string username, string password){
514  string logbook
515  string username
516  string password
517 
518  dfref df = get_elog_df(logbook, kdfVolatile)
519  svar /sdfr=df g_username=username
520  svar /sdfr=df g_password=password
521  g_username = username
522  g_password = password
523 };
524 
533 variable elog_logout(string logbook){
534  string logbook
535 
536  dfref df = get_elog_df(logbook, kdfVolatile)
537  if (strlen(logbook) > 0)
538  svar /z /sdfr=df g_username=username
539  svar /z /sdfr=df g_password=password
540  if (svar_exists(g_username))
541  g_username = ""
542  endif
543  if (svar_exists(g_password))
544  g_password = ""
545  endif
546  else
547  dfref df2 = df:logbooks
548  variable nlb = CountObjectsDFR(df2, 4)
549  variable ilb
550  string slb
551  for (ilb = 0; ilb < nlb; ilb += 1)
552  slb = GetIndexedObjNameDFR(df2, 4, ilb)
553  if (strlen(slb) > 0)
554  elog_logout(slb)
555  endif
556  endfor
557  endif
558 };
559 
564 static variable save_prefs(){
565  dfref saveDF = GetDataFolderDFR()
566 
567  dfref df = get_elog_df("", kdfPersistent)
568  if (DataFolderRefStatus(df) == 1)
569  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
570  fullPath += package_name
571  NewPath/O/C/Q tempPackagePrefsPath, fullPath
572  fullPath += ":preferences.pxp"
573  SetDataFolder df
574  SaveData /O /Q /R fullPath
575  KillPath/Z tempPackagePrefsPath
576  endif
577 
578  SetDataFolder saveDF
579 };
580 
584 static variable load_prefs(){
585  dfref saveDF = GetDataFolderDFR()
586 
587  variable result = -1
588  init_package()
589  setdatafolder get_elog_df("", kdfPersistent)
590 
591  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
592  fullPath += package_name
593 
594  GetFileFolderInfo /Q /Z fullPath
595  if (V_Flag == 0)// Disk directory exists?
596  fullPath += ":preferences.pxp"
597  GetFileFolderInfo /Q /Z fullPath
598  if (V_Flag == 0)// Preference file exist?
599  LoadData /O /R /Q fullPath
601  result = 0
602  endif
603  endif
604 
605  SetDataFolder saveDF
606  return result
607 };
608 
618 static string list_logbooks(variable templates = defaultValue){
619  variable templates
620 
621  if (ParamIsDefault(templates))
622  templates = 0
623  endif
624 
625  dfref df_persistent = get_elog_df("", kdfPersistent)
626  if (templates)
627  dfref df_logbooks = df_persistent:templates
628  else
629  dfref df_logbooks = df_persistent:logbooks
630  endif
631  string logbooks = ""
632 
633  variable nlb = CountObjectsDFR(df_logbooks, 4)
634  variable ilb
635  string slb
636  for (ilb = 0; ilb < nlb; ilb += 1)
637  slb = GetIndexedObjNameDFR(df_logbooks, 4, ilb)
638  if (strlen(slb) > 0)
639  logbooks = AddListItem(slb, logbooks)
640  endif
641  endfor
642 
643  return SortList(logbooks, ";", 16)
644 };
645 
653 variable elog_validate_attributes(string logbook, string attributes){
654 
655  string logbook// name of the logbook (as in igor folder name)
656  string attributes// key=value list of attributes, semicolon separated
657 
658  variable result = 0
659  return result
660 };
661 
685 variable elog_create_entry(string logbook, string attributes, string message, variable encoding = defaultValue, string graphs = defaultValue, variable replyto = defaultValue){
686  string logbook
687  string attributes
688  string message
689  variable encoding
690  string graphs
691  variable replyto
692 
693  if (ParamIsDefault(encoding))
694  encoding = 1
695  endif
696  if (ParamIsDefault(graphs))
697  graphs = ""
698  endif
699  if (ParamIsDefault(replyto))
700  replyto = 0
701  endif
702 
703  dfref savedf = getdatafolderdfr()
704  dfref df_general = get_elog_df("", kdfPersistent)
705  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
706 
707  variable result = 0
708  nvar /sdfr=df_volatile msg_id
709  nvar /sdfr=df_general loglevel
710 
711  if (elog_validate_attributes(logbook,attributes) != 0)
712  if (loglevel >= 2)
713  print "ELOG: failed to validate attributes."
714  endif
715  result = -3
716  endif
717 
718  string cmd = prepare_command_line(logbook)
719  if (strlen(cmd) == 0)
720  if (loglevel >= 2)
721  print "ELOG: failed to prepare command line."
722  endif
723  result = -2
724  endif
725 
726  if (replyto >= 1)
727  cmd += " -r " + num2str(replyto)
728  endif
729  cmd += " -n " + num2str(encoding)
730 
731  variable nattr = ItemsInList(attributes, ";")
732  variable iattr
733  string sattr
734  for (iattr = 0; (iattr < nattr) && (result == 0); iattr += 1)
735  sattr = StringFromList(iattr, attributes, ";")
736  if (strlen(StringFromList(1, sattr, "=")) > 0)
737  sattr = ReplaceString("%", sattr, "")
738  cmd += " -a \"" + sattr + "\""
739  endif
740  endfor
741 
742  if (result == 0)
743  string cmd_graphs = prepare_graph_attachments(graphs)
744  cmd += " " + cmd_graphs
745  endif
746 
747  if ((result == 0) && (strlen(message) > 0))
748  string messagefile = create_message_file(message)
749  if (strlen(messagefile) > 0)
750  cmd += " -m \"" + messagefile + "\""
751  cmd += " > \"" + get_log_path() + "\""
752  if (loglevel >= 5)
753  print cmd
754  endif
755  string cmd_file_path = create_cmd_file(cmd)
756  ExecuteScriptText cmd_file_path
757  variable id = parse_result()
758  if (id > 0)
759  msg_id = id
760  if (loglevel >= 4)
761  print "ELOG: sent message " + num2str(id)
762  endif
763  else
764  if (loglevel >= 2)
765  print "ELOG: sending message failed."
766  endif
767  result = -4
768  endif
769  else
770  if (loglevel >= 2)
771  print "ELOG: failed to create temporary message file."
772  endif
773  result = -1
774  endif
775  endif
776 
777  setdatafolder savedf
778  return result
779 };
780 
788 variable elog_add_attachment(string logbook, variable id, string graphs){
789  string logbook
790  variable id// existing entry ID
791  string graphs// names of graph windows to be added as attachments, semicolon separated
792 
793  dfref savedf = getdatafolderdfr()
794  dfref df_general = get_elog_df("", kdfPersistent)
795  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
796 
797  variable result = 0
798  nvar /sdfr=df_volatile msg_id
799  nvar /sdfr=df_general loglevel
800 
801  string cmd = prepare_command_line(logbook)
802  if (strlen(cmd) == 0)
803  result = -2// error: invalid/missing command line
804  endif
805 
806  cmd += " -e " + num2str(id)
807 
808  if (result == 0)
809  string cmd_graphs = prepare_graph_attachments(graphs)
810  if (strlen(cmd_graphs) == 0)
811  result = -3// error: invalid/missing graphs
812  endif
813  endif
814 
815  if (result == 0)
816  cmd += " " + cmd_graphs
817  cmd += " > \"" + get_log_path() + "\""
818  string cmd_file_path = create_cmd_file(cmd)
819  ExecuteScriptText cmd_file_path
820  id = parse_result()
821  if (id > 0)
822  msg_id = id
823  if (loglevel >= 4)
824  print "ELOG: attached graphs to message " + num2str(id)
825  endif
826  else
827  if (loglevel >= 2)
828  print "ELOG: failed to attach graphs."
829  endif
830  result = -4// error: elog returned error
831  endif
832  endif
833 
834  setdatafolder savedf
835  return result
836 };
837 
845 static string prepare_command_line(string logbook){
846  string logbook
847 
848  dfref df_general = get_elog_df("", kdfPersistent)
849  dfref df_persistent = get_elog_df(logbook, kdfPersistent)
850  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
851 
852  svar /sdfr=df_general elog_path
853  svar /sdfr=df_general hostname
854  nvar /sdfr=df_general port
855  nvar /sdfr=df_general ssl
856  svar /sdfr=df_general subdir
857  nvar /sdfr=df_general loglevel
858  svar /sdfr=df_volatile username
859  svar /sdfr=df_volatile password
860 
861  string cmd
862  cmd = "\"" + elog_path + "\""
863  if (loglevel >= 5)
864  cmd += " -v"
865  endif
866  cmd += " -h " + hostname
867  if ((nvar_exists(port)) && (port > 0))
868  cmd += " -p " + num2str(port)
869  endif
870  if ((svar_exists(subdir)) && (strlen(subdir) > 0))
871  cmd += " -d " + subdir
872  endif
873  cmd += " -l \"" + logbook + "\""
874  if ((nvar_exists(ssl)) && (ssl != 0))
875  cmd += " -s"
876  endif
877  //cmd += " -w " + password
878  if (svar_exists(username) && svar_exists(password) && (strlen(username) > 0) && (strlen(password) > 0))
879  cmd += " -u " + username + " " + password
880  endif
881 
882  if (loglevel >= 5)
883  print cmd
884  endif
885 
886  return cmd
887 };
888 
894 static string format_url(string logbook){
895  string logbook
896 
897  dfref df_general = get_elog_df("", kdfPersistent)
898 
899  svar /sdfr=df_general hostname
900  nvar /sdfr=df_general port
901  nvar /sdfr=df_general ssl
902  svar /sdfr=df_general subdir
903 
904  string cmd = ""
905  if ((nvar_exists(ssl)) && (ssl != 0))
906  cmd += "https://"
907  else
908  cmd += "http://"
909  endif
910  cmd += hostname
911  if ((nvar_exists(port)) && (port > 0))
912  cmd += ":" + num2str(port)
913  endif
914  if ((svar_exists(subdir)) && (strlen(subdir) > 0))
915  cmd += "/" + subdir
916  endif
917  cmd += "/" + logbook
918 
919  return cmd
920 };
921 
930 static string prepare_graph_attachments(string graphs){
931  string graphs// names of graph windows to be added as attachments, semicolon separated
932 
933  string cmd = ""
934  variable ngraphs = ItemsInList(graphs, ";")
935  variable igraph
936  string sgraph
937  string graph_path
938  for (igraph = 0; igraph < ngraphs; igraph += 1)
939  sgraph = StringFromList(igraph, graphs, ";")
940  graph_path = create_graph_file(sgraph, igraph)
941  if (strlen(graph_path) > 0)
942  cmd += " -f \"" + graph_path + "\""
943  endif
944  endfor
945 
946  return cmd
947 };
948 
949 static string get_timestamp(string sep){
950  string sep
951  Variable now = DateTime
952  string dat = ReplaceString("-", Secs2Date(DateTime, -2), "")
953  string tim = ReplaceString(":", Secs2Time(DateTime, 3), "")
954  return dat + sep + tim
955 };
956 
957 static string create_message_file(string message){
958  string message
959 
960  message = ReplaceString("%", message, "")
961  string path = SpecialDirPath("Temporary", 0, 1, 0)
962  variable len = strlen(path)
963  if (numtype(len) == 0)
964  path += "elog_temp_message.txt"
965  variable f1
966  Open f1 as path
967  fprintf f1, message
968  Close f1
969  else
970  path = ""
971  endif
972 
973  return path
974 };
975 
976 static string create_graph_file(string graphname, variable fileindex){
977  string graphname
978  variable fileindex
979 
980  dfref df_volatile_root = get_elog_df("", kdfVolatile)
981  svar /sdfr=df_volatile_root temp_graph_files
982 
983  string path = SpecialDirPath("Temporary", 0, 1, 0)
984  string ts = get_timestamp("_")
985  variable len = strlen(path)
986  if (numtype(len) == 0)
987  path += "elog_" + ts + "_" + num2str(fileindex) + ".png"
988  SavePICT /B=72 /E=-5 /M /O /W=(0,0,8,6) /WIN=$graphname /Z as path
989  if (v_flag == 0)
990  temp_graph_files = AddListItem(path, temp_graph_files, ";", inf)
991  else
992  path = ""
993  endif
994  else
995  path = ""
996  endif
997 
998  return path
999 };
1000 
1001 static string create_cmd_file(string cmd){
1002  string cmd
1003 
1004  string path = SpecialDirPath("Temporary", 0, 1, 0)
1005  variable len = strlen(path)
1006  if (numtype(len) == 0)
1007  path += "elog_temp_cmd.bat"
1008  variable f1
1009  Open f1 as path
1010  fprintf f1, cmd
1011  Close f1
1012  else
1013  path = ""
1014  endif
1015 
1016  return path
1017 };
1018 
1019 static string get_log_path(){
1020  string path = SpecialDirPath("Temporary", 0, 1, 0)
1021  variable len = strlen(path)
1022  if (numtype(len) == 0)
1023  path += "elog.log"
1024  else
1025  path = ""
1026  endif
1027 
1028  return path
1029 };
1030 
1039 static variable cleanup_temp_files(){
1040  dfref df_volatile_root = get_elog_df("", kdfVolatile)
1041  if (DataFolderRefStatus(df_volatile_root))
1042  svar /sdfr=df_volatile_root /z temp_graph_files
1043  if (SVAR_Exists(temp_graph_files))
1044  variable nfi = ItemsInList(temp_graph_files)
1045  variable ifi
1046  string sfi
1047  for (ifi = 0; ifi < nfi; ifi += 1)
1048  sfi = StringFromList(ifi, temp_graph_files)
1049  DeleteFile /Z sfi
1050  endfor
1051  temp_graph_files = ""
1052  endif
1053  endif
1054  return 0
1055 };
1056 
1057 static const string elog_success_msg = "Message successfully transmitted";
1058 static const string elog_parse_id = "ID=%u";
1059 
1065 static variable parse_result(){
1066  dfref df_general = get_elog_df("", kdfPersistent)
1067  nvar /sdfr=df_general loglevel
1068 
1069  string path = get_log_path()
1070  string line = ""
1071  string output = ""
1072  variable success = 0
1073  variable id = -1
1074  string part1 = ""
1075  string part2 = ""
1076 
1077  variable len = strlen(path)
1078  if (numtype(len) == 0)
1079  variable f1
1080  Open /R/Z f1 as path
1081  if (v_flag == 0)
1082  do
1083  FReadLine f1, line
1084  if (strlen(line) > 0)
1085  part1 = StringFromList(0, line, ",")
1086  part2 = ReplaceString(" ", StringFromList(1, line, ","), "")
1087  success = cmpstr(part1, elog_success_msg) == 0
1088  if (success)
1089  sscanf part2, elog_parse_id, id
1090  endif
1091  else
1092  break
1093  endif
1094  output += line
1095  while(!success)
1096  Close f1
1097  endif
1098  endif
1099  if (loglevel >= 5)
1100  print output
1101  endif
1102 
1103  return id
1104 };
1105 
1109  string logbooks = list_logbooks(templates=0)
1110  logbooks = AddListItem("(new)", logbooks)
1111  string templates = list_logbooks(templates=1)
1112  templates = AddListItem("(none)", templates)
1113 
1114  string logbook = StringFromList(0, logbooks)
1115  string template = StringFromList(0, logbooks)
1116  string name = ""
1117  string username = ""
1118  string password = ""
1119 
1120  prompt logbook, "logbook", popup logbooks
1121  prompt template, "template", popup templates
1122  prompt name, "new logbook name"
1123 
1124  doprompt "select logbook", logbook, template, name
1125  if (!v_flag)
1126  if (cmpstr(logbook, "(new)") == 0)
1127  elog_create_logbook(name, template=template)
1128  logbook = name
1129  endif
1130  else
1131  logbook = ""
1132  endif
1133  return logbook
1134 };
1135 
1138 variable elog_prompt_login(string logbook){
1139  string logbook
1140 
1141  string logbooks = list_logbooks(templates=0)
1142 
1143  string username = ""
1144  string password = ""
1145 
1146  prompt logbook, "logbook", popup logbooks
1147  prompt username, "user name"
1148  prompt password, "password (blank to log out)"
1149 
1150  doprompt "log in to logbook", logbook, username, password
1151  if (!v_flag)
1152  elog_login(logbook, username, password)
1153  endif
1154 
1155  return v_flag
1156 };
1157 
1165 string PearlElogPanel(string logbook){
1166  string logbook
1167 
1168  dfref savedf = getdatafolderdfr()
1169  dfref df_general = get_elog_df("", kdfPersistent)
1170  dfref df_persistent = get_elog_df(logbook, kdfPersistent)
1171  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1172 
1173  string win_name = logbook + "ElogPanel"
1174  string win_title = "ELOG " + logbook
1175 
1176  NewPanel /K=1 /N=$win_name /W=(600,200,1200,700) as win_title
1177  win_name = s_name
1178  ModifyPanel /w=$win_name cbRGB=(52224,52224,65280)
1179 
1180  svar /sdfr=df_persistent attributes
1181  svar /sdfr=df_persistent controls
1182  svar /sdfr=df_persistent options
1183  wave /t /sdfr=df_volatile attach_list
1184  wave /sdfr=df_volatile attach_sel
1185  svar /sdfr=df_volatile url
1186 
1187  variable iattr
1188  variable nattr = ItemsInList(attributes, ";")
1189  string s_attr
1190  string s_control
1191  string s_option
1192  string persistent_path = GetDataFolder(1, df_persistent)
1193  string volatile_path = GetDataFolder(1, df_volatile)
1194  string options_path
1195  string variable_path
1196  variable ypos = 2
1197  variable height = 0
1198 
1199  for (iattr = 0; iattr < nattr; iattr += 1)
1200  s_attr = StringFromList(iattr, attributes, ";")
1201  s_control = StringFromList(iattr, controls, ";")
1202  strswitch(s_control[0,1])
1203  case "sv":
1204  SetVariable $s_control, win=$win_name, pos={0,ypos}, size={300,16}, bodyWidth=230
1205  SetVariable $s_control, win=$win_name, title=s_attr, value= _STR:""
1206  SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr
1207  ypos += 18
1208  break
1209  case "pm":
1210  options_path = persistent_path + StringByKey(s_attr, options, "=", ";")
1211  PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={300,21}, bodyWidth=230
1212  PopupMenu $s_control, win=$win_name, title=s_attr
1213  PopupMenu $s_control, win=$win_name, mode=1, popvalue="Test", value= #options_path
1214  PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr
1215  ypos += 23
1216  break
1217  case "cb":
1218  CheckBox $s_control, win=$win_name, pos={70,ypos}, size={300,14}
1219  CheckBox $s_control, win=$win_name, title=s_attr, value= 1
1220  CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr
1221  ypos += 17
1222  break
1223  endswitch
1224  endfor
1225 
1226  TitleBox t_attach, win=$win_name, pos={308,5}, size={70,14}, title="Attachments", frame=0
1227  height = ypos - 21 - 4
1228  ListBox lb_attach, win=$win_name, pos={308,21}, size={264,height}
1229  ListBox lb_attach, win=$win_name, listWave=attach_list
1230  ListBox lb_attach, win=$win_name, mode=1, selWave=attach_sel, selRow=-1
1231  ListBox lb_attach, win=$win_name, widths={20,160,80}
1232  ListBox lb_attach, win=$win_name, help={"Choose graphs to attach to the message."}
1233 
1234  Button b_attach_top, win=$win_name, pos={420,2}, size={40,18}, title="top"
1235  Button b_attach_top, win=$win_name, fcolor=(56576,60928,47872)
1236  Button b_attach_top, win=$win_name, proc=PearlElog#bp_attach_top
1237  Button b_attach_top, win=$win_name, help={"Select top graph for attachment."}
1238  Button b_attach_all, win=$win_name, pos={460,2}, size={40,18}, title="all"
1239  Button b_attach_all, win=$win_name, fcolor=(56576,60928,47872)
1240  Button b_attach_all, win=$win_name, proc=PearlElog#bp_attach_allnone
1241  Button b_attach_all, win=$win_name, help={"Select all graphs for attachment."}
1242  Button b_attach_none, win=$win_name, pos={500,2}, size={40,18}, title="none"
1243  Button b_attach_none, win=$win_name, fcolor=(56576,60928,47872)
1244  Button b_attach_none, win=$win_name, proc=PearlElog#bp_attach_allnone
1245  Button b_attach_none, win=$win_name, help={"Deselect all attachments."}
1246  Button b_save_graphs, win=$win_name, pos={540,2}, size={40,18}, title="save"
1247  Button b_save_graphs, win=$win_name, fcolor=(56576,60928,47872)
1248  Button b_save_graphs, win=$win_name, proc=PearlElog#bp_save_graphs
1249  Button b_save_graphs, win=$win_name, help={"Save selected graphs as PNG bitmap files."}
1250  Button b_attach_up, win=$win_name, pos={576,20}, size={20,20}, title="\\W517"
1251  Button b_attach_up, win=$win_name, fcolor=(56576,60928,47872)
1252  Button b_attach_up, win=$win_name, proc=PearlElog#bp_attach_updown
1253  Button b_attach_up, win=$win_name, help={"Move selected graph up."}
1254  Button b_attach_dw, win=$win_name, pos={576,40}, size={20,20}, title="\\W523"
1255  Button b_attach_dw, win=$win_name, fcolor=(56576,60928,47872)
1256  Button b_attach_dw, win=$win_name, proc=PearlElog#bp_attach_updown
1257  Button b_attach_dw, win=$win_name, help={"Move selected graph down."}
1258 
1259  ypos += 246-160
1260  Button b_submit,win=$win_name, pos={70,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
1261  Button b_submit,win=$win_name, help={"Submit form data to ELOG (new entry)."}
1262  Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
1263  Button b_clear,win=$win_name, pos={120,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
1264  Button b_clear,win=$win_name, help={"Clear the form fields"}
1265  Button b_clear,win=$win_name, fcolor=(56576,60928,47872)
1266 
1267  ypos += 272-246
1268  variable_path = volatile_path + "msg_id"
1269  SetVariable sv_id,win=$win_name, pos={51,ypos},size={119,16},bodyWidth=77
1270  SetVariable sv_id,win=$win_name, title="ID",value=$variable_path
1271  SetVariable sv_id,win=$win_name, help={"ID of last submitted message, or message to attach or reply to."}
1272 
1273  TitleBox t_host, win=$win_name, pos={170,ypos+4}, size={112.00,14.00}, frame=0
1274  TitleBox t_host, win=$win_name, variable=url
1275 
1276  ypos += 270-272
1277  Button b_attach,win=$win_name, pos={170,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
1278  Button b_attach,win=$win_name, help={"Attach the selected graph to an existing ELOG entry (correct ID required)."}
1279  Button b_attach,win=$win_name, fcolor=(56576,60928,47872)
1280  Button b_reply,win=$win_name, pos={220,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
1281  Button b_reply,win=$win_name, help={"Submit form data to ELOG as a reply to an existing message (correct ID required)."}
1282  Button b_reply,win=$win_name, fcolor=(56576,60928,47872)
1283  Button b_login,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
1284  Button b_login,win=$win_name, help={"Enter user name and password."}
1285  Button b_login,win=$win_name, fcolor=(56576,60928,47872)
1286  Button b_logout,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_logout,title="Logout"
1287  Button b_logout,win=$win_name, help={"Clear user name and password."}
1288  Button b_logout,win=$win_name, fcolor=(56576,60928,47872), disable=3
1289 
1290  SetWindow $win_name, hook(elogPanelHook)=PearlElog#elog_panel_hook
1291  SetWindow $win_name, userdata(logbook)=logbook
1292 
1293  ypos += 160-270
1294  TitleBox t_message,win=$win_name, pos={10,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
1295  DefineGuide UGH0={FT,ypos},UGV0={FL,70},UGH1={FB,-52},UGV1={FR,-2}
1296  NewNotebook /F=0 /N=Message /OPTS=3 /W=(115,404,345,341)/FG=(UGV0,UGH0,UGV1,UGH1) /HOST=#
1297  Notebook kwTopWin, defaultTab=20, statusWidth=0, autoSave=0
1298  Notebook kwTopWin fSize=10, fStyle=0, textRGB=(0,0,0)
1299  RenameWindow #,Message
1300  string nb_name = win_name + "#Message"
1301  SetActiveSubwindow ##
1302 
1303  // restore recently used attributes and message
1304  svar /z /sdfr=df_persistent recent
1305  if (svar_exists(recent) && (strlen(recent) > 0))
1306  set_panel_attributes(win_name, recent)
1307  endif
1308  svar /z /sdfr=df_persistent recent_message
1309  if (svar_exists(recent_message) && (strlen(recent_message) > 0))
1310  set_panel_message(win_name, recent_message)
1311  endif
1312  Notebook $nb_name selection={startOfFile,startOfFile}, findText={"",1}
1313 
1314  setdatafolder savedf
1315  return win_name
1316 };
1317 
1318 static variable elog_panel_hook(WMWinHookStruct* s){
1319  STRUCT WMWinHookStruct &s
1320 
1321  Variable hookResult = 0
1322 
1323  switch(s.eventCode)
1324  case 0:// activate
1325  string logbook = GetUserData(s.winName, "", "logbook")
1326  if (strlen(logbook) > 0)
1327  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1328  svar /sdfr=df_volatile url
1329  url = format_url(logbook)
1330  update_attach_items(logbook)
1331  endif
1332  break
1333  case 6:// resize
1334  // move bottom-aligned controls when the window is resized
1335  variable b_top = s.winRect.bottom + 4
1336  Button b_submit,pos={70,b_top}
1337  Button b_clear,pos={120,b_top}
1338  TitleBox t_host, pos={170,b_top+4}
1339  b_top += 24
1340  Button b_attach,pos={170,b_top}
1341  Button b_reply,pos={220,b_top}
1342  Button b_login, pos={550,b_top}
1343  Button b_logout, pos={550,b_top}
1344  b_top += 2
1345  SetVariable sv_id,pos={51,b_top}
1346  break
1347  endswitch
1348 
1349  return hookResult// 0 if nothing done, else 1
1350 };
1351 
1352 static const variable kAttachColSel = 0;
1353 static const variable kAttachColTitle = 1;
1354 static const variable kAttachColName = 2;
1355 
1357 static variable update_attach_items(string logbook){
1358  string logbook
1359 
1360  dfref savedf = getdatafolderdfr()
1361  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1362  wave /t /sdfr=df_volatile attach_list
1363  wave /sdfr=df_volatile attach_sel
1364 
1365  if (!waveexists(attach_list))
1366  return -1
1367  endif
1368  string names = WinList("*", ";", "WIN:1;VISIBLE:1")
1369  names = SortList(names, ";", 16)
1370 
1371  // remove closed graphs
1372  variable i
1373  variable k
1374  variable n = DimSize(attach_list, 0)
1375  string s
1376  for (i = n-1; i >= 0; i -= 1)
1377  s = attach_list[i][kAttachColName]
1378  if (WhichListItem(s, names) < 0)
1379  DeletePoints /M=0 i, 1, attach_list, attach_sel
1380  endif
1381  endfor
1382 
1383  // add new graphs
1384  n = ItemsInList(names)
1385  for (i = 0; i < n; i += 1)
1386  s = StringFromList(i, names)
1387  FindValue /text=s /txop=4 /z attach_list
1388  if (v_value < 0)
1389  k = DimSize(attach_list, 0)
1390  Redimension /n=(k+1,3) attach_list, attach_sel
1391  //InsertPoints /M=0 k, 1, attach_list, attach_sel
1392  attach_list[k][kAttachColSel] = ""
1393  attach_list[k][kAttachColTitle] = ""
1394  attach_list[k][kAttachColName] = s
1395  attach_sel[k][kAttachColSel] = 32
1396  attach_sel[k][kAttachColTitle] = 0
1397  attach_sel[k][kAttachColName] = 0
1398  endif
1399  endfor
1400 
1401  // update titles
1402  n = DimSize(attach_list, 0)
1403  for (i = n-1; i >= 0; i -= 1)
1404  s = attach_list[i][kAttachColName]
1405  getwindow /z $s, wtitle
1406  if (v_flag == 0)
1407  attach_list[i][kAttachColTitle] = s_value
1408  else
1409  attach_list[i][kAttachColTitle] = s
1410  endif
1411  endfor
1412 
1413  setdatafolder savedf
1414  return 0
1415 };
1416 
1418 static variable move_attach_item(string logbook, variable item, variable distance){
1419  string logbook
1420  variable item
1421  variable distance
1422 
1423  dfref savedf = getdatafolderdfr()
1424  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1425  wave /t /sdfr=df_volatile attach_list
1426  wave /sdfr=df_volatile attach_sel
1427  variable n = DimSize(attach_list, 0)
1428  variable dest = item + distance
1429 
1430  if ((item >= 0) && (item < n) && (dest >= 0) && (dest < n))
1431  string name = attach_list[item][kAttachColName]
1432  variable sel = attach_sel[item][kAttachColSel]
1433  DeletePoints /M=0 item, 1, attach_list, attach_sel
1434  InsertPoints /M=0 dest, 1, attach_list, attach_sel
1435  attach_list[dest][kAttachColName] = name
1436  update_attach_items(logbook)
1437  attach_sel[dest][kAttachColSel] = sel
1438  endif
1439 };
1440 
1442 static variable bp_attach_updown(WMButtonAction* ba){
1443  STRUCT WMButtonAction &ba
1444 
1445  switch( ba.eventCode )
1446  case 2:// mouse up
1447  string logbook = GetUserData(ba.win, "", "logbook")
1448  ControlInfo /w=$ba.win lb_attach
1449  variable row = v_value
1450  dfref df = $s_datafolder
1451  wave /t /sdfr=df attach_list = $s_value
1452  if (cmpstr(ba.ctrlName, "b_attach_up") == 0)
1453  // up button
1454  if (row >= 1)
1455  move_attach_item(logbook, row, -1)
1456  ListBox lb_attach, win=$ba.win, selRow=(row-1)
1457  endif
1458  else
1459  // down button
1460  if (row < DimSize(attach_list, 0) - 1)
1461  move_attach_item(logbook, row, +1)
1462  ListBox lb_attach, win=$ba.win, selRow=(row+1)
1463  endif
1464  endif
1465  break
1466  case -1:// control being killed
1467  break
1468  endswitch
1469 
1470  return 0
1471 };
1472 
1474 static variable bp_submit(WMButtonAction* ba){
1475  STRUCT WMButtonAction &ba
1476 
1477  switch( ba.eventCode )
1478  case 2:// mouse up
1479  string logbook = GetUserData(ba.win, "", "logbook")
1480  string attributes
1481  string message
1482  string graphs
1483  attributes = get_panel_attributes(ba.win)
1484  message = get_panel_message(ba.win)
1485  graphs = get_panel_graphs(ba.win)
1486 
1487  variable id
1488  if (cmpstr(ba.ctrlName, "b_reply") == 0)
1489  // Reply button
1490  ControlInfo /w=$ba.win sv_id
1491  id = v_value
1492  else
1493  // Submit button
1494  id = 0
1495  endif
1496 
1497  if ((elog_validate_attributes(logbook, attributes) == 0) && (strlen(message) > 0))
1498  variable result
1499  result = elog_create_entry(logbook, attributes, message, graphs=graphs, replyto=id)
1500  if (result == 0)
1501  dfref df = get_elog_df(logbook, kdfPersistent)
1502  svar /sdfr=df recent
1503  recent = attributes
1504  svar /sdfr=df recent_message
1505  recent_message = message
1506  else
1507  abort "Submission failed. Error code " + num2str(result) + "."
1508  endif
1509  else
1510  abort "Submission failed due to missing/invalid attribute."
1511  endif
1512  break
1513  case -1:// control being killed
1514  break
1515  endswitch
1516 
1517  return 0
1518 };
1519 
1521 static variable bp_attach_top(WMButtonAction* ba){
1522  STRUCT WMButtonAction &ba
1523 
1524  switch( ba.eventCode )
1525  case 2:// mouse up
1526  string graphs = WinName(0, 1, 1)
1527  set_panel_graphs(ba.win, graphs)
1528  break
1529  case -1:// control being killed
1530  break
1531  endswitch
1532 
1533  return 0
1534 };
1535 
1537 static variable bp_attach_allnone(WMButtonAction* ba){
1538  STRUCT WMButtonAction &ba
1539 
1540  switch( ba.eventCode )
1541  case 2:// mouse up
1542  string logbook = GetUserData(ba.win, "", "logbook")
1543  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1544  wave /sdfr=df_volatile attach_sel
1545  if (cmpstr(ba.ctrlName, "b_attach_all") == 0)
1546  attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] | 16
1547  else
1548  attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] & ~16
1549  endif
1550  break
1551  case -1:// control being killed
1552  break
1553  endswitch
1554 
1555  return 0
1556 };
1557 
1558 static variable bp_attach(WMButtonAction* ba){
1559  STRUCT WMButtonAction &ba
1560 
1561  switch( ba.eventCode )
1562  case 2:// mouse up
1563  string logbook = GetUserData(ba.win, "", "logbook")
1564  string graphs
1565  graphs = get_panel_graphs(ba.win)
1566 
1567  variable id
1568  ControlInfo /w=$ba.win sv_id
1569  id = v_value
1570 
1571  // TODO : is there a way around this restriction?
1572  DoAlert /T="ELOG" 1, "This operation will replace all existing attachments. Do you want to continue?"
1573 
1574  if ((id > 0) && (v_flag == 1))
1575  variable result
1576  result = elog_add_attachment(logbook, id, graphs)
1577  if (result != 0)
1578  abort "Submission failed. Error code " + num2str(result) + "."
1579  endif
1580  else
1581  abort "Submission failed due to missing/invalid attribute."
1582  endif
1583  break
1584  case -1:// control being killed
1585  break
1586  endswitch
1587 
1588  return 0
1589 };
1590 
1591 static variable bp_save_graphs(WMButtonAction* ba){
1592  STRUCT WMButtonAction &ba
1593 
1594  switch( ba.eventCode )
1595  case 2:// mouse up
1596  string logbook = GetUserData(ba.win, "", "logbook")
1597  string graphs = get_panel_graphs(ba.win)
1598  variable ngraphs = ItemsInList(graphs, ";")
1599 
1600  variable igraph
1601  string sgraph
1602  string graph_path
1603  for (igraph = 0; igraph < ngraphs; igraph += 1)
1604  sgraph = StringFromList(igraph, graphs, ";")
1605  graph_path = create_graph_file(sgraph, igraph)
1606  if (strlen(graph_path) > 0)
1607  print graph_path
1608  endif
1609  endfor
1610 
1611  break
1612  case -1:// control being killed
1613  break
1614  endswitch
1615 
1616  return 0
1617 };
1618 
1619 static variable bp_clear(WMButtonAction* ba){
1620  STRUCT WMButtonAction &ba
1621 
1622  switch( ba.eventCode )
1623  case 2:// mouse up
1624  set_panel_attributes(ba.win, "", clear=1)
1625  set_panel_message(ba.win, "")
1626  set_panel_graphs(ba.win, "")
1627  break
1628  case -1:// control being killed
1629  break
1630  endswitch
1631 
1632  return 0
1633 };
1634 
1635 static variable bp_login(WMButtonAction* ba){
1636  STRUCT WMButtonAction &ba
1637 
1638  switch( ba.eventCode )
1639  case 2:// mouse up
1640  string logbook = GetUserData(ba.win, "", "logbook")
1641  if (elog_prompt_login(logbook) == 0)
1642  Button b_login, win=$ba.win, disable=3
1643  Button b_logout, win=$ba.win, disable=0
1644  endif
1645  break
1646  case -1:// control being killed
1647  break
1648  endswitch
1649 
1650  return 0
1651 };
1652 
1653 static variable bp_logout(WMButtonAction* ba){
1654  STRUCT WMButtonAction &ba
1655 
1656  switch( ba.eventCode )
1657  case 2:// mouse up
1658  string logbook = GetUserData(ba.win, "", "logbook")
1659  elog_logout(logbook)
1660  Button b_login, win=$ba.win, disable=0
1661  Button b_logout, win=$ba.win, disable=3
1662  break
1663  case -1:// control being killed
1664  break
1665  endswitch
1666 
1667  return 0
1668 };
1669 
1670 static string get_default_panel_name(){
1671  string windowname
1672  windowname = StringFromList(0, WinList("*ElogPanel*", ";", "WIN:64"), ";")
1673  return windowname
1674 };
1675 
1683 static string get_panel_attributes(string windowname){
1684  string windowname
1685 
1686  if (strlen(windowname) == 0)
1687  windowname = get_default_panel_name()
1688  endif
1689  if (strlen(windowname) == 0)
1690  return ""
1691  endif
1692 
1693  string controls = ControlNameList(windowname, ";")
1694  string attributes = ""
1695  string control
1696  string attribute
1697  variable ico
1698  variable nco = ItemsInList(controls, ";")
1699  for (ico = 0; ico < nco; ico += 1)
1700  control = StringFromList(ico, controls, ";")
1701  attribute = GetUserData(windowname, control, "attribute")
1702  if (strlen(attribute) > 0)
1703  ControlInfo /w=$windowname $control
1704  switch(v_flag)
1705  case 2:// checkbox
1706  attributes = ReplaceNumberByKey(attribute, attributes, v_value, "=", ";")
1707  break
1708  case 3:// popupmenu
1709  case 5:// setvariable
1710  attributes = ReplaceStringByKey(attribute, attributes, s_value, "=", ";")
1711  break
1712  endswitch
1713  endif
1714  endfor
1715 
1716  return attributes
1717 };
1718 
1730 static string set_panel_attributes(string windowname, string attributes, variable clear = defaultValue){
1731  string windowname
1732  string attributes
1733  variable clear
1734 
1735  if (strlen(windowname) == 0)
1736  windowname = get_default_panel_name()
1737  endif
1738  if (strlen(windowname) == 0)
1739  return ""
1740  endif
1741  if (ParamIsDefault(clear))
1742  clear = 0
1743  endif
1744 
1745  string path
1746 
1747  string controls = ControlNameList(windowname, ";")
1748  string control
1749  string attribute
1750  string value
1751  variable numval
1752  variable ico
1753  variable nco = ItemsInList(controls, ";")
1754  for (ico = 0; ico < nco; ico += 1)
1755  control = StringFromList(ico, controls, ";")
1756  attribute = GetUserData(windowname, control, "attribute")
1757  if (strlen(attribute))
1758  value = StringByKey(attribute, attributes, "=", ";")
1759  if (strlen(value) || clear)
1760  ControlInfo /w=$windowname $control
1761  switch(v_flag)
1762  case 2:// checkbox
1763  numval = NumberByKey(attribute, attributes, "=", ";")
1764  if ((numtype(numval) != 0) && clear)
1765  numval = 0
1766  endif
1767  if (numtype(numval) == 0)
1768  CheckBox $control, value=numval, win=$windowname
1769  endif
1770  break
1771  case 3:// popupmenu
1772  PopupMenu $control, popvalue=value, win=$windowname
1773  break
1774  case 5:// setvariable
1775  SetVariable /z $control, value= _STR:value, win=$windowname
1776  break
1777  endswitch
1778  endif
1779  endif
1780  endfor
1781 
1782  return attributes
1783 };
1784 
1792 static string get_panel_message(string windowname){
1793  string windowname
1794 
1795  if (strlen(windowname) == 0)
1796  windowname = get_default_panel_name()
1797  endif
1798  if (strlen(windowname) == 0)
1799  return ""
1800  endif
1801 
1802  string nb = windowname + "#Message"
1803  notebook $nb selection={startOfFile, endOfFile}
1804  getselection notebook, $nb, 2
1805 
1806  return s_selection
1807 };
1808 
1818 static string set_panel_message(string windowname, string message){
1819  string windowname
1820  string message
1821 
1822  if (strlen(windowname) == 0)
1823  windowname = get_default_panel_name()
1824  endif
1825 
1826  string nb = windowname + "#Message"
1827  notebook $nb selection={startOfFile, endOfFile},text=message
1828 
1829  return message
1830 };
1831 
1838 static string get_panel_graphs(string windowname){
1839  string windowname// panel window name
1840 
1841  dfref savedf = getdatafolderdfr()
1842  if (strlen(windowname) == 0)
1843  windowname = get_default_panel_name()
1844  endif
1845  if (strlen(windowname) == 0)
1846  return ""
1847  endif
1848 
1849  string logbook = GetUserData(windowname, "", "logbook")
1850  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1851  wave /t /sdfr=df_volatile attach_list
1852  wave /sdfr=df_volatile attach_sel
1853  string graphs = ""
1854  string windows = ""
1855  string graphname
1856 
1857  variable n = DimSize(attach_sel, 0)
1858  variable i
1859  for (i = 0; i < n; i += 1)
1860  if (attach_sel[i][kAttachColSel] & 16)
1861  graphname = attach_list[i][kAttachColName]
1862  windows = WinList(graphname, ";", "WIN:1")
1863  if (ItemsInList(windows) == 1)
1864  graphs = AddListItem(graphname, graphs, ";", inf)
1865  endif
1866  endif
1867  endfor
1868 
1869  return graphs
1870 };
1871 
1878 static string set_panel_graphs(string windowname, string graphs){
1879  string windowname
1880  string graphs
1881 
1882  if (strlen(windowname) == 0)
1883  windowname = get_default_panel_name()
1884  endif
1885  if (strlen(windowname) == 0)
1886  return ""
1887  endif
1888 
1889  string logbook = GetUserData(windowname, "", "logbook")
1890  update_attach_items(logbook)
1891  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1892  wave /t /sdfr=df_volatile attach_list
1893  wave /sdfr=df_volatile attach_sel
1894 
1895  variable n = DimSize(attach_sel, 0)
1896  variable i
1897  string graphname
1898  for (i = 0; i < n; i += 1)
1899  graphname = attach_list[i][kAttachColName]
1900  if (WhichListItem(graphname, graphs)>= 0)
1901  attach_sel[i][kAttachColSel] = 48
1902  else
1903  attach_sel[i][kAttachColSel] = 32
1904  endif
1905  endfor
1906 };
1907 
variable elog_create_entry(string logbook, string attributes, string message, variable encoding=defaultValue, string graphs=defaultValue, variable replyto=defaultValue)
create a new entry in ELOG
Definition: pearl-elog.ipf:685
+Go to the documentation of this file.
1 #pragma rtGlobals=3// Use modern global access method and strict wave access.
2 #pragma version = 1.41
3 #pragma IgorVersion = 6.2
4 #pragma ModuleName = PearlElog
5 
6 // author: matthias.muntwiler@psi.ch
7 // Copyright (c) 2013-17 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 
79 
84 
85 static const string package_name = "pearl_elog";
86 static const string package_path = "root:packages:pearl_elog:";
87 
97 variable pearl_elog(string logbook){
98  string logbook
99 
100  if (init_package() == 0)
101  load_prefs()
102  string templates = list_logbooks(templates=1)
103  if (ItemsInList(templates) < 1)
105  endif
106  endif
107 
108  if (strlen(logbook) == 0)
109  logbook = elog_prompt_logbook()
110  endif
111 
112  string win_name = logbook + "ElogPanel"
113  if (strlen(logbook) > 0)
114  if (strlen(WinList(win_name, ";", "")) > 0)
115  DoWindow /F $win_name
116  else
117  win_name = PearlElogPanel(logbook)
118  STRUCT WMWinHookStruct s
119  s.eventCode = 0
120  s.winName = win_name
121  elog_panel_hook(s)
122  endif
123  endif
124 };
125 
127 static variable IgorBeforeNewHook(string igorApplicationNameStr){
128  string igorApplicationNameStr
129  save_prefs()
131  return 0
132 };
133 
135 static variable IgorQuitHook(string igorApplicationNameStr){
136  string igorApplicationNameStr
137  save_prefs()
139  return 0
140 };
141 
143 static variable AfterFileOpenHook(variable refNum, string file, string pathName, string type, string creator, variable kind){
144  Variable refNum,kind
145  String file,pathName,type,creator
146  if( (kind >= 1) && (kind <= 2))
147  init_package(clean=1)
148  load_prefs()
149  endif
150  return 0
151 };
152 
153 static const variable kdfRoot = 0;
154 static const variable kdfVolatile = 1;
155 static const variable kdfPersistent = 2;
156 static const variable kdfTemplates = 3;
157 
170 static dfr get_elog_df(string name, variable category){
171  string name
172  variable category
173 
174  dfref df_package = $package_path
175  dfref df_persistent = df_package:persistent
176  dfref df_volatile = df_package:volatile
177 
178  switch(category)
179  case kdfRoot:
180  dfref df_parent = df_package
181  break
182  case kdfPersistent:
183  dfref df_parent = df_persistent
184  break
185  case kdfTemplates:
186  dfref df_parent = df_persistent:templates
187  break
188  case kdfVolatile:
189  dfref df_parent = df_volatile
190  break
191  default:
192  Abort "get_elog_df: undefined data folder category."
193  endswitch
194 
195  if ((strlen(name) > 0) && (category >= 1))
196  if (category == kdfTemplates)
197  dfref df_logbooks = df_parent
198  else
199  dfref df_logbooks = df_parent:logbooks
200  endif
201  dfref df_logbook = df_logbooks:$name
202  return df_logbook
203  else
204  return df_parent
205  endif
206 };
207 
217 static variable init_package(variable clean = defaultValue){
218  variable clean
219 
220  if (ParamIsDefault(clean))
221  clean = 0
222  endif
223 
224  dfref savedf = getdatafolderdfr()
225  dfref df_root = get_elog_df("", kdfRoot)
226  if ((clean == 0) && (DataFolderRefStatus(df_root) == 1))
227  return 1
228  endif
229 
230  setdatafolder root:
231  newdatafolder /o/s packages
232  newdatafolder /o/s $package_name
233  dfref df_package_root = getdatafolderdfr()
234  newdatafolder /o/s volatile
235  dfref df_volatile = getdatafolderdfr()
236  newdatafolder /o logbooks
237  setdatafolder df_package_root
238  newdatafolder /o/s persistent
239  dfref df_persistent = getdatafolderdfr()
240  newdatafolder /o logbooks
241  newdatafolder /o templates
242 
243  // common configuration
244  setdatafolder df_persistent
245  string /g elog_path = "c:\\program files (x86)\\ELOG\\elog.exe"
246  string /g hostname = "localhost"
247  variable /g port = 0// 0 = unspecified (default)
248  variable /g ssl = 0// 0 = plain text (incl. passwords), 1 = secure connection
249  string /g subdir = ""
250  variable /g loglevel = 4
251 
252  setdatafolder savedf
253  return 0
254 };
255 
263  dfref savedf = getdatafolderdfr()
264 
265  dfref df_root = get_elog_df("", kdfRoot)
266  dfref df_persistent = get_elog_df("", kdfPersistent)
267  dfref df_templates = get_elog_df("", kdfTemplates)
268 
269  // Experiments template
270  setdatafolder df_templates
271  newdatafolder /o/s Experiments
272 
273  // attributes (persistent)
274  // available attributes
275  string /g attributes = "author;project;sample;source;task;technique;file;valid;"
276  // controls corresponding to attributes
277  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
278  string /g controls = "sv_author;sv_project;sv_sample;pm_source;pm_task;pm_technique;sv_file;cb_valid;"
279  // attributes with fixed options, value item declares the options string
280  string /g options = "source=sources;task=tasks;technique=techniques"
281  // attributes which must be defined
282  string /g required_attributes = "author;project;sample;source;task;technique;valid"
283 
284  // option lists
285  string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
286  string /g tasks = "Measurement;Optimization;Analysis;Sample Preparation;Sample Storage;Comment;Development;Maintenance;Test;Other"
287  string /g techniques = "XPS;UPS;XPD;XAS;XMCD;PhD;ARUPS;STM;STS;LEED;AES;QMS;MBE;Sputter/Anneal;Test;Other"
288 
289  // Calculations template
290  setdatafolder df_templates
291  newdatafolder /o/s Calculations
292 
293  // attributes (persistent)
294  // available attributes
295  string /g attributes = "author;project;sample;program;revision;machine;job;experiment;source path;result path;valid"
296  // controls corresponding to attributes
297  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
298  string /g controls = "sv_author;sv_project;sv_sample;pm_program;sv_revision;pm_machine;sv_job;sv_experiment;sv_sourcepath;sv_resultpath;cb_valid"
299  // attributes with fixed options, value item declares the options string
300  string /g options = "program=programs;machine=machines"
301  // attributes which must be defined
302  string /g required_attributes = "author;project;sample"
303 
304  // option lists
305  string /g programs = "PMSCO;EDAC;MSC;SSC;MUFPOT;DMSUP;Other"
306  string /g machines = "PC;VM;Ra;Merlin;llcx;Other"
307 
308  // System template
309  setdatafolder df_templates
310  newdatafolder /o/s System
311 
312  // attributes (persistent)
313  // available attributes
314  string /g attributes = "author;type;system;source;file"
315  // controls corresponding to attributes
316  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
317  string /g controls = "sv_author;pm_type;pm_system;pm_source;sv_file"
318  // attributes with fixed options, value item declares the options string
319  string /g options = "type=types;system=systems;source=sources"
320  // attributes which must be defined
321  string /g required_attributes = "author;type;system"
322 
323  // option lists
324  string /g types = "Installation;Repair;Maintenance;Test;Commissioning;Bakeout;Incident;Cool-down;Warm-up;Storage;Other"
325  string /g systems = "Vacuum;Control System;BL;XA;XP;SA;SP;T;LL;Monochromator;Carving;Scienta;STM;PC-Scienta;PC-Matrix;PC-Console;PC-Console-Win;PC-XP;EPS;LAC;Desiccator"
326  string /g sources = "Manual Entry;PShell;Scienta Data;SScan Data;Prosilica Data;OTF Data;Beamline Status;LEED Data;QMS Data;Matrix Data;Igor Pro;Other"
327 
328  setdatafolder savedf
329  return 0
330 };
331 
340 static variable init_volatile_vars(){
341  dfref savedf = GetDataFolderDFR()
342 
343  dfref df_volatile_root = get_elog_df("", kdfVolatile)
344  dfref df_volatile_parent = df_volatile_root:logbooks
345 
346  string logbooks = list_logbooks()
347  string logbook
348  variable nlb = ItemsInList(logbooks)
349  variable ilb
350 
351  SetDataFolder df_volatile_root
352  if (exists("temp_graph_files") != 2)
353  string /g temp_graph_files = ""
354  endif
355 
356  for (ilb = 0; ilb < nlb; ilb += 1)
357  logbook = StringFromList(ilb, logbooks)
358 
359  SetDataFolder df_volatile_parent
360  if (DataFolderExists(logbook))
361  SetDataFolder $logbook
362  else
363  NewDataFolder /o/s $logbook
364  endif
365 
366  if (exists("username") != 2)
367  string /g username = ""
368  endif
369  if (exists("password") != 2)
370  string /g password = ""
371  endif
372  if (exists("msg_id") != 2)
373  variable /g msg_id = 0
374  endif
375  if (exists("att_list") != 1)
376  make /n=(0,3) /t /o attach_list
377  make /n=(0,3) /i /o attach_sel
378  endif
379  if (exists("url") != 2)
380  string /g url = ""
381  endif
382  endfor
383 
384  SetDataFolder savedf
385  return 0
386 };
387 
401 
414 variable elog_create_logbook(string name, string template = defaultValue){
415  string name
416  string template
417 
418  if (ParamIsDefault(template))
419  template = ""
420  endif
421 
422  dfref savedf = getdatafolderdfr()
423  dfref df_root = get_elog_df("", kdfRoot)
424  dfref df_persistent_root = get_elog_df("", kdfPersistent)
425  dfref df_persistent_parent = df_persistent_root:logbooks
426  dfref df_volatile_root = get_elog_df("", kdfVolatile)
427  dfref df_volatile_parent = df_volatile_root:logbooks
428 
429  setdatafolder df_persistent_parent
430  if (CheckName(name, 11) != 0)
431  setdatafolder savedf
432  Abort "invalid logbook name"
433  return -1
434  endif
435 
436  if (strlen(template) > 0)
437  dfref df_template = get_elog_df(template, kdfTemplates)
438  dfref df_existing = get_elog_df(name, kdfPersistent)
439  if (DataFolderRefStatus(df_existing))
440  KillDataFolder /Z df_existing
441  endif
442  DuplicateDataFolder df_template, df_persistent_parent:$name
443  else
444  NewDataFolder /o/s df_persistent_parent:$name
445 
446  // ELOG logbook name
447  string /g logbook = name
448  // attributes (persistent)
449  // available attributes
450  string /g attributes = ""
451  // controls corresponding to attributes
452  // prefix determines the control type: sv_ = setvariable (string), pm_ = popup menu, cb = check box
453  string /g controls = ""
454  // attributes with fixed options, value item declares the options string
455  string /g options = ""
456  // attributes which must be defined
457  string /g required_attributes = ""
458  endif
459 
460  // usage data (persistent)
461  setdatafolder get_elog_df(name, kdfPersistent)
462  string /g recent = ""
463  string /g recent_message = ""
464 
466 
467  setdatafolder savedf
468  return 0
469 };
470 
473 variable elog_config(string elog_path = defaultValue, string hostname = defaultValue, variable port = defaultValue, string subdir = defaultValue){
474  string elog_path
475  string hostname
476  variable port
477  string subdir
478 
479  dfref df = get_elog_df("", kdfPersistent)
480 
481  if (!ParamIsDefault(elog_path))
482  svar /sdfr=df g_elog_path = elog_path
483  g_elog_path = elog_path
484  endif
485  if (!ParamIsDefault(hostname))
486  svar /sdfr=df g_hostname = hostname
487  g_hostname = hostname
488  endif
489  if (!ParamIsDefault(port))
490  nvar /sdfr=df g_port = port
491  g_port = port
492  endif
493  if (!ParamIsDefault(subdir))
494  svar /sdfr=df g_subdir = subdir
495  g_subdir = subdir
496  endif
497 };
498 
513 variable elog_login(string logbook, string username, string password){
514  string logbook
515  string username
516  string password
517 
518  dfref df = get_elog_df(logbook, kdfVolatile)
519  svar /sdfr=df g_username=username
520  svar /sdfr=df g_password=password
521  g_username = username
522  g_password = password
523 };
524 
533 variable elog_logout(string logbook){
534  string logbook
535 
536  dfref df = get_elog_df(logbook, kdfVolatile)
537  if (strlen(logbook) > 0)
538  svar /z /sdfr=df g_username=username
539  svar /z /sdfr=df g_password=password
540  if (svar_exists(g_username))
541  g_username = ""
542  endif
543  if (svar_exists(g_password))
544  g_password = ""
545  endif
546  else
547  dfref df2 = df:logbooks
548  variable nlb = CountObjectsDFR(df2, 4)
549  variable ilb
550  string slb
551  for (ilb = 0; ilb < nlb; ilb += 1)
552  slb = GetIndexedObjNameDFR(df2, 4, ilb)
553  if (strlen(slb) > 0)
554  elog_logout(slb)
555  endif
556  endfor
557  endif
558 };
559 
564 static variable save_prefs(){
565  dfref saveDF = GetDataFolderDFR()
566 
567  dfref df = get_elog_df("", kdfPersistent)
568  if (DataFolderRefStatus(df) == 1)
569  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
570  fullPath += package_name
571  NewPath/O/C/Q tempPackagePrefsPath, fullPath
572  fullPath += ":preferences.pxp"
573  SetDataFolder df
574  SaveData /O /Q /R fullPath
575  KillPath/Z tempPackagePrefsPath
576  endif
577 
578  SetDataFolder saveDF
579 };
580 
584 static variable load_prefs(){
585  dfref saveDF = GetDataFolderDFR()
586 
587  variable result = -1
588  init_package()
589  setdatafolder get_elog_df("", kdfPersistent)
590 
591  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
592  fullPath += package_name
593 
594  GetFileFolderInfo /Q /Z fullPath
595  if (V_Flag == 0)// Disk directory exists?
596  fullPath += ":preferences.pxp"
597  GetFileFolderInfo /Q /Z fullPath
598  if (V_Flag == 0)// Preference file exist?
599  LoadData /O /R /Q fullPath
601  result = 0
602  endif
603  endif
604 
605  SetDataFolder saveDF
606  return result
607 };
608 
618 static string list_logbooks(variable templates = defaultValue){
619  variable templates
620 
621  if (ParamIsDefault(templates))
622  templates = 0
623  endif
624 
625  dfref df_persistent = get_elog_df("", kdfPersistent)
626  if (templates)
627  dfref df_logbooks = df_persistent:templates
628  else
629  dfref df_logbooks = df_persistent:logbooks
630  endif
631  string logbooks = ""
632 
633  variable nlb = CountObjectsDFR(df_logbooks, 4)
634  variable ilb
635  string slb
636  for (ilb = 0; ilb < nlb; ilb += 1)
637  slb = GetIndexedObjNameDFR(df_logbooks, 4, ilb)
638  if (strlen(slb) > 0)
639  logbooks = AddListItem(slb, logbooks)
640  endif
641  endfor
642 
643  return SortList(logbooks, ";", 16)
644 };
645 
653 variable elog_validate_attributes(string logbook, string attributes){
654 
655  string logbook// name of the logbook (as in igor folder name)
656  string attributes// key=value list of attributes, semicolon separated
657 
658  variable result = 0
659  return result
660 };
661 
685 variable elog_create_entry(string logbook, string attributes, string message, variable encoding = defaultValue, string graphs = defaultValue, variable replyto = defaultValue){
686  string logbook
687  string attributes
688  string message
689  variable encoding
690  string graphs
691  variable replyto
692 
693  if (ParamIsDefault(encoding))
694  encoding = 1
695  endif
696  if (ParamIsDefault(graphs))
697  graphs = ""
698  endif
699  if (ParamIsDefault(replyto))
700  replyto = 0
701  endif
702 
703  dfref savedf = getdatafolderdfr()
704  dfref df_general = get_elog_df("", kdfPersistent)
705  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
706 
707  variable result = 0
708  nvar /sdfr=df_volatile msg_id
709  nvar /sdfr=df_general loglevel
710 
711  if (elog_validate_attributes(logbook,attributes) != 0)
712  if (loglevel >= 2)
713  print "ELOG: failed to validate attributes."
714  endif
715  result = -3
716  endif
717 
718  string cmd = prepare_command_line(logbook)
719  if (strlen(cmd) == 0)
720  if (loglevel >= 2)
721  print "ELOG: failed to prepare command line."
722  endif
723  result = -2
724  endif
725 
726  if (replyto >= 1)
727  cmd += " -r " + num2str(replyto)
728  endif
729  cmd += " -n " + num2str(encoding)
730 
731  variable nattr = ItemsInList(attributes, ";")
732  variable iattr
733  string sattr
734  for (iattr = 0; (iattr < nattr) && (result == 0); iattr += 1)
735  sattr = StringFromList(iattr, attributes, ";")
736  if (strlen(StringFromList(1, sattr, "=")) > 0)
737  sattr = ReplaceString("%", sattr, "")
738  cmd += " -a \"" + sattr + "\""
739  endif
740  endfor
741 
742  if (result == 0)
743  string cmd_graphs = prepare_graph_attachments(graphs)
744  cmd += " " + cmd_graphs
745  endif
746 
747  if ((result == 0) && (strlen(message) > 0))
748  string messagefile = create_message_file(message)
749  if (strlen(messagefile) > 0)
750  cmd += " -m \"" + messagefile + "\""
751  cmd += " > elog.log"
752  if (loglevel >= 5)
753  print cmd
754  endif
755  string cmd_file_path = create_cmd_file(cmd)
756  if (strlen(cmd_file_path) > 0)
757  ExecuteScriptText cmd_file_path
758  variable id = parse_result()
759  if (id > 0)
760  msg_id = id
761  if (loglevel >= 4)
762  print "ELOG: sent message " + num2str(id)
763  endif
764  else
765  if (loglevel >= 2)
766  print "ELOG: sending message failed."
767  endif
768  result = -4
769  endif
770  else
771  result = -2
772  endif
773  else
774  if (loglevel >= 2)
775  print "ELOG: failed to create temporary message file."
776  endif
777  result = -1
778  endif
779  endif
780 
781  setdatafolder savedf
782  return result
783 };
784 
792 variable elog_add_attachment(string logbook, variable id, string graphs){
793  string logbook
794  variable id// existing entry ID
795  string graphs// names of graph windows to be added as attachments, semicolon separated
796 
797  dfref savedf = getdatafolderdfr()
798  dfref df_general = get_elog_df("", kdfPersistent)
799  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
800 
801  variable result = 0
802  nvar /sdfr=df_volatile msg_id
803  nvar /sdfr=df_general loglevel
804 
805  string cmd = prepare_command_line(logbook)
806  if (strlen(cmd) == 0)
807  result = -2// error: invalid/missing command line
808  endif
809 
810  cmd += " -e " + num2str(id)
811 
812  if (result == 0)
813  string cmd_graphs = prepare_graph_attachments(graphs)
814  if (strlen(cmd_graphs) == 0)
815  result = -3// error: invalid/missing graphs
816  endif
817  endif
818 
819  if (result == 0)
820  cmd += " " + cmd_graphs
821  cmd += " > elog.log"
822  string cmd_file_path = create_cmd_file(cmd)
823  if (strlen(cmd_file_path) > 0)
824  ExecuteScriptText cmd_file_path
825  id = parse_result()
826  if (id > 0)
827  msg_id = id
828  if (loglevel >= 4)
829  print "ELOG: attached graphs to message " + num2str(id)
830  endif
831  else
832  if (loglevel >= 2)
833  print "ELOG: failed to attach graphs."
834  endif
835  result = -4// error: elog returned error
836  endif
837  else
838  result = -2// error: invalid command line
839  endif
840  endif
841 
842  setdatafolder savedf
843  return result
844 };
845 
853 static string prepare_command_line(string logbook){
854  string logbook
855 
856  dfref df_general = get_elog_df("", kdfPersistent)
857  dfref df_persistent = get_elog_df(logbook, kdfPersistent)
858  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
859 
860  svar /sdfr=df_general elog_path
861  svar /sdfr=df_general hostname
862  nvar /sdfr=df_general port
863  nvar /sdfr=df_general ssl
864  svar /sdfr=df_general subdir
865  nvar /sdfr=df_general loglevel
866  svar /sdfr=df_volatile username
867  svar /sdfr=df_volatile password
868 
869  string cmd
870  cmd = "\"" + elog_path + "\""
871  if (loglevel >= 5)
872  cmd += " -v"
873  endif
874  cmd += " -h " + hostname
875  if ((nvar_exists(port)) && (port > 0))
876  cmd += " -p " + num2str(port)
877  endif
878  if ((svar_exists(subdir)) && (strlen(subdir) > 0))
879  cmd += " -d " + subdir
880  endif
881  cmd += " -l \"" + logbook + "\""
882  if ((nvar_exists(ssl)) && (ssl != 0))
883  cmd += " -s"
884  endif
885  //cmd += " -w " + password
886  if (svar_exists(username) && svar_exists(password) && (strlen(username) > 0) && (strlen(password) > 0))
887  cmd += " -u " + username + " " + password
888  endif
889 
890  if (loglevel >= 5)
891  print cmd
892  endif
893 
894  return cmd
895 };
896 
902 static string format_url(string logbook){
903  string logbook
904 
905  dfref df_general = get_elog_df("", kdfPersistent)
906 
907  svar /sdfr=df_general hostname
908  nvar /sdfr=df_general port
909  nvar /sdfr=df_general ssl
910  svar /sdfr=df_general subdir
911 
912  string cmd = ""
913  if ((nvar_exists(ssl)) && (ssl != 0))
914  cmd += "https://"
915  else
916  cmd += "http://"
917  endif
918  cmd += hostname
919  if ((nvar_exists(port)) && (port > 0))
920  cmd += ":" + num2str(port)
921  endif
922  if ((svar_exists(subdir)) && (strlen(subdir) > 0))
923  cmd += "/" + subdir
924  endif
925  cmd += "/" + logbook
926 
927  return cmd
928 };
929 
939 static string prepare_graph_attachments(string graphs){
940  string graphs// names of graph windows to be added as attachments, semicolon separated
941 
942  string cmd = ""
943  variable ngraphs = ItemsInList(graphs, ";")
944  variable igraph
945  string sgraph
946  string graph_path
947  for (igraph = 0; igraph < ngraphs; igraph += 1)
948  sgraph = StringFromList(igraph, graphs, ";")
949  graph_path = create_graph_file(sgraph, igraph)
950  if (strlen(graph_path) > 0)
951  cmd += " -f \"" + graph_path + "\""
952  endif
953  endfor
954 
955  return cmd
956 };
957 
958 static string get_timestamp(string sep){
959  string sep
960  Variable now = DateTime
961  string dat = ReplaceString("-", Secs2Date(DateTime, -2), "")
962  string tim = ReplaceString(":", Secs2Time(DateTime, 3), "")
963  return dat + sep + tim
964 };
965 
982 static string create_message_file(string message){
983  string message
984 
985  message = ReplaceString("%", message, "")
986  string path = SpecialDirPath("Temporary", 0, 1, 0)
987  variable len = strlen(path)
988  string filename
989 
990  if (numtype(len) == 0)
991  filename = "elog_temp_message.txt"
992  path += filename
993  variable f1
994  Open f1 as path
995  fprintf f1, message
996  Close f1
997  else
998  filename = ""
999  endif
1000 
1001  return filename
1002 };
1003 
1023 static string create_graph_file(string graphname, variable fileindex){
1024  string graphname
1025  variable fileindex
1026 
1027  dfref df_volatile_root = get_elog_df("", kdfVolatile)
1028  svar /sdfr=df_volatile_root temp_graph_files
1029 
1030  string path = SpecialDirPath("Temporary", 0, 1, 0)
1031  string ts = get_timestamp("_")
1032  variable len = strlen(path)
1033  string filename
1034 
1035  if (numtype(len) == 0)
1036  filename = "elog_" + ts + "_" + num2str(fileindex) + ".png"
1037  path += filename
1038  SavePICT /B=72 /E=-5 /M /O /W=(0,0,8,6) /WIN=$graphname /Z as path
1039  if (v_flag == 0)
1040  temp_graph_files = AddListItem(path, temp_graph_files, ";", inf)
1041  else
1042  filename = ""
1043  endif
1044  else
1045  filename = ""
1046  endif
1047 
1048  return filename
1049 };
1050 
1059 static string create_cmd_file(string cmd){
1060  string cmd
1061 
1062  dfref df_general = get_elog_df("", kdfPersistent)
1063  nvar /sdfr=df_general loglevel
1064 
1065  if (strlen(cmd) >= 1024)
1066  if (loglevel >= 2)
1067  print "ELOG: command line too long (add fewer attachments)."
1068  endif
1069  return ""
1070  endif
1071 
1072  string work_path = SpecialDirPath("Temporary", 0, 1, 0)
1073  variable len = strlen(work_path)
1074  if (numtype(len) == 0)
1075  string cmdx
1076  string cmd_path = work_path + "elog_temp_cmd.bat"
1077 
1078  variable f1
1079  Open f1 as cmd_path
1080  cmdx = "c:\r\n"
1081  fprintf f1, cmdx
1082  cmdx = "cd \"" + work_path + "\"\r\n"
1083  fprintf f1, cmdx
1084  cmdx = "del elog.log"
1085  fprintf f1, cmdx + "\r\n"
1086  fprintf f1, cmd
1087  Close f1
1088  else
1089  cmd_path = ""
1090  endif
1091 
1092  return cmd_path
1093 };
1094 
1095 static string get_log_path(){
1096  string path = SpecialDirPath("Temporary", 0, 1, 0)
1097  variable len = strlen(path)
1098  if (numtype(len) == 0)
1099  path += "elog.log"
1100  else
1101  path = ""
1102  endif
1103 
1104  return path
1105 };
1106 
1115 static variable cleanup_temp_files(){
1116  dfref df_volatile_root = get_elog_df("", kdfVolatile)
1117  if (DataFolderRefStatus(df_volatile_root))
1118  svar /sdfr=df_volatile_root /z temp_graph_files
1119  if (SVAR_Exists(temp_graph_files))
1120  variable nfi = ItemsInList(temp_graph_files)
1121  variable ifi
1122  string sfi
1123  for (ifi = 0; ifi < nfi; ifi += 1)
1124  sfi = StringFromList(ifi, temp_graph_files)
1125  DeleteFile /Z sfi
1126  endfor
1127  temp_graph_files = ""
1128  endif
1129  endif
1130  return 0
1131 };
1132 
1133 static const string elog_success_msg = "Message successfully transmitted";
1134 static const string elog_parse_id = "ID=%u";
1135 
1141 static variable parse_result(){
1142  dfref df_general = get_elog_df("", kdfPersistent)
1143  nvar /sdfr=df_general loglevel
1144 
1145  string path = get_log_path()
1146  string line = ""
1147  string output = ""
1148  variable success = 0
1149  variable id = -1
1150  string part1 = ""
1151  string part2 = ""
1152 
1153  variable len = strlen(path)
1154  if (numtype(len) == 0)
1155  variable f1
1156  Open /R/Z f1 as path
1157  if (v_flag == 0)
1158  do
1159  FReadLine f1, line
1160  if (strlen(line) > 0)
1161  part1 = StringFromList(0, line, ",")
1162  part2 = ReplaceString(" ", StringFromList(1, line, ","), "")
1163  success = cmpstr(part1, elog_success_msg) == 0
1164  if (success)
1165  sscanf part2, elog_parse_id, id
1166  endif
1167  else
1168  break
1169  endif
1170  output += line
1171  while(!success)
1172  Close f1
1173  endif
1174  endif
1175  if (loglevel >= 5)
1176  print output
1177  endif
1178 
1179  return id
1180 };
1181 
1185  string logbooks = list_logbooks(templates=0)
1186  logbooks = AddListItem("(new)", logbooks)
1187  string templates = list_logbooks(templates=1)
1188  templates = AddListItem("(none)", templates)
1189 
1190  string logbook = StringFromList(0, logbooks)
1191  string template = StringFromList(0, logbooks)
1192  string name = ""
1193  string username = ""
1194  string password = ""
1195 
1196  prompt logbook, "logbook", popup logbooks
1197  prompt template, "template", popup templates
1198  prompt name, "new logbook name"
1199 
1200  doprompt "select logbook", logbook, template, name
1201  if (!v_flag)
1202  if (cmpstr(logbook, "(new)") == 0)
1203  elog_create_logbook(name, template=template)
1204  logbook = name
1205  endif
1206  else
1207  logbook = ""
1208  endif
1209  return logbook
1210 };
1211 
1214 variable elog_prompt_login(string logbook){
1215  string logbook
1216 
1217  string logbooks = list_logbooks(templates=0)
1218 
1219  string username = ""
1220  string password = ""
1221 
1222  prompt logbook, "logbook", popup logbooks
1223  prompt username, "user name"
1224  prompt password, "password (blank to log out)"
1225 
1226  doprompt "log in to logbook", logbook, username, password
1227  if (!v_flag)
1228  elog_login(logbook, username, password)
1229  endif
1230 
1231  return v_flag
1232 };
1233 
1241 string PearlElogPanel(string logbook){
1242  string logbook
1243 
1244  dfref savedf = getdatafolderdfr()
1245  dfref df_general = get_elog_df("", kdfPersistent)
1246  dfref df_persistent = get_elog_df(logbook, kdfPersistent)
1247  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1248 
1249  string win_name = logbook + "ElogPanel"
1250  string win_title = "ELOG " + logbook
1251 
1252  NewPanel /K=1 /N=$win_name /W=(600,200,1200,700) as win_title
1253  win_name = s_name
1254  ModifyPanel /w=$win_name cbRGB=(52224,52224,65280)
1255 
1256  svar /sdfr=df_persistent attributes
1257  svar /sdfr=df_persistent controls
1258  svar /sdfr=df_persistent options
1259  wave /t /sdfr=df_volatile attach_list
1260  wave /sdfr=df_volatile attach_sel
1261  svar /sdfr=df_volatile url
1262 
1263  variable iattr
1264  variable nattr = ItemsInList(attributes, ";")
1265  string s_attr
1266  string s_control
1267  string s_option
1268  string persistent_path = GetDataFolder(1, df_persistent)
1269  string volatile_path = GetDataFolder(1, df_volatile)
1270  string options_path
1271  string variable_path
1272  variable ypos = 2
1273  variable height = 0
1274 
1275  for (iattr = 0; iattr < nattr; iattr += 1)
1276  s_attr = StringFromList(iattr, attributes, ";")
1277  s_control = StringFromList(iattr, controls, ";")
1278  strswitch(s_control[0,1])
1279  case "sv":
1280  SetVariable $s_control, win=$win_name, pos={0,ypos}, size={300,16}, bodyWidth=230
1281  SetVariable $s_control, win=$win_name, title=s_attr, value= _STR:""
1282  SetVariable $s_control, win=$win_name, userdata(attribute)=s_attr
1283  ypos += 18
1284  break
1285  case "pm":
1286  options_path = persistent_path + StringByKey(s_attr, options, "=", ";")
1287  PopupMenu $s_control, win=$win_name, pos={0,ypos}, size={300,21}, bodyWidth=230
1288  PopupMenu $s_control, win=$win_name, title=s_attr
1289  PopupMenu $s_control, win=$win_name, mode=1, popvalue="Test", value= #options_path
1290  PopupMenu $s_control, win=$win_name, userdata(attribute)=s_attr
1291  ypos += 23
1292  break
1293  case "cb":
1294  CheckBox $s_control, win=$win_name, pos={70,ypos}, size={300,14}
1295  CheckBox $s_control, win=$win_name, title=s_attr, value= 1
1296  CheckBox $s_control, win=$win_name, userdata(attribute)=s_attr
1297  ypos += 17
1298  break
1299  endswitch
1300  endfor
1301 
1302  TitleBox t_attach, win=$win_name, pos={308,5}, size={70,14}, title="Attachments", frame=0
1303  height = ypos - 21 - 4
1304  ListBox lb_attach, win=$win_name, pos={308,21}, size={264,height}
1305  ListBox lb_attach, win=$win_name, listWave=attach_list
1306  ListBox lb_attach, win=$win_name, mode=1, selWave=attach_sel, selRow=-1
1307  ListBox lb_attach, win=$win_name, widths={20,160,80}
1308  ListBox lb_attach, win=$win_name, help={"Choose graphs to attach to the message."}
1309 
1310  Button b_attach_top, win=$win_name, pos={420,2}, size={40,18}, title="top"
1311  Button b_attach_top, win=$win_name, fcolor=(56576,60928,47872)
1312  Button b_attach_top, win=$win_name, proc=PearlElog#bp_attach_top
1313  Button b_attach_top, win=$win_name, help={"Select top graph for attachment."}
1314  Button b_attach_all, win=$win_name, pos={460,2}, size={40,18}, title="all"
1315  Button b_attach_all, win=$win_name, fcolor=(56576,60928,47872)
1316  Button b_attach_all, win=$win_name, proc=PearlElog#bp_attach_allnone
1317  Button b_attach_all, win=$win_name, help={"Select all graphs for attachment."}
1318  Button b_attach_none, win=$win_name, pos={500,2}, size={40,18}, title="none"
1319  Button b_attach_none, win=$win_name, fcolor=(56576,60928,47872)
1320  Button b_attach_none, win=$win_name, proc=PearlElog#bp_attach_allnone
1321  Button b_attach_none, win=$win_name, help={"Deselect all attachments."}
1322  Button b_save_graphs, win=$win_name, pos={540,2}, size={40,18}, title="save"
1323  Button b_save_graphs, win=$win_name, fcolor=(56576,60928,47872)
1324  Button b_save_graphs, win=$win_name, proc=PearlElog#bp_save_graphs
1325  Button b_save_graphs, win=$win_name, help={"Save selected graphs as PNG bitmap files."}
1326  Button b_attach_up, win=$win_name, pos={576,20}, size={20,20}, title="\\W517"
1327  Button b_attach_up, win=$win_name, fcolor=(56576,60928,47872)
1328  Button b_attach_up, win=$win_name, proc=PearlElog#bp_attach_updown
1329  Button b_attach_up, win=$win_name, help={"Move selected graph up."}
1330  Button b_attach_dw, win=$win_name, pos={576,40}, size={20,20}, title="\\W523"
1331  Button b_attach_dw, win=$win_name, fcolor=(56576,60928,47872)
1332  Button b_attach_dw, win=$win_name, proc=PearlElog#bp_attach_updown
1333  Button b_attach_dw, win=$win_name, help={"Move selected graph down."}
1334 
1335  ypos += 246-160
1336  Button b_submit,win=$win_name, pos={70,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
1337  Button b_submit,win=$win_name, help={"Submit form data to ELOG (new entry)."}
1338  Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
1339  Button b_clear,win=$win_name, pos={120,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
1340  Button b_clear,win=$win_name, help={"Clear the form fields"}
1341  Button b_clear,win=$win_name, fcolor=(56576,60928,47872)
1342 
1343  ypos += 272-246
1344  variable_path = volatile_path + "msg_id"
1345  SetVariable sv_id,win=$win_name, pos={51,ypos},size={119,16},bodyWidth=77
1346  SetVariable sv_id,win=$win_name, title="ID",value=$variable_path
1347  SetVariable sv_id,win=$win_name, help={"ID of last submitted message, or message to attach or reply to."}
1348 
1349  TitleBox t_host, win=$win_name, pos={170,ypos+4}, size={112.00,14.00}, frame=0
1350  TitleBox t_host, win=$win_name, variable=url
1351 
1352  ypos += 270-272
1353  Button b_attach,win=$win_name, pos={170,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
1354  Button b_attach,win=$win_name, help={"Attach the selected graph to an existing ELOG entry (correct ID required)."}
1355  Button b_attach,win=$win_name, fcolor=(56576,60928,47872)
1356  Button b_reply,win=$win_name, pos={220,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
1357  Button b_reply,win=$win_name, help={"Submit form data to ELOG as a reply to an existing message (correct ID required)."}
1358  Button b_reply,win=$win_name, fcolor=(56576,60928,47872)
1359  Button b_login,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
1360  Button b_login,win=$win_name, help={"Enter user name and password."}
1361  Button b_login,win=$win_name, fcolor=(56576,60928,47872)
1362  Button b_logout,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_logout,title="Logout"
1363  Button b_logout,win=$win_name, help={"Clear user name and password."}
1364  Button b_logout,win=$win_name, fcolor=(56576,60928,47872), disable=3
1365 
1366  SetWindow $win_name, hook(elogPanelHook)=PearlElog#elog_panel_hook
1367  SetWindow $win_name, userdata(logbook)=logbook
1368 
1369  ypos += 160-270
1370  TitleBox t_message,win=$win_name, pos={10,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
1371  DefineGuide UGH0={FT,ypos},UGV0={FL,70},UGH1={FB,-52},UGV1={FR,-2}
1372  NewNotebook /F=0 /N=Message /OPTS=3 /W=(115,404,345,341)/FG=(UGV0,UGH0,UGV1,UGH1) /HOST=#
1373  Notebook kwTopWin, defaultTab=20, statusWidth=0, autoSave=0
1374  Notebook kwTopWin fSize=10, fStyle=0, textRGB=(0,0,0)
1375  RenameWindow #,Message
1376  string nb_name = win_name + "#Message"
1377  SetActiveSubwindow ##
1378 
1379  // restore recently used attributes and message
1380  svar /z /sdfr=df_persistent recent
1381  if (svar_exists(recent) && (strlen(recent) > 0))
1382  set_panel_attributes(win_name, recent)
1383  endif
1384  svar /z /sdfr=df_persistent recent_message
1385  if (svar_exists(recent_message) && (strlen(recent_message) > 0))
1386  set_panel_message(win_name, recent_message)
1387  endif
1388  Notebook $nb_name selection={startOfFile,startOfFile}, findText={"",1}
1389 
1390  setdatafolder savedf
1391  return win_name
1392 };
1393 
1394 static variable elog_panel_hook(WMWinHookStruct* s){
1395  STRUCT WMWinHookStruct &s
1396 
1397  Variable hookResult = 0
1398 
1399  switch(s.eventCode)
1400  case 0:// activate
1401  string logbook = GetUserData(s.winName, "", "logbook")
1402  if (strlen(logbook) > 0)
1403  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1404  svar /sdfr=df_volatile url
1405  url = format_url(logbook)
1406  update_attach_items(logbook)
1407  endif
1408  break
1409  case 6:// resize
1410  // move bottom-aligned controls when the window is resized
1411  variable b_top = s.winRect.bottom + 4
1412  Button b_submit,pos={70,b_top}
1413  Button b_clear,pos={120,b_top}
1414  TitleBox t_host, pos={170,b_top+4}
1415  b_top += 24
1416  Button b_attach,pos={170,b_top}
1417  Button b_reply,pos={220,b_top}
1418  Button b_login, pos={550,b_top}
1419  Button b_logout, pos={550,b_top}
1420  b_top += 2
1421  SetVariable sv_id,pos={51,b_top}
1422  break
1423  endswitch
1424 
1425  return hookResult// 0 if nothing done, else 1
1426 };
1427 
1428 static const variable kAttachColSel = 0;
1429 static const variable kAttachColTitle = 1;
1430 static const variable kAttachColName = 2;
1431 
1433 static variable update_attach_items(string logbook){
1434  string logbook
1435 
1436  dfref savedf = getdatafolderdfr()
1437  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1438  wave /t /sdfr=df_volatile attach_list
1439  wave /sdfr=df_volatile attach_sel
1440 
1441  if (!waveexists(attach_list))
1442  return -1
1443  endif
1444  string names = WinList("*", ";", "WIN:1;VISIBLE:1")
1445  names = SortList(names, ";", 16)
1446 
1447  // remove closed graphs
1448  variable i
1449  variable k
1450  variable n = DimSize(attach_list, 0)
1451  string s
1452  for (i = n-1; i >= 0; i -= 1)
1453  s = attach_list[i][kAttachColName]
1454  if (WhichListItem(s, names) < 0)
1455  DeletePoints /M=0 i, 1, attach_list, attach_sel
1456  endif
1457  endfor
1458 
1459  // add new graphs
1460  n = ItemsInList(names)
1461  for (i = 0; i < n; i += 1)
1462  s = StringFromList(i, names)
1463  FindValue /text=s /txop=4 /z attach_list
1464  if (v_value < 0)
1465  k = DimSize(attach_list, 0)
1466  Redimension /n=(k+1,3) attach_list, attach_sel
1467  //InsertPoints /M=0 k, 1, attach_list, attach_sel
1468  attach_list[k][kAttachColSel] = ""
1469  attach_list[k][kAttachColTitle] = ""
1470  attach_list[k][kAttachColName] = s
1471  attach_sel[k][kAttachColSel] = 32
1472  attach_sel[k][kAttachColTitle] = 0
1473  attach_sel[k][kAttachColName] = 0
1474  endif
1475  endfor
1476 
1477  // update titles
1478  n = DimSize(attach_list, 0)
1479  for (i = n-1; i >= 0; i -= 1)
1480  s = attach_list[i][kAttachColName]
1481  getwindow /z $s, wtitle
1482  if (v_flag == 0)
1483  attach_list[i][kAttachColTitle] = s_value
1484  else
1485  attach_list[i][kAttachColTitle] = s
1486  endif
1487  endfor
1488 
1489  setdatafolder savedf
1490  return 0
1491 };
1492 
1494 static variable move_attach_item(string logbook, variable item, variable distance){
1495  string logbook
1496  variable item
1497  variable distance
1498 
1499  dfref savedf = getdatafolderdfr()
1500  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1501  wave /t /sdfr=df_volatile attach_list
1502  wave /sdfr=df_volatile attach_sel
1503  variable n = DimSize(attach_list, 0)
1504  variable dest = item + distance
1505 
1506  if ((item >= 0) && (item < n) && (dest >= 0) && (dest < n))
1507  string name = attach_list[item][kAttachColName]
1508  variable sel = attach_sel[item][kAttachColSel]
1509  DeletePoints /M=0 item, 1, attach_list, attach_sel
1510  InsertPoints /M=0 dest, 1, attach_list, attach_sel
1511  attach_list[dest][kAttachColName] = name
1512  update_attach_items(logbook)
1513  attach_sel[dest][kAttachColSel] = sel
1514  endif
1515 };
1516 
1518 static variable bp_attach_updown(WMButtonAction* ba){
1519  STRUCT WMButtonAction &ba
1520 
1521  switch( ba.eventCode )
1522  case 2:// mouse up
1523  string logbook = GetUserData(ba.win, "", "logbook")
1524  ControlInfo /w=$ba.win lb_attach
1525  variable row = v_value
1526  dfref df = $s_datafolder
1527  wave /t /sdfr=df attach_list = $s_value
1528  if (cmpstr(ba.ctrlName, "b_attach_up") == 0)
1529  // up button
1530  if (row >= 1)
1531  move_attach_item(logbook, row, -1)
1532  ListBox lb_attach, win=$ba.win, selRow=(row-1)
1533  endif
1534  else
1535  // down button
1536  if (row < DimSize(attach_list, 0) - 1)
1537  move_attach_item(logbook, row, +1)
1538  ListBox lb_attach, win=$ba.win, selRow=(row+1)
1539  endif
1540  endif
1541  break
1542  case -1:// control being killed
1543  break
1544  endswitch
1545 
1546  return 0
1547 };
1548 
1550 static variable bp_submit(WMButtonAction* ba){
1551  STRUCT WMButtonAction &ba
1552 
1553  switch( ba.eventCode )
1554  case 2:// mouse up
1555  string logbook = GetUserData(ba.win, "", "logbook")
1556  string attributes
1557  string message
1558  string graphs
1559  attributes = get_panel_attributes(ba.win)
1560  message = get_panel_message(ba.win)
1561  graphs = get_panel_graphs(ba.win)
1562 
1563  variable id
1564  if (cmpstr(ba.ctrlName, "b_reply") == 0)
1565  // Reply button
1566  ControlInfo /w=$ba.win sv_id
1567  id = v_value
1568  else
1569  // Submit button
1570  id = 0
1571  endif
1572 
1573  if ((elog_validate_attributes(logbook, attributes) == 0) && (strlen(message) > 0))
1574  variable result
1575  result = elog_create_entry(logbook, attributes, message, graphs=graphs, replyto=id)
1576  if (result == 0)
1577  dfref df = get_elog_df(logbook, kdfPersistent)
1578  svar /sdfr=df recent
1579  recent = attributes
1580  svar /sdfr=df recent_message
1581  recent_message = message
1582  else
1583  abort "Submission failed. Error code " + num2str(result) + "."
1584  endif
1585  else
1586  abort "Submission failed due to missing/invalid attribute."
1587  endif
1588  break
1589  case -1:// control being killed
1590  break
1591  endswitch
1592 
1593  return 0
1594 };
1595 
1597 static variable bp_attach_top(WMButtonAction* ba){
1598  STRUCT WMButtonAction &ba
1599 
1600  switch( ba.eventCode )
1601  case 2:// mouse up
1602  string graphs = WinName(0, 1, 1)
1603  set_panel_graphs(ba.win, graphs)
1604  break
1605  case -1:// control being killed
1606  break
1607  endswitch
1608 
1609  return 0
1610 };
1611 
1613 static variable bp_attach_allnone(WMButtonAction* ba){
1614  STRUCT WMButtonAction &ba
1615 
1616  switch( ba.eventCode )
1617  case 2:// mouse up
1618  string logbook = GetUserData(ba.win, "", "logbook")
1619  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1620  wave /sdfr=df_volatile attach_sel
1621  if (cmpstr(ba.ctrlName, "b_attach_all") == 0)
1622  attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] | 16
1623  else
1624  attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] & ~16
1625  endif
1626  break
1627  case -1:// control being killed
1628  break
1629  endswitch
1630 
1631  return 0
1632 };
1633 
1634 static variable bp_attach(WMButtonAction* ba){
1635  STRUCT WMButtonAction &ba
1636 
1637  switch( ba.eventCode )
1638  case 2:// mouse up
1639  string logbook = GetUserData(ba.win, "", "logbook")
1640  string graphs
1641  graphs = get_panel_graphs(ba.win)
1642 
1643  variable id
1644  ControlInfo /w=$ba.win sv_id
1645  id = v_value
1646 
1647  // TODO : is there a way around this restriction?
1648  DoAlert /T="ELOG" 1, "This operation will replace all existing attachments. Do you want to continue?"
1649 
1650  if ((id > 0) && (v_flag == 1))
1651  variable result
1652  result = elog_add_attachment(logbook, id, graphs)
1653  if (result != 0)
1654  abort "Submission failed. Error code " + num2str(result) + "."
1655  endif
1656  else
1657  abort "Submission failed due to missing/invalid attribute."
1658  endif
1659  break
1660  case -1:// control being killed
1661  break
1662  endswitch
1663 
1664  return 0
1665 };
1666 
1667 static variable bp_save_graphs(WMButtonAction* ba){
1668  STRUCT WMButtonAction &ba
1669 
1670  switch( ba.eventCode )
1671  case 2:// mouse up
1672  string logbook = GetUserData(ba.win, "", "logbook")
1673  string graphs = get_panel_graphs(ba.win)
1674  variable ngraphs = ItemsInList(graphs, ";")
1675 
1676  variable igraph
1677  string sgraph
1678  string graph_path
1679  for (igraph = 0; igraph < ngraphs; igraph += 1)
1680  sgraph = StringFromList(igraph, graphs, ";")
1681  graph_path = create_graph_file(sgraph, igraph)
1682  if (strlen(graph_path) > 0)
1683  print graph_path
1684  endif
1685  endfor
1686 
1687  break
1688  case -1:// control being killed
1689  break
1690  endswitch
1691 
1692  return 0
1693 };
1694 
1695 static variable bp_clear(WMButtonAction* ba){
1696  STRUCT WMButtonAction &ba
1697 
1698  switch( ba.eventCode )
1699  case 2:// mouse up
1700  set_panel_attributes(ba.win, "", clear=1)
1701  set_panel_message(ba.win, "")
1702  set_panel_graphs(ba.win, "")
1703  break
1704  case -1:// control being killed
1705  break
1706  endswitch
1707 
1708  return 0
1709 };
1710 
1711 static variable bp_login(WMButtonAction* ba){
1712  STRUCT WMButtonAction &ba
1713 
1714  switch( ba.eventCode )
1715  case 2:// mouse up
1716  string logbook = GetUserData(ba.win, "", "logbook")
1717  if (elog_prompt_login(logbook) == 0)
1718  Button b_login, win=$ba.win, disable=3
1719  Button b_logout, win=$ba.win, disable=0
1720  endif
1721  break
1722  case -1:// control being killed
1723  break
1724  endswitch
1725 
1726  return 0
1727 };
1728 
1729 static variable bp_logout(WMButtonAction* ba){
1730  STRUCT WMButtonAction &ba
1731 
1732  switch( ba.eventCode )
1733  case 2:// mouse up
1734  string logbook = GetUserData(ba.win, "", "logbook")
1735  elog_logout(logbook)
1736  Button b_login, win=$ba.win, disable=0
1737  Button b_logout, win=$ba.win, disable=3
1738  break
1739  case -1:// control being killed
1740  break
1741  endswitch
1742 
1743  return 0
1744 };
1745 
1746 static string get_default_panel_name(){
1747  string windowname
1748  windowname = StringFromList(0, WinList("*ElogPanel*", ";", "WIN:64"), ";")
1749  return windowname
1750 };
1751 
1759 static string get_panel_attributes(string windowname){
1760  string windowname
1761 
1762  if (strlen(windowname) == 0)
1763  windowname = get_default_panel_name()
1764  endif
1765  if (strlen(windowname) == 0)
1766  return ""
1767  endif
1768 
1769  string controls = ControlNameList(windowname, ";")
1770  string attributes = ""
1771  string control
1772  string attribute
1773  variable ico
1774  variable nco = ItemsInList(controls, ";")
1775  for (ico = 0; ico < nco; ico += 1)
1776  control = StringFromList(ico, controls, ";")
1777  attribute = GetUserData(windowname, control, "attribute")
1778  if (strlen(attribute) > 0)
1779  ControlInfo /w=$windowname $control
1780  switch(v_flag)
1781  case 2:// checkbox
1782  attributes = ReplaceNumberByKey(attribute, attributes, v_value, "=", ";")
1783  break
1784  case 3:// popupmenu
1785  case 5:// setvariable
1786  attributes = ReplaceStringByKey(attribute, attributes, s_value, "=", ";")
1787  break
1788  endswitch
1789  endif
1790  endfor
1791 
1792  return attributes
1793 };
1794 
1806 static string set_panel_attributes(string windowname, string attributes, variable clear = defaultValue){
1807  string windowname
1808  string attributes
1809  variable clear
1810 
1811  if (strlen(windowname) == 0)
1812  windowname = get_default_panel_name()
1813  endif
1814  if (strlen(windowname) == 0)
1815  return ""
1816  endif
1817  if (ParamIsDefault(clear))
1818  clear = 0
1819  endif
1820 
1821  string path
1822 
1823  string controls = ControlNameList(windowname, ";")
1824  string control
1825  string attribute
1826  string value
1827  variable numval
1828  variable ico
1829  variable nco = ItemsInList(controls, ";")
1830  for (ico = 0; ico < nco; ico += 1)
1831  control = StringFromList(ico, controls, ";")
1832  attribute = GetUserData(windowname, control, "attribute")
1833  if (strlen(attribute))
1834  value = StringByKey(attribute, attributes, "=", ";")
1835  if (strlen(value) || clear)
1836  ControlInfo /w=$windowname $control
1837  switch(v_flag)
1838  case 2:// checkbox
1839  numval = NumberByKey(attribute, attributes, "=", ";")
1840  if ((numtype(numval) != 0) && clear)
1841  numval = 0
1842  endif
1843  if (numtype(numval) == 0)
1844  CheckBox $control, value=numval, win=$windowname
1845  endif
1846  break
1847  case 3:// popupmenu
1848  PopupMenu $control, popvalue=value, win=$windowname
1849  break
1850  case 5:// setvariable
1851  SetVariable /z $control, value= _STR:value, win=$windowname
1852  break
1853  endswitch
1854  endif
1855  endif
1856  endfor
1857 
1858  return attributes
1859 };
1860 
1868 static string get_panel_message(string windowname){
1869  string windowname
1870 
1871  if (strlen(windowname) == 0)
1872  windowname = get_default_panel_name()
1873  endif
1874  if (strlen(windowname) == 0)
1875  return ""
1876  endif
1877 
1878  string nb = windowname + "#Message"
1879  notebook $nb selection={startOfFile, endOfFile}
1880  getselection notebook, $nb, 2
1881 
1882  return s_selection
1883 };
1884 
1894 static string set_panel_message(string windowname, string message){
1895  string windowname
1896  string message
1897 
1898  if (strlen(windowname) == 0)
1899  windowname = get_default_panel_name()
1900  endif
1901 
1902  string nb = windowname + "#Message"
1903  notebook $nb selection={startOfFile, endOfFile},text=message
1904 
1905  return message
1906 };
1907 
1914 static string get_panel_graphs(string windowname){
1915  string windowname// panel window name
1916 
1917  dfref savedf = getdatafolderdfr()
1918  if (strlen(windowname) == 0)
1919  windowname = get_default_panel_name()
1920  endif
1921  if (strlen(windowname) == 0)
1922  return ""
1923  endif
1924 
1925  string logbook = GetUserData(windowname, "", "logbook")
1926  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1927  wave /t /sdfr=df_volatile attach_list
1928  wave /sdfr=df_volatile attach_sel
1929  string graphs = ""
1930  string windows = ""
1931  string graphname
1932 
1933  variable n = DimSize(attach_sel, 0)
1934  variable i
1935  for (i = 0; i < n; i += 1)
1936  if (attach_sel[i][kAttachColSel] & 16)
1937  graphname = attach_list[i][kAttachColName]
1938  windows = WinList(graphname, ";", "WIN:1")
1939  if (ItemsInList(windows) == 1)
1940  graphs = AddListItem(graphname, graphs, ";", inf)
1941  endif
1942  endif
1943  endfor
1944 
1945  return graphs
1946 };
1947 
1954 static string set_panel_graphs(string windowname, string graphs){
1955  string windowname
1956  string graphs
1957 
1958  if (strlen(windowname) == 0)
1959  windowname = get_default_panel_name()
1960  endif
1961  if (strlen(windowname) == 0)
1962  return ""
1963  endif
1964 
1965  string logbook = GetUserData(windowname, "", "logbook")
1966  update_attach_items(logbook)
1967  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1968  wave /t /sdfr=df_volatile attach_list
1969  wave /sdfr=df_volatile attach_sel
1970 
1971  variable n = DimSize(attach_sel, 0)
1972  variable i
1973  string graphname
1974  for (i = 0; i < n; i += 1)
1975  graphname = attach_list[i][kAttachColName]
1976  if (WhichListItem(graphname, graphs)>= 0)
1977  attach_sel[i][kAttachColSel] = 48
1978  else
1979  attach_sel[i][kAttachColSel] = 32
1980  endif
1981  endfor
1982 };
1983 
variable elog_create_entry(string logbook, string attributes, string message, variable encoding=defaultValue, string graphs=defaultValue, variable replyto=defaultValue)
create a new entry in ELOG
Definition: pearl-elog.ipf:685
static variable AfterFileOpenHook(variable refNum, string file, string pathName, string type, string creator, variable kind)
initialize the package and reload preferences after an experiment is loaded.
Definition: pearl-elog.ipf:143
-
variable elog_add_attachment(string logbook, variable id, string graphs)
add one or more graphs to an existing ELOG entry
Definition: pearl-elog.ipf:788
+
variable elog_add_attachment(string logbook, variable id, string graphs)
add one or more graphs to an existing ELOG entry
Definition: pearl-elog.ipf:792
static const string package_path
Definition: pearl-elog.ipf:86
-
static string get_panel_graphs(string windowname)
get the names of the graphs selected for attachment
-
static variable bp_attach_updown(WMButtonAction *ba)
button procedure for the attachment up and down buttons
-
static string create_message_file(string message)
Definition: pearl-elog.ipf:957
-
static variable parse_result()
parse the result file from an elog invokation.
+
static string get_panel_graphs(string windowname)
get the names of the graphs selected for attachment
+
static variable bp_attach_updown(WMButtonAction *ba)
button procedure for the attachment up and down buttons
+
static string create_message_file(string message)
save the message to a temporary text file
Definition: pearl-elog.ipf:982
+
static variable parse_result()
parse the result file from an elog invokation.
variable elog_create_logbook(string name, string template=defaultValue)
create a new logbook.
Definition: pearl-elog.ipf:414
-
static string set_panel_attributes(string windowname, string attributes, variable clear=defaultValue)
set the fields of the ELOG panel
-
static variable bp_logout(WMButtonAction *ba)
-
static string get_default_panel_name()
-
static variable elog_panel_hook(WMWinHookStruct *s)
+
static string set_panel_attributes(string windowname, string attributes, variable clear=defaultValue)
set the fields of the ELOG panel
+
static variable bp_logout(WMButtonAction *ba)
+
static string get_default_panel_name()
+
static variable elog_panel_hook(WMWinHookStruct *s)
variable elog_config(string elog_path=defaultValue, string hostname=defaultValue, variable port=defaultValue, string subdir=defaultValue)
set global module configuration parameters
Definition: pearl-elog.ipf:473
interface for writing ELOG entries with Igor graphs as attachment.
static variable IgorBeforeNewHook(string igorApplicationNameStr)
save preferences and recent values before Igor opens a new experiment.
Definition: pearl-elog.ipf:127
-
static string set_panel_graphs(string windowname, string graphs)
update selection of graphs for attachment
+
static string set_panel_graphs(string windowname, string graphs)
update selection of graphs for attachment
variable elog_init_pearl_templates()
setup PEARL template logbooks.
Definition: pearl-elog.ipf:262
-
static string create_graph_file(string graphname, variable fileindex)
Definition: pearl-elog.ipf:976
-
static const variable kAttachColName
-
static variable bp_clear(WMButtonAction *ba)
+
static string create_graph_file(string graphname, variable fileindex)
save a graph to a temporary graphics file
+
static const variable kAttachColName
+
static variable bp_clear(WMButtonAction *ba)
variable elog_login(string logbook, string username, string password)
set username and password for login to a logbook
Definition: pearl-elog.ipf:513
-
static variable bp_attach_top(WMButtonAction *ba)
select top graph window for attachment
-
static const variable kAttachColSel
-
string PearlElogPanel(string logbook)
open a new panel for submitting data to ELOG.
+
static variable bp_attach_top(WMButtonAction *ba)
select top graph window for attachment
+
static const variable kAttachColSel
+
string PearlElogPanel(string logbook)
open a new panel for submitting data to ELOG.
variable elog_validate_attributes(string logbook, string attributes)
validate attributes
Definition: pearl-elog.ipf:653
-
static string prepare_graph_attachments(string graphs)
prepare screenshots of graph windows for attachments
Definition: pearl-elog.ipf:930
+
static string prepare_graph_attachments(string graphs)
prepare screenshots of graph windows for attachments
Definition: pearl-elog.ipf:939
static string list_logbooks(variable templates=defaultValue)
get a list of configured logbooks or templates.
Definition: pearl-elog.ipf:618
-
static variable bp_attach(WMButtonAction *ba)
-
static variable move_attach_item(string logbook, variable item, variable distance)
move an attachment item in the list of attachments
+
static variable bp_attach(WMButtonAction *ba)
+
static variable move_attach_item(string logbook, variable item, variable distance)
move an attachment item in the list of attachments
static dfr get_elog_df(string name, variable category)
get the package, logbook, or template datafolder.
Definition: pearl-elog.ipf:170
-
string elog_prompt_logbook()
prompt to open or create a logbook
-
static variable bp_save_graphs(WMButtonAction *ba)
-
static variable update_attach_items(string logbook)
update the list of attachments
-
static variable bp_login(WMButtonAction *ba)
+
string elog_prompt_logbook()
prompt to open or create a logbook
+
static variable bp_save_graphs(WMButtonAction *ba)
+
static variable update_attach_items(string logbook)
update the list of attachments
+
static variable bp_login(WMButtonAction *ba)
static const variable kdfVolatile
Definition: pearl-elog.ipf:154
static const variable kdfTemplates
Definition: pearl-elog.ipf:156
-
static string prepare_command_line(string logbook)
format the ELOG command and essential address arguments.
Definition: pearl-elog.ipf:845
-
static variable cleanup_temp_files()
delete temporary files created by the ELOG module.
-
static string get_log_path()
-
static const variable kAttachColTitle
-
static const string elog_parse_id
-
static string get_panel_message(string windowname)
get the message field of the ELOG panel
-
static string create_cmd_file(string cmd)
+
static string prepare_command_line(string logbook)
format the ELOG command and essential address arguments.
Definition: pearl-elog.ipf:853
+
static variable cleanup_temp_files()
delete temporary files created by the ELOG module.
+
static string get_log_path()
+
static const variable kAttachColTitle
+
static const string elog_parse_id
+
static string get_panel_message(string windowname)
get the message field of the ELOG panel
+
static string create_cmd_file(string cmd)
write the command line to a file.
static variable init_volatile_vars()
initialize volatile variables.
Definition: pearl-elog.ipf:340
static variable load_prefs()
load persistent package data from the preferences file.
Definition: pearl-elog.ipf:584
static const variable kdfPersistent
Definition: pearl-elog.ipf:155
static variable init_package(variable clean=defaultValue)
initialize the package data folder.
Definition: pearl-elog.ipf:217
static variable save_prefs()
save persistent package data to the preferences file.
Definition: pearl-elog.ipf:564
static const variable kdfRoot
Definition: pearl-elog.ipf:153
-
variable elog_prompt_login(string logbook)
prompt the user for login to a logbook
-
static string set_panel_message(string windowname, string message)
set the message field of the ELOG panel
+
variable elog_prompt_login(string logbook)
prompt the user for login to a logbook
+
static string set_panel_message(string windowname, string message)
set the message field of the ELOG panel
static variable IgorQuitHook(string igorApplicationNameStr)
save preferences and recent values before Igor quits.
Definition: pearl-elog.ipf:135
-
static variable bp_submit(WMButtonAction *ba)
button procedure for the Submit and Reply buttons
-
static variable bp_attach_allnone(WMButtonAction *ba)
select/deselect all graph windows for attachment
-
static string get_panel_attributes(string windowname)
get a list of attributes from the fields of the ELOG panel.
-
static const string elog_success_msg
-
static string get_timestamp(string sep)
Definition: pearl-elog.ipf:949
+
static variable bp_submit(WMButtonAction *ba)
button procedure for the Submit and Reply buttons
+
static variable bp_attach_allnone(WMButtonAction *ba)
select/deselect all graph windows for attachment
+
static string get_panel_attributes(string windowname)
get a list of attributes from the fields of the ELOG panel.
+
static const string elog_success_msg
+
static string get_timestamp(string sep)
Definition: pearl-elog.ipf:958
variable elog_logout(string logbook)
clear username and password of a logbook or all logbooks.
Definition: pearl-elog.ipf:533
variable pearl_elog(string logbook)
main function to initialize ELOG and to open an ELOG panel.
Definition: pearl-elog.ipf:97
-
static string format_url(string logbook)
format the URL for display to the user
Definition: pearl-elog.ipf:894
+
static string format_url(string logbook)
format the URL for display to the user
Definition: pearl-elog.ipf:902
static const string package_name
Definition: pearl-elog.ipf:85
@@ -178,7 +178,7 @@ $(document).ready(function(){initNavTree('pearl-elog_8ipf_source.html','');}); @@ -606,7 +609,7 @@ Variables -

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

+

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

@@ -650,7 +653,7 @@ Variables -

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

+

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

@@ -677,7 +680,7 @@ Variables -

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

@@ -862,7 +865,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 159 of file pearl-pshell-import.ipf.

+

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

@@ -926,7 +929,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 697 of file pearl-pshell-import.ipf.

+

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

@@ -980,7 +983,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 1083 of file pearl-pshell-import.ipf.

+

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

@@ -1046,7 +1049,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi - +
fileIDID of open HDF5 file from psh5_open_file().
scanpathpath to scan group in the HDF5 file.
datasetnamename of the dataset. 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/ScientaSpectrum". in this case, the dataset is loaded into a sub-folder named "region1".
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_paramparameter string for the reduction function.
progressprogress window.
    @@ -1066,7 +1069,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    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.
    Version
    this function supports regions as of version 1.03.
    -

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

    +

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

    @@ -1140,7 +1143,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 1276 of file pearl-pshell-import.ipf.

    +

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

    @@ -1197,7 +1200,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 1140 of file pearl-pshell-import.ipf.

    +

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

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

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

    +

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

    - +
    @@ -1253,12 +1256,6 @@ global string s_scanpaths in new data folder contains a list of scan groups insi - - - - - - @@ -1301,10 +1298,8 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    load a preview image from a PShell data file.

    the data wave is loaded into the current data folder. attributes are loaded into the attr subfolder. existing waves in attr are deleted.

    -
    Warning
    EXPERIMENTAL this function uses the root:pearl_area:preview data folder. existing data there may be deleted!
    Parameters
    string psh5_load_preview ( string ANickName,
    string  APathName,
    - @@ -1316,7 +1311,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    name of loaded preview wave.
    -

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

    +

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

    @@ -1394,7 +1389,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.
    Todo:
    load scan positions.
    -

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

    +

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

    @@ -1445,7 +1440,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 562 of file pearl-pshell-import.ipf.

    +

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

    @@ -1506,7 +1501,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 369 of file pearl-pshell-import.ipf.

    +

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

    @@ -1546,7 +1541,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 522 of file pearl-pshell-import.ipf.

    +

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

    @@ -1578,7 +1573,8 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

    the info string contains up to three lines which are made up of the following information:

    • number of scan positions.
    • dataset names of scan positioners.
    • -
    • dataset names of detectors.
    • +
    • dataset names of detectors (without region names).
    • +
    • region names
    Parameters
    ANickNamedestination wave name. the wave is created in the current data folder.
    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
    load_data1 (default): load data; 0: do not load data
    @@ -1589,7 +1585,7 @@ global string s_scanpaths in new data folder contains a list of scan groups insi
    Returns
    newline terminated string.
    -

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

    +

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

    @@ -1636,7 +1632,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 630 of file pearl-pshell-import.ipf.

    +

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

    @@ -1693,7 +1689,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 831 of file pearl-pshell-import.ipf.

    +

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

    @@ -1758,7 +1754,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 945 of file pearl-pshell-import.ipf.

    +

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

    @@ -1809,7 +1805,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 99 of file pearl-pshell-import.ipf.

    +

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

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

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

    +

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

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

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

+

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

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

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

+

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

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

convert text wave to list.

-

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

+

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

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

convert numeric wave to list.

-

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

+

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

@@ -2059,6 +2055,22 @@ global string s_scanpaths in new data folder contains a list of scan groups insi

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

+ + + +
+
+ + + + +
const variable kDetectorSensitivity = 4
+
+ +

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

+ +

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

+
@@ -2147,7 +2159,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 
99 variable psh5_open_file(string ANickName, string APathName, string AFileName){
100  string ANickName
101  string APathName
102  string AFileName
103 
104  setdatafolder root:
105  newdatafolder /s /o $("root:" + ANickName)
106  dfref fileDF = GetDataFolderDFR()
107 
108  variable fileID
109  HDF5OpenFile /P=$APathName /R fileID as AFileName
110  if (v_flag == 0)
111  string /g s_filepath
112  string /g s_scanpaths
113  s_filepath = s_path + s_filename
114  s_scanpaths = psh5_list_scans(fileID)
115  else
116  fileID = 0
117  endif
118 
119  return fileID
120 };
121 
129 variable psh5_close_file(variable fileID){
130  variable fileID
131 
132  HDF5CloseFile fileID
133 };
134 
159 string psh5_load_complete(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue){
160  string ANickName
161  string APathName
162  string AFileName
163  variable load_data
164  variable load_attr
165 
166  if (ParamIsDefault(load_data))
167  load_data = 1
168  endif
169  if (ParamIsDefault(load_attr))
170  load_attr = 1
171  endif
172 
173  dfref saveDF = GetDataFolderDFR()
174 
175  // performance monitoring
176  variable timerRefNum
177  variable /g psh5_perf_secs
178  timerRefNum = startMSTimer
179 
180  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
181  if (fileID)
182  dfref fileDF = GetDataFolderDFR()
183  svar s_filepath
184  svar s_scanpaths
185  AFileName = s_filepath
186  print "loading " + s_filepath + "\r"
187 
188  variable ig
189  variable ng = ItemsInList(s_scanpaths, ";")
190  string sg
191  string folder
192 
193  for (ig = 0; ig < ng; ig += 1)
194  sg = StringFromList(ig, s_scanpaths, ";")
195  folder = ReplaceString("/", sg, "")
196  folder = ReplaceString(" ", folder, "")
197  folder = CleanupName(folder, 0)
198  setdatafolder fileDF
199  newdatafolder /s /o $folder
200  psh5_load_scan_complete(fileID, sg, load_data=load_data, load_attr=load_attr)
201  endfor
202 
203  psh5_close_file(fileID)
204  else
205  AFileName = ""
206  endif
207 
208  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
209 
210  setdatafolder saveDF
211  return AFileName
212 };
213 
245 string psh5_load_preview(string ANickName, string APathName, string AFileName, variable load_data = defaultValue, variable load_attr = defaultValue, string pref_scans = defaultValue, string pref_datasets = defaultValue){
246  string ANickName
247  string APathName
248  string AFileName
249  variable load_data
250  variable load_attr
251  string pref_scans
252  string pref_datasets
253 
254  if (ParamIsDefault(load_data))
255  load_data = 1
256  endif
257  if (ParamIsDefault(load_attr))
258  load_attr = 1
259  endif
260  if (ParamIsDefault(pref_scans))
261  pref_scans = "*scan1*;"
262  endif
263  if (ParamIsDefault(pref_datasets))
264  pref_datasets = ""
265  endif
266 
267  dfref saveDF = GetDataFolderDFR()
268  setdatafolder root:
269  newdatafolder /o/s pearl_area
270  newdatafolder /o/s preview
271 
272  variable fileID
273  string scanpaths = ""
274  string dataname = ""
275 
276  // performance monitoring
277  variable timerRefNum
278  variable /g adh5_perf_secs
279  timerRefNum = startMSTimer
280 
281  HDF5OpenFile /P=$APathName /R /Z fileID as AFileName
282  if (v_flag == 0)
283  AFileName = s_path + s_filename
284  dfref fileDF = GetDataFolderDFR()
285 
286  scanpaths = psh5_list_scans(fileID)
287  variable ng = ItemsInList(scanpaths)
288  variable ig
289  string sg
290  variable np = ItemsInList(pref_scans)
291  variable ip
292  string sp
293  variable found = 0
294  if (ng > 0)
295  for (ip = 0; ip < np; ip += 1)
296  for (ig = 0; ig < ng; ig += 1)
297  sg = StringFromList(ig, scanpaths)
298  sp = StringFromList(ip, pref_scans)
299  if (StringMatch(sg, sp))
300  found = 1
301  break
302  endif
303  endfor
304  if (found)
305  break
306  endif
307  endfor
308  if (!found)
309  ig = 0
310  endif
311  sg = StringFromList(ig, scanpaths)
312 
313  if (load_attr)
314  setdatafolder fileDF
315  newdatafolder /o/s attr
316  killwaves /a/z
317  psh5_load_scan_attrs(fileID, sg)
318  endif
319 
320  setdatafolder fileDF
321  dataname = psh5_load_scan_preview(fileID, sg, set_scale=load_attr, pref_datasets=pref_datasets)
322 
323  wave /z data = $dataname
324  string destpath = GetDataFolder(1, saveDF) + ANickName
325  if (waveexists(data))
326  duplicate /o data, $destpath
327  wave /z data = $destpath
328  else
329  print "no data found in file " + AFileName
330  endif
331 
332  else
333  print "no scans found in file " + AFileName
334  endif
335 
336  HDF5CloseFile fileID
337  endif
338 
339  if (timerRefNum >= 0)
340  adh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
341  endif
342 
343  setdatafolder saveDF
344  return dataname
345 };
346 
369 string psh5_load_scan_complete(variable fileID, string scanpath, variable load_data = defaultValue, variable load_attr = defaultValue){
370  variable fileID
371  string scanpath
372  variable load_data
373  variable load_attr
374 
375  if (ParamIsDefault(load_data))
376  load_data = 1
377  endif
378  if (ParamIsDefault(load_attr))
379  load_attr = 1
380  endif
381 
382  dfref saveDF = GetDataFolderDFR()
383 
384  dfref dataDF = GetDataFolderDFR()
385  string wavenames
386  string attrnames
387  psh5_load_scan_meta(fileID, scanpath)
388  if (load_attr)
389  newdatafolder /s /o attr
390  attrnames = psh5_load_scan_attrs(fileID, scanpath)
391  endif
392  if (load_data)
393  setdatafolder dataDF
394  wavenames = psh5_load_scan_data(fileID, scanpath)
395  endif
396  if (load_data && load_attr)
397  setdatafolder dataDF
399  endif
400 
401  setdatafolder saveDF
402  return wavenames
403 };
404 
413 string psh5_list_scans(variable fileID){
414  variable fileID
415 
416  HDF5ListGroup /F /TYPE=1 fileID, "/"
417 
418  variable ig
419  variable ng = ItemsInList(S_HDF5ListGroup, ";")
420  string sg
421  string scans = ""
422 
423  for (ig = 0; ig < ng; ig += 1)
424  sg = StringFromList(ig, S_HDF5ListGroup, ";")
425  if (cmpstr(sg[1,4], "scan") == 0)
426  scans = AddListItem(sg, scans, ";", inf)
427  endif
428  endfor
429 
430  return scans
431 };
432 
448 string psh5_list_scan_datasets(variable fileID, string scanpath, variable include_regions = defaultValue){
449  variable fileID
450  string scanpath
451  variable include_regions
452 
453  if (ParamIsDefault(include_regions))
454  include_regions = 0
455  endif
456  string result
457 
458  HDF5ListGroup /TYPE=2 /Z fileID, scanpath
459  result = S_HDF5ListGroup
460 
461  if (include_regions)
462  HDF5ListGroup /R /TYPE=2 /Z fileID, scanpath
463  variable n = ItemsInList(S_HDF5ListGroup)
464  variable i
465  string ds
466  string region_datasets
467  for (i = 0; i < n; i += 1)
468  ds = StringFromList(i, S_HDF5ListGroup)
469  if (StringMatch(ds, "region*/*"))
470  //region_datasets = psh5_list_scan_datasets(fileID, ReplaceString("//", scanpath + "/" + region, "/"), include_regions=0)
471  result = AddListItem(ds, result, ";", inf)
472  endif
473  endfor
474  endif
475 
476  return result
477 };
478 
489 string psh5_list_scan_regions(variable fileID, string scanpath){
490  variable fileID
491  string scanpath
492 
493  HDF5ListGroup /TYPE=1 /Z fileID, scanpath
494  variable n = ItemsInList(S_HDF5ListGroup)
495  variable i
496  string result = ""
497  string s
498  for (i = 0; i < n; i += 1)
499  s = StringFromList(i, S_HDF5ListGroup)
500  if (StringMatch(s, "region*"))
501  result = AddListItem(s, result, ";", inf)
502  endif
503  endfor
504 
505  return result
506 };
507 
522 string psh5_load_scan_data(variable fileID, string scanpath){
523  variable fileID
524  string scanpath
525 
526  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
527  variable nds = ItemsInList(datasets)
528  variable ids
529  string sds
530  string sw
531  string wavenames = ""
532  for (ids = 0; ids < nds; ids += 1)
533  sds = StringFromList(ids, datasets)
534  sw = psh5_load_dataset(fileID, scanpath, sds, set_scale=0)
535  wavenames = AddListItem(sw, wavenames, ";", inf)
536  endfor
537 
538  return wavenames
539 };
540 
562 string psh5_load_scan_attrs(variable fileID, string scanpath, variable attr_sets = defaultValue){
563  variable fileID
564  string scanpath
565  variable attr_sets
566 
567  if (ParamIsDefault(attr_sets))
568  attr_sets = 1
569  endif
570 
571  string attr_path = ReplaceString("//", scanpath + "/attrs", "/")
572  string attr_list = ""
573  if (attr_sets & 1)
574  HDF5ListGroup /TYPE=2 /Z fileID, attr_path
575  if (!v_flag)
576  attr_list = S_HDF5ListGroup
577  endif
578  endif
579 
580  variable ids
581  variable nds
582  string sds
583 
584  if (attr_sets & 2)
585  nds = ItemsInList(kScientaScalingDatasets, ";")
586  for (ids = 0; ids < nds; ids += 1)
587  sds = StringFromList(ids, kScientaScalingDatasets)
588  if (WhichListItem(sds, attr_list) < 0)
589  attr_list = AddListItem(sds, attr_list, ";", inf)
590  endif
591  endfor
592  endif
593 
594  nds = ItemsInList(attr_list, ";")
595  string wavenames = ""
596  for (ids = 0; ids < nds; ids += 1)
597  sds = StringFromList(ids, attr_list, ";")
598  HDF5LoadData /O /Q /Z fileID, attr_path + "/" + sds
599  if (!v_flag)
600  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
601  endif
602  endfor
603  wavenames = ReplaceString(";;", wavenames, ";")
604 
605  return wavenames
606 };
607 
630 string psh5_load_scan_meta(variable fileID, string scanpath){
631  variable fileID
632  string scanpath
633  string wavenames = ""
634 
635  HDF5LoadData /O /Q /Z /A="Dimensions" /N=ScanDimensions /TYPE=1 fileID, scanpath
636  if (!v_flag)
637  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
638  else
639  make /n=1 /o ScanDimensions
640  ScanDimensions = 0
641  wavenames = AddListItem("ScanDimensions", wavenames, ";", inf)
642  endif
643  HDF5LoadData /O /Q /Z /A="Readables" /N=ScanReadables /TYPE=1 fileID, scanpath
644  if (!v_flag)
645  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
646  else
647  make /n=1 /o /t ScanReadables
648  ScanReadables[0] = "ScientaSpectrum"
649  wavenames = AddListItem("ScanReadables", wavenames, ";", inf)
650  endif
651  HDF5LoadData /O /Q /Z /A="Writables" /N=ScanWritables /TYPE=1 fileID, scanpath
652  if (!v_flag)
653  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
654  endif
655  HDF5LoadData /O /Q /Z /A="Steps" /N=ScanSteps /TYPE=1 fileID, scanpath
656  if (!v_flag)
657  wavenames = AddListItem(s_wavenames, wavenames, ";", inf)
658  endif
659  wavenames = ReplaceString(";;", wavenames, ";")
660 
661  return wavenames
662 };
663 
697 string psh5_load_dataset(variable fileID, string scanpath, string datasetname, variable set_scale = defaultValue){
698  variable fileID
699  string scanpath
700  string datasetname
701  variable set_scale
702 
703  if (ParamIsDefault(set_scale))
704  set_scale = 1
705  endif
706 
707  dfref base_df = GetDataFolderDFR()
708 
709  string datasetpath
710  datasetpath = scanpath + "/" + datasetname
711  datasetpath = ReplaceString("//", datasetpath, "/")
712 
713  string regionname
714  string regionpath
715  if (ItemsInList(datasetname, "/") >= 2)
716  regionname = StringFromList(0, datasetname, "/")
717  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
718  datasetname = RemoveListItem(0, datasetname, "/")
719  NewDataFolder /o/s $regionname
720  else
721  regionname = ""
722  regionpath = scanpath
723  endif
724 
725  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
726  InitHDF5DataInfo(di)
727  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
728  if (err != 0)
729  print "error accessing detector/data"
730  return ""
731  endif
732 
733  string dataname
734  if (di.ndims < 2)
735  HDF5LoadData /O /Q /Z fileID, datasetpath
736  dataname = StringFromList(0, S_waveNames)
737  else
738  dataname = psh5_load_dataset_slabs(fileID, regionpath, datasetname)
739  endif
740 
741  wave /z data = $dataname
742  if (waveexists(data))
743  psh5_load_dataset_meta(fileID, regionpath, datasetname, data)
744  ps_set_dimlabels(data)
745  if (set_scale)
746  ps_scale_dataset(data)
747  endif
748  else
749  dataname = ""
750  endif
751 
752  setdatafolder base_df
753  return dataname
754 };
755 
769 static string select_dataset(string file_datasets, string pref_datasets){
770  string file_datasets
771  string pref_datasets
772 
773  variable index
774  variable nds = ItemsInList(file_datasets)
775  variable ids
776  string sds = ""
777  string mds = ""
778  variable np = ItemsInList(pref_datasets)
779  variable ip
780  string sp
781  variable found = 0
782  if (nds > 0)
783  for (ip = 0; ip < np; ip += 1)
784  for (ids = 0; ids < nds; ids += 1)
785  sds = StringFromList(ids, file_datasets)
786  index = ItemsInList(sds, "/") - 1
787  mds = StringFromList(index, sds, "/")
788  sp = StringFromList(ip, pref_datasets)
789  if (StringMatch(mds, sp))
790  found = 1
791  break
792  endif
793  endfor
794  if (found)
795  break
796  endif
797  endfor
798  if (!found)
799  ids = 0
800  sds = StringFromList(ids, file_datasets)
801  endif
802  endif
803 
804  return sds
805 };
806 
831 string psh5_load_scan_preview(variable fileID, string scanpath, variable set_scale = defaultValue, string pref_datasets = defaultValue){
832  variable fileID
833  string scanpath
834  variable set_scale
835  string pref_datasets
836 
837  if (ParamIsDefault(set_scale))
838  set_scale = 1
839  endif
840  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
841  pref_datasets = kPreviewDatasets
842  endif
843 
844  dfref saveDF = GetDataFolderDFR()
845  dfref dataDF = saveDF
846 
847  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
848  string datasetname = select_dataset(datasets, pref_datasets)
849  string datasetpath
850  datasetpath = scanpath + "/" + datasetname
851  datasetpath = ReplaceString("//", datasetpath, "/")
852 
853  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
854  InitHDF5DataInfo(di)
855  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
856  if (err != 0)
857  print "error accessing detector/data"
858  return ""
859  endif
860 
861  string dataname
862  if (di.ndims < 2)
863  HDF5LoadData /O /Q /Z fileID, datasetpath
864  dataname = StringFromList(0, S_waveNames)
865  wave /z data = $dataname
866  if (waveexists(data))
867  ps_set_dimlabels(data)
868  endif
869  else
870  variable dim2start = 0
871  variable dim2count = 1
872  variable dim3start = 0
873  variable dim3count = 1
874  if (di.ndims >= 3)
875  dim2start = floor(di.dims[2] / 2)
876  dim2count = 1
877  endif
878  if (di.ndims >= 4)
879  dim3start = floor(di.dims[3] / 2)
880  dim3count = 1
881  endif
882 
883  dataname = psh5_load_dataset_slab(fileID, scanpath, datasetname, dim2start, dim2count, dim3start, dim3count)
884  endif
885 
886  wave /z data = $dataname
887  if (waveexists(data))
888  if (set_scale)
889  setdatafolder dataDF
890  string positioners
891  string positioner
892  string positionerpath
893  positioners = psh5_load_scan_meta(fileID, scanpath)
894  wave /t /z ScanWritables
895  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
896  positioner = ScanWritables[0]
897  if (strlen(positioner) > 0)
898  positionerpath = scanpath + "/" + positioner
899  positionerpath = ReplaceString("//", positionerpath, "/")
900  HDF5LoadData /O /Q /Z fileID, positionerpath
901  endif
902  endif
903 
904  setdatafolder dataDF
905  newdatafolder /o/s attr
906  killwaves /a/z
907  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
908  setdatafolder dataDF
909  ps_scale_dataset(data)
910  endif
911  else
912  dataname = ""
913  endif
914 
915  return dataname
916 };
917 
945 string psh5_load_scan_section(variable fileID, string scanpath, variable dim, variable set_scale = defaultValue, string pref_datasets = defaultValue){
946  variable fileID
947  string scanpath
948  variable dim
949  variable set_scale
950  string pref_datasets
951 
952  // select first dimension (future argument)
953  // 0 = first dimension is x axis (energy of scienta image)
954  dim = 0
955 
956  if (ParamIsDefault(set_scale))
957  set_scale = 1
958  endif
959  if (ParamIsDefault(pref_datasets) || (strlen(pref_datasets) == 0))
960  pref_datasets = kPreviewDatasets
961  endif
962 
963  dfref saveDF = GetDataFolderDFR()
964  dfref dataDF = saveDF
965 
966  string datasets = psh5_list_scan_datasets(fileID, scanpath)
967  string datasetname = select_dataset(datasets, pref_datasets)
968  string datasetpath
969  datasetpath = scanpath + "/" + datasetname
970  datasetpath = ReplaceString("//", datasetpath, "/")
971  string dataname = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
972  string destname = dataname[0,29] + num2str(dim)
973 
974  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
975  InitHDF5DataInfo(di)
976  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
977  if (err != 0)
978  print "error accessing detector/data"
979  return ""
980  else if (di.ndims != 3)
981  print "error: rank of dataset != 3"
982  return ""
983  endif
984 
985  variable idx, idy, idz, idt
986  variable transpose = WhichListItem(dataname, kTransposedDatasets) >= 0
987  if (transpose)
988  idx = 1
989  idy = 0
990  else
991  idx = 0
992  idy = 1
993  endif
994  idz = 2
995  idt = 3
996 
997  variable nx, ny, nz
998  nx = di.dims[idx]
999  ny = di.dims[idy]
1000  nz = di.dims[idz]
1001 
1002  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
1003  wave slab
1004  slab[][%Start] = 0
1005  slab[][%Stride] = 1
1006  slab[][%Count] = 1
1007  slab[][%Block] = 1
1008 
1009  if (dim == 0)
1010  slab[idy][%Start] = floor(ny / 2)
1011  slab[idx][%Block] = nx
1012  make /n=(nx,nz) /o $destname
1013  else
1014  slab[idx][%Start] = floor(nx / 2)
1015  slab[idy][%Block] = ny
1016  make /n=(ny,nz) /o $destname
1017  endif
1018  slab[idz][%Block] = nz
1019  wave data = $destname
1020  data = 0
1021 
1022  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
1023  if (!v_flag)
1024  wave slabdata
1025  if (transpose)
1026  data += slabdata[0][p][q][0]
1027  else
1028  data += slabdata[p][0][q][0]
1029  endif
1030  endif
1031  killwaves /z slab, slabdata
1032 
1033  if (set_scale)
1034  make /n=(1,1,1) /free dummy
1035  ps_set_dimlabels2(dummy, dataname)
1036  setdimlabel 0, -1, $GetDimLabel(dummy, dim, -1), data
1037  setdimlabel 1, -1, $kScanDimLabel, data
1038 
1039  setdatafolder dataDF
1040  string positioners
1041  string positioner
1042  string positionerpath
1043  positioners = psh5_load_scan_meta(fileID, scanpath)
1044  wave /t /z ScanWritables
1045  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
1046  positioner = ScanWritables[0]
1047  if (strlen(positioner) > 0)
1048  positionerpath = scanpath + "/" + positioner
1049  positionerpath = ReplaceString("//", positionerpath, "/")
1050  HDF5LoadData /O /Q /Z fileID, positionerpath
1051  endif
1052  endif
1053 
1054  setdatafolder dataDF
1055  newdatafolder /o/s attr
1056  killwaves /a/z
1057  psh5_load_scan_attrs(fileID, scanpath, attr_sets=2)
1058  setdatafolder dataDF
1059  ps_scale_dataset(data)
1060  endif
1061 
1062  return destname
1063 };
1064 
1083 variable psh5_load_dataset_meta(variable fileID, string datapath, string datasetname, wave datawave){
1084  variable fileID
1085  string datapath
1086  string datasetname
1087  wave datawave
1088 
1089  dfref saveDF = GetDataFolderDFR()
1090  SetDataFolder NewFreeDataFolder()
1091 
1092  string datasetpath = datapath + "/" + datasetname
1093  datasetpath = ReplaceString("//", datasetpath, "/")
1094  string wnote
1095 
1096  HDF5LoadData /O /Q /Z /A="Writable Dimension" /N=WriteDim fileID, datasetpath
1097  if (!v_flag)
1098  wave WriteDim
1099  // scan dimension starts at 1
1100  sprintf wnote, "ScanDimension=%u", WriteDim[0]
1101  Note datawave, wnote
1102  endif
1103 
1104  HDF5LoadData /O /Q /Z /A="Writable Index" /N=WriteIndex fileID, datasetpath
1105  if (!v_flag)
1106  wave WriteIndex
1107  sprintf wnote, "WriteableIndex=%u", WriteIndex[0]
1108  Note datawave, wnote
1109  endif
1110 
1111  HDF5LoadData /O /Q /Z /A="Readable Index" /N=ReadIndex fileID, datasetpath
1112  if (!v_flag)
1113  wave ReadIndex
1114  sprintf wnote, "ReadableIndex=%u", ReadIndex[0]
1115  Note datawave, wnote
1116  endif
1117 
1118  setdatafolder saveDF
1119  return 0
1120 };
1121 
1140 string psh5_load_dataset_slabs(variable fileID, string datapath, string datasetname, variable progress = defaultValue){
1141  variable fileID
1142  string datapath
1143  string datasetname
1144  variable progress
1145 
1146  if (ParamIsDefault(progress))
1147  progress = 1
1148  endif
1149 
1150  variable result = 0
1151  string datasetpath
1152  string datawavename
1153  datasetpath = datapath + "/" + datasetname
1154  datasetpath = ReplaceString("//", datasetpath, "/")
1155  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
1156 
1157  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
1158  InitHDF5DataInfo(di)
1159  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
1160  if (err != 0)
1161  print "error accessing detector/data"
1162  return ""
1163  endif
1164  if (di.ndims < 2)
1165  print "error: rank of dataset < 2"
1166  return ""
1167  else if (di.ndims < 3)
1168  progress = 0
1169  endif
1170 
1171  variable idx, idy, idz, idt, izt
1172  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
1173  if (transpose)
1174  idx = 1
1175  idy = 0
1176  else
1177  idx = 0
1178  idy = 1
1179  endif
1180  idz = 2
1181  idt = 3
1182 
1183  variable nx, ny, nz, nt, nzt
1184  nx = di.dims[idx]
1185  ny = di.dims[idy]
1186  nz = di.dims[idz]
1187  nt = di.dims[idt]
1188  make /n=(nx,ny,nz,nt) /o $datawavename
1189  wave data = $datawavename
1190 
1191  nz = max(nz, 1)
1192  nt = max(nt, 1)
1193  nzt = nz * nt
1194  izt = 0
1195  if (progress)
1196  display_progress_panel("HDF5 Import", "Loading data...", nzt)
1197  endif
1198 
1199  // load data image by image
1200  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
1201  wave slab
1202  slab[][%Start] = 0
1203  slab[][%Stride] = 1
1204  slab[][%Count] = 1
1205  slab[][%Block] = 1
1206  slab[idx][%Block] = nx
1207  slab[idy][%Block] = ny
1208 
1209  variable iz, it
1210  for (iz = 0; iz < nz; iz += 1)
1211  for (it = 0; it < nt; it += 1)
1212  slab[idz][%Start] = iz
1213  slab[idt][%Start] = it
1214  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
1215  wave slabdata// 2D, 3D, or 4D with singletons
1216  if (transpose)
1217  data[][][iz][it] = slabdata[q][p][0][0]
1218  else
1219  data[][][iz][it] = slabdata[p][q][0][0]
1220  endif
1221 
1222  // progress window
1223  izt += 1
1224  if (progress)
1225  if (update_progress_panel(izt))
1226  result = -4// user abort
1227  break
1228  endif
1229  endif
1230  endfor
1231  if (result < 0)
1232  break
1233  endif
1234  endfor
1235 
1236  if (progress)
1238  endif
1239 
1240  killwaves /z slab, slabdata
1241  if (!result)
1242  ps_set_dimlabels(data)
1243  return datawavename
1244  else
1245  killwaves /z data
1246  return ""
1247  endif
1248 };
1249 
1276 string psh5_load_dataset_slab(variable fileID, string datapath, string datasetname, variable dim2start, variable dim2count, variable dim3start, variable dim3count){
1277  variable fileID
1278  string datapath
1279  string datasetname
1280  variable dim2start
1281  variable dim2count
1282  variable dim3start
1283  variable dim3count
1284 
1285  string datasetpath
1286  string datawavename
1287  datasetpath = datapath + "/" + datasetname
1288  datasetpath = ReplaceString("//", datasetpath, "/")
1289  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
1290 
1291  STRUCT HDF5DataInfo di
1292  InitHDF5DataInfo(di)
1293  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
1294  if (err != 0)
1295  print "error accessing detector/data"
1296  return ""
1297  endif
1298  if (di.ndims < 2)
1299  print "error: rank of dataset < 2"
1300  return ""
1301  endif
1302 
1303  variable idx, idy, idz, idt
1304  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
1305  if (transpose)
1306  idx = 1
1307  idy = 0
1308  else
1309  idx = 0
1310  idy = 1
1311  endif
1312  idz = 2
1313  idt = 3
1314 
1315  variable nx, ny
1316  nx = di.dims[idx]
1317  ny = di.dims[idy]
1318  make /n=(nx,ny) /o $datawavename
1319  wave data = $datawavename
1320  data = 0
1321 
1322  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
1323  wave slab
1324  slab[][%Start] = 0
1325  slab[][%Stride] = 1
1326  slab[][%Count] = 1
1327  slab[][%Block] = 1
1328  slab[idx][%Block] = nx
1329  slab[idy][%Block] = ny
1330 
1331  variable iz, it
1332  variable navg = 0
1333  variable dim2end = dim2start + dim2count - 1
1334  variable dim3end = dim3start + dim3count - 1
1335  for (iz = dim2start; iz <= dim2end; iz += 1)
1336  for (it = dim3start; it <= dim3end; it += 1)
1337  slab[idz][%Start] = iz
1338  slab[idt][%Start] = it
1339  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
1340  if (!v_flag)
1341  wave slabdata
1342  if (transpose)
1343  data += slabdata[q][p][0][0]
1344  else
1345  data += slabdata[p][q][0][0]
1346  endif
1347  navg += 1
1348  endif
1349  endfor
1350  endfor
1351  if (navg)
1352  data /= navg
1353  endif
1354 
1355  killwaves /z slab, slabdata
1356  ps_set_dimlabels(data)
1357  return datawavename
1358 };
1359 
1375 variable ps_set_dimlabels(wave data){
1376  wave data
1377 
1378  ps_set_dimlabels2(data, NameOfWave(data))
1379 };
1380 
1394 variable ps_set_dimlabels2(wave data, string name){
1395  wave data
1396  string name
1397 
1398  variable dummy
1399  try
1400  // intrinsic dimensions
1401  strswitch(name)
1402  case "ScientaImage":
1403  setdimlabel 0, -1, $kEnergyDimLabel, data
1404  setdimlabel 1, -1, $kAngleDimLabel, data
1405  if (WaveDims(data) >= 3)
1406  setdimlabel 2, -1, $kScanDimLabel, data
1407  endif
1408  AbortOnRTE
1409  break
1410  case "ImageAngleDistribution":
1411  case "ScientaAngleDistribution":
1412  if (WaveDims(data) >= 2)
1413  setdimlabel 0, -1, $kScanDimLabel, data
1414  setdimlabel 1, -1, $kAngleDimLabel, data
1415  else
1416  setdimlabel 0, -1, $kAngleDimLabel, data
1417  endif
1418  AbortOnRTE
1419  break
1420  case "ScientaSpectrum":
1421  case "ImageEnergyDistribution":
1422  case "ScientaEnergyDistribution":
1423  if (WaveDims(data) >= 2)
1424  setdimlabel 0, -1, $kScanDimLabel, data
1425  setdimlabel 1, -1, $kEnergyDimLabel, data
1426  else
1427  setdimlabel 0, -1, $kEnergyDimLabel, data
1428  endif
1429  AbortOnRTE
1430  break
1431  default:
1432  if (WaveDims(data) == 1)
1433  setdimlabel 0, -1, $kScanDimLabel, data
1434  AbortOnRTE
1435  else
1436  return 1
1437  endif
1438  endswitch
1439  catch
1440  dummy = GetRTError(1)
1441  return 2
1442  endtry
1443  return 0
1444 };
1445 
1451 static dfr find_scan_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  else
1459  dfref scanDF = dataDF
1460  endif
1461  return scanDF
1462 };
1463 
1468 static dfr find_attr_folder(dfref dataDF){
1469  dfref dataDF
1470 
1471  dfref attrDF = dataDF:attr
1472  if (!DataFolderRefStatus(attrDF))
1473  string df = GetDataFolder(1, dataDF) + ":"
1474  dfref scanDF = $df
1475  dfref attrDF = scanDF:attr
1476  endif
1477  return attrDF
1478 };
1479 
1497  dfref scanDF = GetDataFolderDFR()
1498  dfref attrDF = find_attr_folder(scanDF)
1499 
1500  make /n=3 /free lo, hi
1501  make /n=3 /t /free ax, un
1502  wave /t /z /SDFR=scanDF ScanReadables
1503  if (WaveExists(ScanReadables))
1504  variable isr
1505  variable nsr = numpnts(ScanReadables)
1506  string ssr
1507  string sdf
1508  for (isr = 0; isr < nsr; isr += 1)
1509  setdatafolder scanDF
1510  ssr = ScanReadables[isr]
1511  if (ItemsInList(ssr, "/") >= 2)
1512  sdf = StringFromList(0, ssr, "/")
1513  ssr = RemoveListItem(0, ssr, "/")
1514  setdatafolder $sdf
1515  endif
1516  wave /z wsr=$ssr
1517  if (WaveExists(wsr))
1518  ps_detect_scale(ax, lo, hi, un)
1519  ps_scale_dataset_2(wsr, ax, lo, hi, un)
1520  endif
1521  endfor
1522  endif
1523  setdatafolder scanDF
1524 };
1525 
1542 variable ps_scale_dataset(wave data){
1543  wave data
1544 
1545  dfref saveDF = GetDataFolderDFR()
1546  dfref dataDF = GetWavesDataFolderDFR(data)
1547 
1548  setdatafolder dataDF
1549  make /n=3 /free lo, hi
1550  make /n=3 /t /free ax, un
1551  ps_detect_scale(ax, lo, hi, un)
1552  ps_scale_dataset_2(data, ax, lo, hi, un)
1553  setdatafolder saveDF
1554 };
1555 
1556 static wave find_scale_wave(string name, dfref dataDF, dfref scanDF, dfref attrDF){
1557  string name
1558  dfref dataDF
1559  dfref scanDF
1560  dfref attrDF
1561 
1562  wave /SDFR=dataDF /Z w = $name
1563  if (!WaveExists(w))
1564  wave /SDFR=scanDF /Z w = $name
1565  if (!WaveExists(w))
1566  wave /SDFR=attrDF /Z w = $name
1567  endif
1568  endif
1569  return w
1570 };
1571 
1613 variable ps_detect_scale(wave ax, wave lo, wave hi, wave un){
1614  wave /t ax
1615  wave lo
1616  wave hi
1617  wave /t un
1618 
1619  dfref dataDF = GetDataFolderDFR()
1620  dfref scanDF = find_scan_folder(dataDF)
1621  dfref attrDF = find_attr_folder(dataDF)
1622 
1623  redimension /n=4 lo, hi, un, ax
1624  setdimlabel 0, 0, $kEnergyDimLabel, lo, hi, un, ax
1625  setdimlabel 0, 1, $kAngleDimLabel, lo, hi, un, ax
1626  setdimlabel 0, 2, $kScanDimLabel, lo, hi, un, ax
1627  setdimlabel 0, 3, $kDataDimLabel, lo, hi, un, ax
1628 
1629  // default values
1630  lo[%$kEnergyDimLabel] = 0
1631  hi[%$kEnergyDimLabel] = 1
1632  un[%$kEnergyDimLabel] = "eV"
1633  ax[%$kEnergyDimLabel] = "Ekin"
1634 
1635  lo[%$kAngleDimLabel] = -1
1636  hi[%$kAngleDimLabel] = 1
1637  un[%$kAngleDimLabel] = "arb."
1638  un[%$kAngleDimLabel] = "slice"
1639 
1640  lo[%$kScanDimLabel] = 0
1641  hi[%$kScanDimLabel] = 1
1642  un[%$kScanDimLabel] = "arb."
1643  ax[%$kScanDimLabel] = "scan"
1644 
1645  lo[%$kDataDimLabel] = 0
1646  hi[%$kDataDimLabel] = 0
1647  un[%$kDataDimLabel] = "arb."
1648  ax[%$kDataDimLabel] = "value"
1649 
1650  wave /SDFR=attrDF /T /Z LensMode
1651  wave /Z ChannelBegin = find_scale_wave("ScientaChannelBegin", dataDF, scanDF, attrDF)
1652  wave /Z ChannelEnd = find_scale_wave("ScientaChannelEnd", dataDF, scanDF, attrDF)
1653  wave /Z SliceBegin = find_scale_wave("ScientaSliceBegin", dataDF, scanDF, attrDF)
1654  wave /Z SliceEnd = find_scale_wave("ScientaSliceEnd", dataDF, scanDF, attrDF)
1655 
1656  // lens mode can give more detail
1657  if (waveexists(LensMode) && (numpnts(LensMode) >= 1))
1658  strswitch(LensMode[0])
1659  case "Angular45":
1660  lo[%$kAngleDimLabel] = -45/2
1661  hi[%$kAngleDimLabel] = +45/2
1662  un[%$kAngleDimLabel] = ""
1663  ax[%$kAngleDimLabel] = "angle"
1664  break
1665  case "Angular60":
1666  lo[%$kAngleDimLabel] = -60/2
1667  hi[%$kAngleDimLabel] = +60/2
1668  un[%$kAngleDimLabel] = ""
1669  ax[%$kAngleDimLabel] = "angle"
1670  break
1671  case "Transmission":
1672  un[%$kAngleDimLabel] = "arb."
1673  ax[%$kAngleDimLabel] = "offset"
1674  break
1675  endswitch
1676  endif
1677 
1678  // best option if scales are explicit in separate waves
1679  if (waveexists(ChannelBegin) && waveexists(ChannelEnd) && (numpnts(ChannelBegin) >= 1) && (numpnts(ChannelEnd) >= 1))
1680  lo[%$kEnergyDimLabel] = ChannelBegin[0]
1681  hi[%$kEnergyDimLabel] = ChannelEnd[0]
1682  endif
1683  if (waveexists(SliceBegin) && waveexists(SliceEnd) && (numpnts(SliceBegin) >= 1) && (numpnts(SliceEnd) >= 1))
1684  lo[%$kAngleDimLabel] = SliceBegin[0]
1685  hi[%$kAngleDimLabel] = SliceEnd[0]
1686  endif
1687 
1688  wave /z /t /SDFR=scanDF ScanWritables
1689  if (WaveExists(ScanWritables))
1690  wave /z /SDFR=scanDF scanner = $ScanWritables[0]
1691  if (!WaveExists(scanner))
1692  wave /z /SDFR=attrDF scanner = $ScanWritables[0]
1693  endif
1694  if (WaveExists(scanner) && (numpnts(scanner) >= 1))
1695  lo[%$kScanDimLabel] = scanner[0]
1696  hi[%$kScanDimLabel] = scanner[numpnts(scanner)-1]
1697  ax[%$kScanDimLabel] = NameOfWave(scanner)
1698  strswitch(NameOfWave(scanner))
1699  case "Eph":
1700  ax[%$kScanDimLabel] = "photon energy"
1701  un[%$kScanDimLabel] = "eV"
1702  break
1703  case "ManipulatorX":
1704  case "ManipulatorY":
1705  case "ManipulatorZ":
1706  case "FocusYTrans":
1707  case "FocusZTrans":
1708  case "RefocusYTrans":
1709  case "RefocusZTrans":
1710  case "ExitSlitY":
1711  un[%$kScanDimLabel] = "mm"
1712  break
1713  case "ExitSlit":
1714  un[%$kScanDimLabel] = "m"
1715  break
1716  case "ManipulatorTheta":
1717  case "ManipulatorTilt":
1718  case "ManipulatorPhi":
1719  un[%$kScanDimLabel] = ""
1720  break
1721  case "FocusXRot":
1722  case "FocusYRot":
1723  case "FocusZRot":
1724  case "RefocusXRot":
1725  case "RefocusYRot":
1726  case "RefocusZRot":
1727  un[%$kScanDimLabel] = "mrad"
1728  break
1729  endswitch
1730  endif
1731  endif
1732 };
1733 
1767 variable ps_scale_dataset_2(wave data, wave ax, wave lo, wave hi, wave un){
1768  wave data
1769  wave /t ax
1770  wave lo
1771  wave hi
1772  wave /t un
1773 
1774  string sdim
1775  sdim = GetDimLabel(data, 0, -1)
1776  if (strlen(sdim))
1777  setscale /i x lo[%$sdim], hi[%$sdim], un[%$sdim], data
1778  Note data, "AxisLabelX=" + ax[%$sdim]
1779  endif
1780 
1781  sdim = GetDimLabel(data, 1, -1)
1782  if (strlen(sdim))
1783  setscale /i y lo[%$sdim], hi[%$sdim], un[%$sdim], data
1784  Note data, "AxisLabelY=" + ax[%$sdim]
1785  endif
1786 
1787  sdim = GetDimLabel(data, 2, -1)
1788  if (strlen(sdim))
1789  setscale /i z lo[%$sdim], hi[%$sdim], un[%$sdim], data
1790  Note data, "AxisLabelZ=" + ax[%$sdim]
1791  endif
1792 
1793  string data_unit = un[%$kDataDimLabel]
1794  string data_label = ax[%$kDataDimLabel]
1795  if (cmpstr(data_unit, "arb.") == 0)
1796  strswitch(NameOfWave(data))
1797  case "SampleCurrent":
1798  case "RefCurrent":
1799  case "AuxCurrent":
1800  data_unit = "A"
1801  data_label = "current"
1802  break
1803  case "MachineCurrent":
1804  data_unit = "mA"
1805  data_label = "current"
1806  break
1807  endswitch
1808  endif
1809  setscale d 0, 0, data_unit, data
1810  Note data, "AxisLabelD=" + data_label
1811  Note data, "Dataset=" + NameOfWave(data)
1812 };
1813 
1853 string psh5_load_reduced(string ANickName, string APathName, string AFileName, funcref reduction_func, string reduction_param, variable progress = defaultValue){
1854  string ANickName
1855  string APathName
1856  string AFileName
1857  funcref adh5_default_reduction reduction_func
1858  string reduction_param
1859  variable progress
1860 
1861  if (ParamIsDefault(progress))
1862  progress = 1
1863  endif
1864 
1865  dfref saveDF = GetDataFolderDFR()
1866 
1867  // performance monitoring
1868  variable timerRefNum
1869  variable /g psh5_perf_secs
1870  timerRefNum = startMSTimer
1871 
1872  variable fileID = psh5_open_file(ANickName, APathName, AFileName)
1873  string wavenames = ""
1874  if (fileID)
1875  dfref fileDF = GetDataFolderDFR()
1876  svar s_filepath
1877  svar s_scanpaths
1878  AFileName = s_filepath
1879  print "loading " + s_filepath + "\r"
1880 
1881  variable ig = 0
1882  variable ng = ItemsInList(s_scanpaths)
1883  string scanpath
1884  string folder
1885  string positioners
1886  string positioner
1887  string positionerpath
1888 
1889  scanpath = StringFromList(ig, s_scanpaths)
1890  folder = ReplaceString("/", scanpath, "")
1891  folder = ReplaceString(" ", folder, "")
1892  folder = CleanupName(folder, 0)
1893  setdatafolder fileDF
1894  newdatafolder /s /o $folder
1895  dfref dataDF = GetDataFolderDFR()
1896  positioners = psh5_load_scan_meta(fileID, scanpath)
1897  newdatafolder /s /o attr
1898  killwaves /a/z
1899  psh5_load_scan_attrs(fileID, scanpath)
1900  setdatafolder dataDF
1901  wave /t /z ScanWritables
1902  if (waveexists(ScanWritables) && (numpnts(ScanWritables) >= 1))
1903  positioner = ScanWritables[0]
1904  if (strlen(positioner) > 0)
1905  positionerpath = scanpath + "/" + positioner
1906  positionerpath = ReplaceString("//", positionerpath, "/")
1907  HDF5LoadData /O /Q /Z fileID, positionerpath
1908  endif
1909  endif
1910 
1911  setdatafolder dataDF
1912  string datasets = psh5_list_scan_datasets(fileID, scanpath, include_regions=1)
1913  string dataset = select_dataset(datasets, "ScientaImage")
1914  wavenames = psh5_load_dataset_reduced(fileID, scanpath, dataset, reduction_func, reduction_param, progress=progress)
1915 
1916  psh5_close_file(fileID)
1917  endif
1918 
1919  if (timerRefNum >= 0)
1920  psh5_perf_secs = stopMSTimer(timerRefNum) / 1e6
1921  endif
1922 
1923  setdatafolder saveDF
1924  return wavenames
1925 };
1926 
1927 
1976 string psh5_load_dataset_reduced(variable fileID, string scanpath, string datasetname, funcref reduction_func, string reduction_param, variable progress = defaultValue, variable nthreads = defaultValue){
1977  variable fileID
1978  string scanpath
1979  string datasetname
1980  funcref adh5_default_reduction reduction_func
1981  string reduction_param
1982  variable progress
1983  variable nthreads
1984 
1985  if (ParamIsDefault(progress))
1986  progress = 1
1987  endif
1988  if (ParamIsDefault(nthreads))
1989  nthreads = -1
1990  endif
1991 
1992  dfref base_df = GetDataFolderDFR()
1993  variable result = 0
1994  string datasetpath
1995  string datawavename
1996  string wavenames = ""
1997 
1998  datasetpath = scanpath + "/" + datasetname
1999  datasetpath = ReplaceString("//", datasetpath, "/")
2000  datawavename = StringFromList(ItemsInList(datasetpath, "/") - 1, datasetpath, "/")
2001 
2002  string regionname
2003  string regionpath
2004  if (ItemsInList(datasetname, "/") >= 2)
2005  regionname = StringFromList(0, datasetname, "/")
2006  regionpath = ReplaceString("//", scanpath + "/" + regionname, "/")
2007  datasetname = RemoveListItem(0, datasetname, "/")
2008  NewDataFolder /o/s $regionname
2009  else
2010  regionname = ""
2011  regionpath = scanpath
2012  endif
2013 
2014  STRUCT HDF5DataInfo di// Defined in HDF5 Browser.ipf.
2015  InitHDF5DataInfo(di)
2016  variable err = HDF5DatasetInfo(fileID, datasetpath, 0, di)
2017  if (err != 0)
2018  print "error accessing detector/data"
2019  result = -1
2020  return wavenames
2021  endif
2022  if (di.ndims < 2)
2023  print "error: rank of dataset < 2"
2024  result = -2
2025  return wavenames
2026  else if (di.ndims < 3)
2027  progress = 0
2028  endif
2029 
2030  variable idx, idy, idz, idt
2031  variable transpose = WhichListItem(datawavename, kTransposedDatasets) >= 0
2032  if (transpose)
2033  idx = 1
2034  idy = 0
2035  else
2036  idx = 0
2037  idy = 1
2038  endif
2039  idz = 2
2040  idt = 3
2041 
2042  variable nx, ny, nz, nt, nzt
2043  nx = di.dims[idx]
2044  ny = di.dims[idy]
2045  nz = di.dims[idz]
2046  nt = di.dims[idt]
2047  // adjust singleton dimensions
2048  nz = max(nz, 1)
2049  nt = max(nt, 1)
2050  nzt = nz * nt
2051 
2052  // load data image by image
2053  HDF5MakeHyperslabWave(GetDataFolder(1) + "slab", max(di.ndims, 4))
2054  wave slab
2055  slab[][%Start] = 0
2056  slab[][%Stride] = 1
2057  slab[][%Count] = 1
2058  slab[][%Block] = 1
2059  slab[idx][%Block] = nx
2060  slab[idy][%Block] = ny
2061 
2062  // set up multi threading
2063  if (nthreads < 0)
2064  nthreads = ThreadProcessorCount
2065  endif
2066  if (nthreads > 0)
2067  variable threadGroupID = ThreadGroupCreate(nthreads)
2068  variable ithread
2069  for (ithread = 0; ithread < nthreads; ithread += 1)
2070  ThreadStart threadGroupID, ithread, reduce_slab_worker(reduction_func)
2071  endfor
2072  else
2073  make /n=(nzt) /df /free processing_folders
2074  endif
2075 
2076  if (progress)
2077  display_progress_panel("HDF5 Import", "Loading data (step 1 of 2)...", nzt)
2078  endif
2079 
2080  make /n=(nx,ny) /d /o image_template
2081  setdimlabel 0, -1, $kEnergyDimLabel, image_template
2082  setdimlabel 1, -1, $kAngleDimLabel, image_template
2083  ps_scale_dataset(image_template)
2084 
2085  variable iz, it, izt
2086  string dfname
2087  izt = 0
2088  for (iz = 0; iz < nz; iz += 1)
2089  for (it = 0; it < nt; it += 1)
2090  // load hyperslab
2091  slab[idz][%Start] = iz
2092  slab[idt][%Start] = it
2093  dfname = "processing_" + num2str(izt)
2094  newdatafolder /s $dfname
2095  HDF5LoadData /O /Q /Z /SLAB=slab /N=slabdata fileID, datasetpath
2096 
2097  // send to processing queue
2098  duplicate image_template, image
2099  variable /g r_index = iz
2100  variable /g s_index = it
2101  string /g func_param = reduction_param
2102 
2103  if (nthreads > 0)
2104  WaveClear image
2105  ThreadGroupPutDF threadGroupID, :
2106  else
2107  processing_folders[izt] = GetDataFolderDFR()
2108  make /n=1/d profile1, profile2
2109  wave slabdata
2110  variable /g func_result
2111  func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
2112  WaveClear slabdata, image, profile1, profile2
2113  setdatafolder ::
2114  endif
2115 
2116  izt += 1
2117  // progress window
2118  if (progress)
2119  if (update_progress_panel(izt))
2120  print "user abort"
2121  result = -4
2122  break
2123  endif
2124  endif
2125  endfor
2126  endfor
2127 
2128  killwaves /z slab, slabdata, image_template
2129  if (progress)
2130  update_progress_panel(0, message="Processing data (step 2 of 2)...")
2131  endif
2132 
2133  dfref dfr
2134  for (izt = 0; (izt < nzt) && (result == 0); izt += 1)
2135  if (nthreads > 0)
2136  do
2137  dfr = ThreadGroupGetDFR(threadGroupID, 1000)
2138  if (DatafolderRefStatus(dfr) != 0)
2139  break
2140  endif
2141  if (progress)
2142  if (update_progress_panel(izt))
2143  print "user abort"
2144  result = -4
2145  break
2146  endif
2147  endif
2148  while (1)
2149  else
2150  dfr = processing_folders[izt]
2151  if (progress)
2152  if (update_progress_panel(izt))
2153  print "user abort"
2154  result = -4
2155  break
2156  endif
2157  endif
2158  endif
2159 
2160  if (result != 0)
2161  break
2162  endif
2163 
2164  nvar rr = dfr:r_index
2165  nvar ss = dfr:s_index
2166  nvar func_result = dfr:func_result
2167  wave profile1 = dfr:profile1
2168  wave profile2 = dfr:profile2
2169 
2170  if (func_result == 0)
2171  if (izt == 0)
2172  make /n=(dimsize(profile1, 0), nz, nt) /d /o ReducedData1
2173  make /n=(dimsize(profile2, 0), nz, nt) /d /o ReducedData2
2174  setdimlabel 0, -1, $getdimlabel(profile1, 0, -1), ReducedData1
2175  setdimlabel 0, -1, $getdimlabel(profile2, 0, -1), ReducedData2
2176  setdimlabel 1, -1, $kScanDimLabel, ReducedData1
2177  setdimlabel 1, -1, $kScanDimLabel, ReducedData2
2178  setscale /p x dimoffset(profile1, 0), dimdelta(profile1, 0), waveunits(profile1, 0), ReducedData1
2179  setscale /p x dimoffset(profile2, 0), dimdelta(profile2, 0), waveunits(profile2, 0), ReducedData2
2180  setscale d 0, 0, waveunits(profile1, -1), ReducedData1
2181  setscale d 0, 0, waveunits(profile2, -1), ReducedData2
2182  endif
2183  ReducedData1[][rr][ss] = profile1[p]
2184  ReducedData2[][rr][ss] = profile2[p]
2185  else
2186  print "error during data reduction."
2187  result = -3
2188  break
2189  endif
2190  endfor
2191 
2192  if (nthreads > 0)
2193  variable tstatus = ThreadGroupRelease(threadGroupID)
2194  if (tstatus == -2)
2195  print "error: thread did not terminate properly."
2196  result = -5
2197  endif
2198  else
2199  for (izt = 0; izt < nzt; izt += 1)
2200  KillDataFolder /Z processing_folders[izt]
2201  endfor
2202  endif
2203 
2204  if (result == 0)
2205  if (nz == 1)
2206  redimension /n=(-1, 0, 0) ReducedData1
2207  redimension /n=(-1, 0, 0) ReducedData2
2208  else if (nt == 1)
2209  redimension /n=(-1, nz, 0) ReducedData1
2210  redimension /n=(-1, nz, 0) ReducedData2
2211  endif
2212  wavenames = "ReducedData1;ReducedData2;"
2213  ps_scale_dataset(ReducedData1)
2214  ps_scale_dataset(ReducedData2)
2215  endif
2216  if (progress)
2218  endif
2219 
2220  setdatafolder base_df
2221  return wavenames
2222 };
2223 
2224 threadsafe static variable reduce_slab_worker(funcref reduction_func){
2225  funcref adh5_default_reduction reduction_func
2226  do
2227  // wait for job from main thread
2228  do
2229  dfref dfr = ThreadGroupGetDFR(0, 1000)
2230  if (DataFolderRefStatus(dfr) == 0)
2231  if (GetRTError(2))
2232  return 0// no more jobs
2233  endif
2234  else
2235  break
2236  endif
2237  while (1)
2238 
2239  // get input data
2240  wave slabdata = dfr:slabdata
2241  wave image = dfr:image
2242  svar func_param = dfr:func_param
2243  nvar rr = dfr:r_index
2244  nvar ss = dfr:s_index
2245 
2246  // do the work
2247  newdatafolder /s outDF
2248  make /n=1/d profile1, profile2
2249  variable /g r_index = rr
2250  variable /g s_index = ss
2251  variable /g func_result
2252  func_result = reduce_slab_image(slabdata, image, profile1, profile2, reduction_func, func_param)
2253 
2254  // send output to queue and clean up
2255  WaveClear slabdata, image, profile1, profile2
2256  ThreadGroupPutDF 0, :
2257  KillDataFolder dfr
2258  while (1)
2259 
2260  return 0
2261 };
2262 
2263 threadsafe static variable reduce_slab_image(wave slabdata, wave image, wave profile1, wave profile2, funcref reduction_func, string reduction_param){
2264  wave slabdata
2265  wave image
2266  wave profile1
2267  wave profile2
2268  funcref adh5_default_reduction reduction_func
2269  string reduction_param
2270 
2271  image = slabdata[q][p][0][0]
2272 
2273  return reduction_func(image, profile1, profile2, reduction_param)
2274 };
2275 
2290 string psh5_load_info(string APathName, string AFileName){
2291  string APathName
2292  string AFileName
2293 
2294  dfref saveDF = GetDataFolderDFR()
2295  dfref fileDF = NewFreeDataFolder()
2296  setdatafolder fileDF
2297 
2298  variable fileID
2299  string filepath
2300  string scanpaths
2301  variable nscans
2302  variable iscan
2303  string scanpath
2304  string info = ""
2305 
2306  HDF5OpenFile /P=$APathName /R fileID as AFileName
2307  if (v_flag == 0)
2308  filepath = s_path + s_filename
2309  scanpaths = psh5_list_scans(fileID)
2310  nscans = ItemsInList(scanpaths)
2311  for (iscan = 0; iscan < nscans; iscan += 1)
2312  scanpath = StringFromList(iscan, scanpaths)
2313  info = info + scanpath + "\r"
2314  info = info + psh5_load_scan_info(fileID, scanpath)
2315  endfor
2316  HDF5CloseFile fileID
2317  endif
2318 
2319  setdatafolder saveDF
2320  return info
2321 };
2322 
2336 string psh5_load_scan_info(variable fileID, string scanpath){
2337  variable fileID
2338  string scanpath
2339 
2340  string info = ""
2341  string positions = ""
2342  string positioners = ""
2343  string detectors = ""
2344 
2345  psh5_load_scan_meta(fileID, scanpath)
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  if (WaveExists(ScanReadables) && (numpnts(ScanReadables) >= 1))
2361  detectors = "detectors = " + twave2list(ScanReadables, ",")
2362  info = AddListItem(detectors, info, "\r", inf)
2363  endif
2364 
2365  return info
2366 };
2367 
2371 static string twave2list(wave wt, string sep){
2372  wave /t wt
2373  string sep
2374 
2375  string list = ""
2376  variable n = numpnts(wt)
2377  variable i
2378  for (i = 0; i < n; i += 1)
2379  list = AddListItem(wt[i], list, sep, inf)
2380  endfor
2381 
2382  return list
2383 };
2384 
2388 static string wave2list(wave w, string format, string sep){
2389  wave w
2390  string format
2391  string sep
2392 
2393  string list = ""
2394  variable n = numpnts(w)
2395  variable i
2396  string s
2397  for (i = 0; i < n; i += 1)
2398  sprintf s, format, w[i]
2399  list = AddListItem(s, list, sep, inf)
2400  endfor
2401 
2402  return list
2403 };
2404 
string psh5_list_scan_regions(variable fileID, string scanpath)
list regions of a PShell scan group.
+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.
+
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.
variable kill_progress_panel()
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.
+
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
+
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
-
string psh5_load_preview(string ANickName, 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 dfr find_scan_folder(dfref dataDF)
find the scan folder
+
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.
+
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.
-
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.
+
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.
-
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_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)
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.
+
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.
+
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.
@@ -208,7 +218,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

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

+

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

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

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

+

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

@@ -270,7 +280,71 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

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

+

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

+ +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
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

+

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.

+
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
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
  • +
  • pos1 position of peak 1
  • +
  • wid1 width of peak 1
  • +
  • pos2 position of peak 2
  • +
  • wid2 width of peak 2
  • +
  • return select result to return, either "int1" or "int2".
  • +
  • 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.
+ +

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

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

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

+

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

@@ -350,7 +424,28 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

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

+

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

+ +
+ + +
+
+ + + + + + + + +
variable prompt_gauss2_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.

+ +

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

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

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

+

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

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

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

+

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

@@ -413,7 +508,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
Returns
zero if the user clicked OK, non-zero if the user clicked Cancel.
-

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

+

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

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

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

+

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

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

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.
-

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

@@ -625,7 +720,28 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

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

+

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

+ +
+ + +
+
+ + + + + + + + +
variable test_gauss2_reduction (wave image)
+
+ +

apply the gauss2_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.

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

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

+

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

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

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

+

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

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

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

+

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

@@ -699,7 +815,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.02
5 
6 // $Id$
7 // author: matthias.muntwiler@psi.ch
8 // Copyright (c) 2013-14 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 
29 
34 
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 
66  // this function is for testing only, until we implement a proper interface
67  string param = csr_int_linbg_reduction("")
68  svar /z global_params = root:packages:pearl_explorer:s_reduction_params
69  if (svar_exists(global_params))
70  global_params = param
71  endif
72  return param
73 };
74 
75 string csr_int_linbg_reduction(string win){
76  // PRELIMINARY - function arguments may change
77 
78  // sets reduction parameters from cursors in a graph.
79  // an even number of cursors (2 or more) must be set on the image.
80  // cursor names and order do not matter,
81  // except that the alphabetically first cursor which is attached to an image selects the image.
82  // the cursors mark the following positions, from innermost to outermost pair:
83  // 1) low and high limits of peak region.
84  // 2) peak-side boundary of lower and upper background region.
85  // 3) lower and upper cropping region.
86 
87  string win
88 
89  // read all cursor positions
90  variable ic
91  string sc
92  variable nc = 10
93  make /n=(nc) /free positions
94  variable np = 0
95  wave /z image = $""
96  string imagename = ""
97  string tracename = ""
98  string info
99 
100  for (ic = 0; ic < nc; ic += 1)
101  sc = num2char(char2num("A") + ic)
102  wave /z wc = CsrWaveRef($sc, win)
103  info = CsrInfo($sc, win)
104  tracename = StringByKey("TNAME", info, ":", ";")
105  if (waveexists(wc) && (wavedims(wc) == 2))
106  if (!waveexists(image))
107  wave image = wc
108  imagename = tracename
109  endif
110  if (cmpstr(tracename, imagename) == 0)
111  positions[np] = pcsr($sc, win)
112  np += 1
113  endif
114  endif
115  endfor
116 
117  np = floor(np / 2) * 2// ignore odd cursor
118  redimension /n=(np) positions
119  sort positions, positions
120  // shift upper positions by one so that the rightmost pixel becomes 1.0
121  positions = p >= np / 2 ? positions + 1 : positions
122  positions = positions / dimsize(image, 0)
123 
124  // map innermost cursor pair to peak center and size
125  variable ip2 = np / 2
126  variable ip1 = ip2 - 1
127  variable Cpos = (positions[ip1] + positions[ip2]) / 2
128  variable Csize = positions[ip2] - positions[ip1]
129  if (ip1 >= 0)
130  Cpos = (positions[ip1] + positions[ip2]) / 2
131  Csize = positions[ip2] - positions[ip1]
132  else
133  // default: a small region in the center
134  Cpos = 0.5
135  Csize = 0.2
136  endif
137 
138  // background region
139  ip1 -= 1
140  ip2 += 1
141  variable Lsize
142  variable Hsize
143  if (ip1 >= 0)
144  Lsize = positions[ip1]
145  Hsize = 1 - positions[ip2]
146  else
147  // default: everything outside the peak region
148  Lsize = Cpos - Csize / 2
149  Hsize = 1 - (Cpos + Csize / 2)
150  endif
151 
152  // crop region
153  ip1 -= 1
154  ip2 += 1
155  variable Lcrop
156  variable Hcrop
157  if (ip1 >= 0)
158  Lcrop = positions[ip1]
159  Hcrop = 1 - positions[ip2]
160  else
161  // default: dead corners of the EW4000 at PEARL
162  Lcrop = 0.11
163  Hcrop = 0.11
164  endif
165  Lsize = max(Lsize - Lcrop, 0)
166  Hsize = max(Hsize - Hcrop, 0)
167 
168  string param = ""
169  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
170  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
171  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
172  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
173  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
174  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
175 
176  return param
177 };
178 
179 variable test_int_linbg(wave image){
180  // useful for testing or manual processing
181  // since the int_linbg_reduction function cannot be called from the command line directly.
182  wave image
183 
184  string param = ""
186 
187  string data1_name = "test_data1"
188  string data2_name = "test_data2"
189  duplicate /o image, $data1_name, $data2_name
190  wave w_data1 = $data1_name
191  wave w_data2 = $data2_name
192 
193  int_linbg_reduction(image, w_data1, w_data2, param)
194 };
195 
196 threadsafe variable int_linbg_reduction(wave source, wave dest1, wave dest2, string* param){
197  // data reduction function for adh5_load_reduced_detector
198  // calculates the average pixel value of each angular slice
199  // in one center and two background intervals.
200  // a background value is calculated at the center position
201  // by linear interpolation from the two background values.
202  // returns the center minus linear background in dest1.
203  // returns the Poisson one-sigma error in dest2.
204  wave source// source wave
205  // Scienta detector image, energy axis along X, angle axis along Y
206  wave dest1, dest2// destination waves
207  // each wave is a one-dimensional intensity distribution
208  // the function may redimension these waves to one of the image dimensions
209  // (it must be clear to the user which dimension this is).
210  // the meaning of dest1 and dest2 is up to the particular function,
211  // e.g. dest1 could hold the mean value and dest2 the one-sigma error,
212  // or dest1 could hold the X-profile, and dest2 the Y-profile.
213  string &param// parameters in a key1=value1;key2=value2;... list
214  // all region parameters are relative to the image size (0...1)
215  // Lcrop = size of the lower cropping region
216  // Hcrop = size of the upper cropping region
217  // Lsize = size of the lower background integration region
218  // Hsize = size of the upper background integration region
219  // Cpos = center position of the of the peak integration region
220  // Csize = size of the peak integration region
221 
222  // typical values (peak centered on detector, FWHM ~ 20 % of image)
223  // Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2
224 
225  variable nx = dimsize(source, 0)
226  variable ny = dimsize(source, 1)
227 
228  // read parameters
229  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
230  variable lsize = NumberByKey("Lsize", param, "=", ";")
231  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
232  variable hsize = NumberByKey("Hsize", param, "=", ";")
233  variable cpos = NumberByKey("Cpos", param, "=", ";")
234  variable csize = NumberByKey("Csize", param, "=", ";")
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  return 1// Cpos parameter missing
252  endif
253  if (numtype(Csize) != 0)
254  return 2// Csize parameter missing
255  endif
256 
257  variable lpos = lcrop + lsize / 2
258  variable hpos = 1 - (hcrop + hsize / 2)
259 
260  variable p0
261  variable p1
262 
263  adh5_setup_profile(source, dest1, 1)
264  adh5_setup_profile(source, dest2, 1)
265 
266  duplicate /free dest1, lbg, hbg
267  if (lsize > 0)
268  p0 = round(lcrop * nx)
269  p1 = round((lcrop + lsize) * nx)
270  ad_profile_y_w(source, p0, p1, lbg)
271  else
272  lbg = 0
273  endif
274  if (hsize > 0)
275  p0 = round((1 - hcrop - hsize) * nx)
276  p1 = round((1 - hcrop) * nx)
277  ad_profile_y_w(source, p0, p1, hbg)
278  else
279  hbg = 0
280  endif
281  if (csize > 0)
282  p0 = round((cpos - csize/2) * nx)
283  p1 = round((cpos + csize/2) * nx)
284  ad_profile_y_w(source, p0, p1, dest1)
285  else
286  dest1 = 0
287  endif
288 
289  variable scale = (cpos - lpos) / (hpos - lpos)
290  dest2 = dest1
291  dest1 -= scale * (hbg - lbg) + lbg
292  dest2 = sqrt(dest2 + scale^2 * (hbg + lbg))
293  return 0// return zero if successful, non-zero if an error occurs
294 };
295 
296 variable test_shockley_anglefit(wave image, variable branch){
297  // apply the Shockley_anglefit function to a single image
298  // useful for testing or manual processing
299  // since the Shockley_anglefit function cannot be called from the command line directly.
300  wave image
301  variable branch// +1 or -1
302 
303  string param = ""
304  param = ReplaceStringByKey("branch", param, num2str(branch), "=", ";")
305 
306  string s_branch
307  if (branch >= 0)
308  s_branch = "p"
309  else
310  s_branch = "n"
311  endif
312  string pkpos_name = "saf_pkpos_" + s_branch
313  string pkwid_name = "saf_pkwid_" + s_branch
314  duplicate /o image, $pkpos_name, $pkwid_name
315  wave w_pkpos = $pkpos_name
316  wave w_pkwid = $pkwid_name
317 
318  shockley_anglefit(image, w_pkpos, w_pkwid, param)
319 };
320 
321 variable prompt_Shockley_anglefit(string* param){
322  string &param
323 
324  variable branch = NumberByKey("branch", param, "=", ";")
325 
326  prompt branch, "Branch (-1 or +1)"
327 
328  doprompt "Shockley_anglefit_reduction Parameters", branch
329  if (v_flag == 0)
330  param = ReplaceNumberByKey("branch", param, branch, "=", ";")
331  endif
332 
333  return v_flag
334 };
335 
336 threadsafe variable Shockley_anglefit(wave source, wave dest1, wave dest2, string* param){
337  // data reduction function for adh5_load_reduced_detector
338  // specialized for analysing the Cu(111) Shockley surface state
339  // do curve fitting of one branch of the surface state
340  // the result is peak position versus energy
341  // TODO: this function contains hard-coded parameters. please generalize as necessary.
342  wave source// source wave
343  // Scienta detector image, energy axis along X, angle axis along Y
344  // the apex of the surface state must be at angle 0
345  wave dest1, dest2// destination waves
346  // dest1: peak position
347  // dest2: peak width (sigma)
348  string &param// parameters in a key1=value1;key2=value2;... list
349  // branch=-1 or +1: select negative (positive) angles for the fit interval, respectively
350 
351  variable nx = dimsize(source, 0)
352  variable ny = dimsize(source, 1)
353 
354  // read parameters
355  variable branch = NumberByKey("branch", param, "=", ";")
356 
357  // validate parameters
358  if (numtype(branch) != 0)
359  branch = +1
360  endif
361 
362  // prepare output
363  adh5_setup_profile(source, dest1, 0)
364  adh5_setup_profile(source, dest2, 0)
365  dest1 = nan
366  dest2 = nan
367 
368  // select angle range
369  // hard-coded for a particular measurement series
370  variable y0
371  variable y1
372  if (branch < 0)
373  y0 = -5
374  y1 = 0
375  else
376  y0 = 0
377  y1 = 5
378  endif
379 
380  // select energy range
381  // start at the point of highest intensity and go up 0.45 eV
382  variable p0
383  variable p1
384  variable q0
385  variable q1
386  duplicate /free dest1, center
387  q0 = round((y0 - dimoffset(source, 1)) / dimdelta(source, 1))
388  q1 = round((y1 - dimoffset(source, 1)) / dimdelta(source, 1))
389  ad_profile_x_w(source, q0, q1, center)
390  wavestats /q/m=1 center
391  p0 = round((v_maxloc - dimoffset(source, 0)) / dimdelta(source, 0))
392  p1 = round((v_maxloc + 0.4 - dimoffset(source, 0)) / dimdelta(source, 0))
393 
394  // prepare intermediate data buffer
395  make /n=(ny)/d/free profile
396  setscale /p x dimoffset(source,1), dimdelta(source,1), waveunits(source,1), profile
397 
398  variable pp
399  for (pp = p0; pp <= p1; pp += 1)
400  profile = source[pp][p]
401  curvefit /Q /NTHR=1 /W=2 gauss profile(y0,y1)
402  wave w_coef
403  dest1[pp] = w_coef[2]
404  dest2[pp] = w_coef[3]
405  endfor
406  return 0// return zero if successful, non-zero if an error occurs
407 };
408 
409 variable prompt_int_quadbg_reduction(string* param){
410  string &param
411 
412  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
413  variable Lsize = NumberByKey("Lsize", param, "=", ";")
414  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
415  variable Hsize = NumberByKey("Hsize", param, "=", ";")
416  variable Cpos = NumberByKey("Cpos", param, "=", ";")
417  variable Csize = NumberByKey("Csize", param, "=", ";")
418 
419  prompt Lcrop, "Lower cropping region"
420  prompt Hcrop, "Upper cropping region"
421  prompt Lsize, "Lower background region"
422  prompt Hsize, "Upper background region"
423  prompt Cpos, "Center position"
424  prompt Csize, "Center integration region"
425 
426  doprompt "int_quadbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
427  if (v_flag == 0)
428  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
429  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
430  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
431  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
432  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
433  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
434  endif
435 
436  return v_flag
437 };
438 
439 variable test_int_quadbg(wave image){
440  // useful for testing or manual processing
441  // since the int_quadbg_reduction function cannot be called from the command line directly.
442  wave image
443 
444  string param = ""
446 
447  string data1_name = "test_data1"
448  string data2_name = "test_data2"
449  duplicate /o image, $data1_name, $data2_name
450  wave w_data1 = $data1_name
451  wave w_data2 = $data2_name
452 
453  int_quadbg_reduction(image, w_data1, w_data2, param)
454 };
455 
456 threadsafe variable int_quadbg_reduction(wave source, wave dest1, wave dest2, string* param){
457  // data reduction function for adh5_load_reduced_detector
458  // integrates peak area minus a quadratic backgrouind
459  wave source// source wave
460  // Scienta detector image, energy axis along X, angle axis along Y
461  wave dest1, dest2// destination waves
462  string &param// parameters in a key1=value1;key2=value2;... list
463  // all region parameters are relative to the image size (0...1)
464  // Lcrop = size of the lower cropping region
465  // Hcrop = size of the upper cropping region
466  // Lsize = size of the lower background integration region
467  // Hsize = size of the upper background integration region
468  // Cpos = center position of the of the peak integration region
469  // Csize = size of the peak integration region
470 
471  // typical values (peak centered on detector, FWHM ~ 20 % of image)
472  // Lcrop=0.11;Hcrop=0.11;Lsize=0.2;Hsize=0.2;Cpos=0.5;Csize=0.2
473 
474  variable nx = dimsize(source, 0)
475  variable ny = dimsize(source, 1)
476 
477  // read parameters
478  variable lcrop = NumberByKey("Lcrop", param, "=", ";")
479  variable lsize = NumberByKey("Lsize", param, "=", ";")
480  variable hcrop = NumberByKey("Hcrop", param, "=", ";")
481  variable hsize = NumberByKey("Hsize", param, "=", ";")
482  variable cpos = NumberByKey("Cpos", param, "=", ";")
483  variable csize = NumberByKey("Csize", param, "=", ";")
484 
485  // validate parameters
486  // background parameters are optional, center parameter is required.
487  if (numtype(lcrop) != 0)
488  lcrop = 0
489  endif
490  if (numtype(lsize) != 0)
491  lsize = 0
492  endif
493  if (numtype(hcrop) != 0)
494  hcrop = 0
495  endif
496  if (numtype(hsize) != 0)
497  hsize = 0
498  endif
499  if (numtype(Cpos) != 0)
500  return 1// Cpos parameter missing
501  endif
502  if (numtype(Csize) != 0)
503  return 2// Csize parameter missing
504  endif
505 
506  // crop boundaries
507  variable pcl = round(lcrop * nx)
508  variable pch = round((1 - hcrop) * nx)
509  // fit boundaries
510  variable pfl = round((lcrop + lsize) * nx)
511  variable pfh = round((1 - hcrop - hsize) * nx)
512  // integration boundaries
513  variable pil = round((cpos - csize/2) * nx)
514  variable pih = round((cpos + csize/2) * nx)
515 
516  adh5_setup_profile(source, dest1, 0)
517  adh5_setup_profile(source, dest2, 0)
518 
519  // prepare intermediate data buffer
520  make /n=(nx) /d /free profile, mask, fit
521  setscale /p x dimoffset(source,0), dimdelta(source,0), waveunits(source,0), profile, mask, fit
522  mask = ((p >= pcl) && (p < pfl)) || ((p >= pfh) && (p < pch))
523 
524  variable qq
525  variable sp, sf
526  variable xil = x2pnt(profile, pil)
527  variable xih = x2pnt(profile, pih)
528 
529  make /n=3 /free /d w_coef
530  for (qq = 0; qq < ny; qq += 1)
531  profile = source[p][qq]
532  curvefit /Q /NTHR=1 /W=2 poly 3, kwCWave=w_coef, profile /M=mask
533  fit = poly(w_coef, x)
534  sp = sum(profile, xil, xih)
535  sf = sum(fit, xil, xih)
536  dest1[qq] = sp - sf
537  dest2[qq] = sqrt(sp)
538  endfor
539 
540  return 0// return zero if successful, non-zero if an error occurs
541 };
542 
543 variable scienta_norm(wave w, variable x){
544  wave w
545  variable x
546 
547  return w[0] * (x^2 - w[1]^2)
548 };
549 
550 wave fit_scienta_ang_transm(wave data, wave params){
551  wave data// measured angular distribution (1D)
552  wave /z params
553 
554  if (!waveexists(params))
555  make /n=12 /o params
556  endif
557  redimension /n=12/d params
558 
559  variable h = wavemax(data) - wavemin(data)
560  params[0] = h / 2
561  params[1] = 0
562  params[2] = 7
563  params[3] = h / 4
564  params[4] = -23
565  params[5] = 4
566  params[6] = h / 4
567  params[7] = +23
568  params[8] = 4
569  params[9] = h / 2
570  params[10] = 0
571  params[11] = -0.001
572  FuncFit /NTHR=0 /q scienta_ang_transm params data
573 
574  return params
575 };
576 
577 threadsafe variable scienta_ang_transm(wave w, variable x){
578  // parameterized angular transmission function of the analyser
579  wave w// coefficients
580  // w[0] = amplitude gauss 1
581  // w[1] = position gauss 1
582  // w[2] = width gauss 1
583  // w[3] = amplitude gauss 2
584  // w[4] = position gauss 2
585  // w[5] = width gauss 2
586  // w[6] = amplitude gauss 3
587  // w[7] = position gauss 3
588  // w[8] = width gauss 3
589  // w[9] = constant background
590  // w[10] = linear background
591  // w[11] = quadratic background
592  variable x
593 
594  make /free /n=4 /d w_int
595  w_int[0] = 0
596  w_int[1,] = w[p - 1]
597  variable pk1 = gauss1d(w_int, x)
598  w_int[1,] = w[p + 2]
599  variable pk2 = gauss1d(w_int, x)
600  w_int[1,] = w[p + 5]
601  variable pk3 = gauss1d(w_int, x)
602  w_int[0,2] = w[9 + p]
603  w_int[3] = 0
604  variable bg = poly(w_int, x)
605 
606  return bg + pk1 + pk2 + pk3
607 };
608 
609 wave fit_scienta_poly_bg(wave data, wave params, variable bgterms){
610  wave data// measured distribution (2D)
611  wave /z params// wave, will be redimensioned for the correct size
612  variable bgterms// number of terms in the polynomial background: 2, 3, or 4
613 
614  if (!waveexists(params))
615  make /n=15 /o params
616  endif
617  redimension /n=15 /d params
618 
619  variable wmax = wavemax(data)
620  variable wmin = wavemin(data)
621  params[0] = 0
622  params[1] = 7
623  params[2] = 1 / 2
624  params[3] = -23
625  params[4] = 4
626  params[5] = 1 / 2
627  params[6] = +23
628  params[7] = 4
629  params[8] = 1
630  params[9] = 0
631  params[10] = -0.001
632  params[11] = wmin
633  params[12] = (wmax - wmin) / dimdelta(data,1) / dimsize(data,1)
634  params[13] = 0
635  params[14] = 0
636 
637  string h = "0000000000000"
638  if (bgterms < 3)
639  h = h + "1"
640  else
641  h = h + "0"
642  endif
643  if (bgterms < 4)
644  h = h + "1"
645  else
646  h = h + "0"
647  endif
648  FuncFitMD /NTHR=1 /q /h=h scienta_poly_bg params data
649 
650  return params
651 };
652 
653 variable scienta_poly_bg(wave w, variable e, variable a){
654  // polynomial background with
655  // parameterized angular transmission function of the analyser
656  wave w// coefficients
657  // angular transmission, varies with a
658  // amplitude of gauss 1 = 1 constant
659  // other peak amplitudes and linear terms are relative to gauss 1
660  // w[0] = position gauss 1
661  // w[1] = width gauss 1
662  // w[2] = amplitude gauss 2, relative to gauss 1
663  // w[3] = position gauss 2
664  // w[4] = width gauss 2
665  // w[5] = amplitude gauss 3, relative to gauss 1
666  // w[6] = position gauss 3
667  // w[7] = width gauss 3
668  // w[8] = constant term
669  // w[9] = linear term
670  // w[10] = quadratic term
671  // spectral background, varies with e
672  // w[11] = constant term
673  // w[12] = linear term
674  // w[13] = quadratic term
675  // w[14] = cubic term
676  variable a// detection angle
677  variable e// electron energy
678 
679  make /free /n=4 /d w_int
680  variable p0 = 0
681 
682  w_int[0] = 0
683  w_int[1] = 1
684  w_int[2,] = w[p0 + p - 2]
685  variable pk1 = gauss1d(w_int, a)
686  p0 += 2
687 
688  w_int[1,] = w[p0 + p - 1]
689  variable pk2 = gauss1d(w_int, a)
690  p0 += 3
691 
692  w_int[1,] = w[p0 + p - 1]
693  variable pk3 = gauss1d(w_int, a)
694  p0 += 3
695 
696  w_int[0,2] = w[p0 + p]
697  w_int[3] = 0
698  variable base = poly(w_int, a)
699  p0 += 3
700 
701  w_int[0,3] = w[p0 + p]
702  variable bg = poly(w_int, e)
703 
704  return bg * (base + pk1 + pk2 + pk3)
705 };
706 
715 variable prompt_redim_linbg_reduction(string* param){
716  string &param
717 
718  variable Lcrop = NumberByKey("Lcrop", param, "=", ";")
719  variable Lsize = NumberByKey("Lsize", param, "=", ";")
720  variable Hcrop = NumberByKey("Hcrop", param, "=", ";")
721  variable Hsize = NumberByKey("Hsize", param, "=", ";")
722  variable Cpos = NumberByKey("Cpos", param, "=", ";")
723  variable Csize = NumberByKey("Csize", param, "=", ";")
724 
725  prompt Lcrop, "Lower cropping region"
726  prompt Hcrop, "Upper cropping region"
727  prompt Lsize, "Lower background region"
728  prompt Hsize, "Upper background region"
729  prompt Cpos, "Center position"
730  prompt Csize, "Center integration region"
731 
732  doprompt "redim_linbg_reduction Parameters", lcrop, hcrop, lsize, hsize, cpos, csize
733  if (v_flag == 0)
734  param = ReplaceNumberByKey("Lcrop", param, Lcrop, "=", ";")
735  param = ReplaceNumberByKey("Lsize", param, Lsize, "=", ";")
736  param = ReplaceNumberByKey("Hcrop", param, Hcrop, "=", ";")
737  param = ReplaceNumberByKey("Hsize", param, Hsize, "=", ";")
738  param = ReplaceNumberByKey("Cpos", param, Cpos, "=", ";")
739  param = ReplaceNumberByKey("Csize", param, Csize, "=", ";")
740  endif
741 
742  return v_flag
743 };
744 
786 threadsafe variable redim_linbg_reduction(wave source, wave dest1, wave dest2, string* param){
787  wave source
788  wave dest1, dest2
789  string &param
790 
791  variable nx = dimsize(source, 0)
792  variable ny = dimsize(source, 1)
793 
794  duplicate /free source, source_redim
795  redimension /n=(nx * ny) source_redim
796  nx += 1
797  redimension /n=(nx, ny) source_redim
798 
799  return int_linbg_reduction(source_redim, dest1, dest2, param)
800 };
801 
802 
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)
-
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 #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)
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)
+
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)
-
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
+
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 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 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