diff --git a/README.md b/README.md index 735f244..a5e4f78 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,9 @@ PEARL Procedures should be installed according to the regular Igor Pro guideline - Find the `HDF5.XOP` (`HDF5-64.xop` for Igor 7 64-bit) extension in the `Igor Pro Folder` under `More Extensions/File Loaders` (`More Extensions (64-bit)/File Loaders`), create a shortcut, and move the shortcut to the `Igor Extensions` folder next to your `User Procedures` folder. - Find the `HDF5 Help.ihf` next to `HDF5.XOP`, create a shortcut, and move the shortcut to the `Igor Help Files` folder next to your `User Procedures` folder. -PEARL Procedures are compatible with Igor Pro versions 6-8, 32-bit and 64-bit. -They are not compatible with Igor 6.36 and older. -As long as no Igor 8 specific features are used, the produced experiment files remain compatible with Igor 6. -Some features, in particular 3D graphics, may not work properly under Igor 7 and newer. +PEARL Procedures are compatible with Igor Pro versions 6.37 and 8.04, 32-bit and 64-bit. +Please make sure to use the latest release version. +As long as no Igor 8 specific features are used (long object names), the produced experiment files remain compatible with Igor 6. License @@ -35,7 +34,7 @@ Matthias Muntwiler, Copyright --------- -Copyright 2009-2019 by [Paul Scherrer Institut](http://www.psi.ch) +Copyright 2009-2020 by [Paul Scherrer Institut](http://www.psi.ch) Release Notes diff --git a/doc/html/_page_projections.html b/doc/html/_page_projections.html index 0741dbf..b2a23c5 100644 --- a/doc/html/_page_projections.html +++ b/doc/html/_page_projections.html @@ -29,7 +29,7 @@
PEARL Procedures -  rev-distro-2.0.3-2-g58135e4-dirty +  rev-distro-2.1.0-1-gb7390cb-dirty
Igor procedures for the analysis of PEARL data
@@ -107,7 +107,7 @@ $(document).ready(function(){initNavTree('_page_projections.html','');}); @@ -447,7 +449,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

Definition at line 588 of file pearl-anglescan-panel.ipf.

+

Definition at line 666 of file pearl-anglescan-panel.ipf.

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

display a graph window of the processed data.

if the window exists, it is updated and brought to the front of the window stack.

-

Definition at line 242 of file pearl-anglescan-panel.ipf.

+

Definition at line 249 of file pearl-anglescan-panel.ipf.

@@ -509,7 +511,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
Returns
name of the graph window
-

Definition at line 690 of file pearl-anglescan-panel.ipf.

+

Definition at line 768 of file pearl-anglescan-panel.ipf.

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

Definition at line 197 of file pearl-anglescan-panel.ipf.

+

Definition at line 204 of file pearl-anglescan-panel.ipf.

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

Definition at line 738 of file pearl-anglescan-panel.ipf.

+

Definition at line 816 of file pearl-anglescan-panel.ipf.

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

save the output diffractogram to an igor text file

-

Definition at line 723 of file pearl-anglescan-panel.ipf.

+

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

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

create the angle scan processing panel

-

Definition at line 822 of file pearl-anglescan-panel.ipf.

+

Definition at line 900 of file pearl-anglescan-panel.ipf.

@@ -630,12 +632,12 @@ Licensed under the Apache License, Version 2.0 (the "License");

update graphs with new color table or contrast

applies to the preview graph and the diffractogram.

-

Definition at line 632 of file pearl-anglescan-panel.ipf.

+

Definition at line 710 of file pearl-anglescan-panel.ipf.

- -

◆ bp_crop_alpha_preview()

+ +

◆ bp_crop_preview()

@@ -644,7 +646,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
- + @@ -658,7 +660,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
static variable bp_crop_alpha_preview static variable bp_crop_preview ( WMButtonAction *  ba)
-

Definition at line 1274 of file pearl-anglescan-panel.ipf.

+

Definition at line 1370 of file pearl-anglescan-panel.ipf.

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

Definition at line 1430 of file pearl-anglescan-panel.ipf.

+

Definition at line 1526 of file pearl-anglescan-panel.ipf.

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

Definition at line 1416 of file pearl-anglescan-panel.ipf.

+

Definition at line 1512 of file pearl-anglescan-panel.ipf.

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

Definition at line 1143 of file pearl-anglescan-panel.ipf.

+

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

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

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

+

Definition at line 1314 of file pearl-anglescan-panel.ipf.

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

Definition at line 1288 of file pearl-anglescan-panel.ipf.

+

Definition at line 1384 of file pearl-anglescan-panel.ipf.

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

Definition at line 1246 of file pearl-anglescan-panel.ipf.

+

Definition at line 1342 of file pearl-anglescan-panel.ipf.

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

Definition at line 1302 of file pearl-anglescan-panel.ipf.

+

Definition at line 1398 of file pearl-anglescan-panel.ipf.

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

Definition at line 1232 of file pearl-anglescan-panel.ipf.

+

Definition at line 1328 of file pearl-anglescan-panel.ipf.

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

Definition at line 1316 of file pearl-anglescan-panel.ipf.

+

Definition at line 1412 of file pearl-anglescan-panel.ipf.

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

Definition at line 1260 of file pearl-anglescan-panel.ipf.

+

Definition at line 1356 of file pearl-anglescan-panel.ipf.

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

Definition at line 1330 of file pearl-anglescan-panel.ipf.

+

Definition at line 1426 of file pearl-anglescan-panel.ipf.

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

Definition at line 1344 of file pearl-anglescan-panel.ipf.

+

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

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

Definition at line 1359 of file pearl-anglescan-panel.ipf.

+

Definition at line 1455 of file pearl-anglescan-panel.ipf.

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

Definition at line 1380 of file pearl-anglescan-panel.ipf.

+

Definition at line 1476 of file pearl-anglescan-panel.ipf.

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

Definition at line 1402 of file pearl-anglescan-panel.ipf.

+

Definition at line 1498 of file pearl-anglescan-panel.ipf.

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

Definition at line 1157 of file pearl-anglescan-panel.ipf.

+

Definition at line 1253 of file pearl-anglescan-panel.ipf.

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

Definition at line 1171 of file pearl-anglescan-panel.ipf.

+

Definition at line 1267 of file pearl-anglescan-panel.ipf.

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

Definition at line 1197 of file pearl-anglescan-panel.ipf.

+

Definition at line 1293 of file pearl-anglescan-panel.ipf.

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

Definition at line 758 of file pearl-anglescan-panel.ipf.

+

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

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

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

+

Definition at line 843 of file pearl-anglescan-panel.ipf.

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

Definition at line 772 of file pearl-anglescan-panel.ipf.

+

Definition at line 850 of file pearl-anglescan-panel.ipf.

@@ -1270,12 +1272,12 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

Definition at line 779 of file pearl-anglescan-panel.ipf.

+

Definition at line 857 of file pearl-anglescan-panel.ipf.

- -

◆ do_crop_alpha()

+ +

◆ delete_rows()

@@ -1284,7 +1286,75 @@ Licensed under the Apache License, Version 2.0 (the "License");
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
static variable do_crop_alpha static variable delete_rows (string rows,
wave data,
wave theta,
wave tilt,
wave phi 
)
+ + +static + + +
+ +

delete individual rows from the data strip

+
Parameters
+ + + + + + +
[in]rowscomma-separated list of row indices or ranges. ranges are specified by joining the start and end index with a hyphen, e.g. 24-46. the list does not need to be ordered.
[in,out]data2D data the original wave is modified.
[in,out]thetatheta positions along Y dimension of data. the original wave is modified.
[in,out]tilttilt positions along Y dimension of data the original wave is modified.
[in,out]phiphi positions along Y dimension of data the original wave is modified.
+
+
+ +

Definition at line 406 of file pearl-anglescan-panel.ipf.

+ +
+
+ +

◆ do_crop()

+ +
+
+ + +
+ + + @@ -1308,7 +1378,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
static variable do_crop ( variable  check,
-

alpha-crop the process data.

+

crop the process data.

Parameters
[in]checkselect which output to generate (currently not used).
-

Definition at line 77 of file pearl-anglescan-panel.ipf.

+

Definition at line 75 of file pearl-anglescan-panel.ipf.

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

the preferences file is an Igor packed experiment file in a special preferences folder.

this function is called automatically when the procedure is first compiled, or whenever the user clicks the corresponding button.

-

Definition at line 161 of file pearl-anglescan-panel.ipf.

+

Definition at line 168 of file pearl-anglescan-panel.ipf.

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

Definition at line 1529 of file pearl-anglescan-panel.ipf.

+

Definition at line 1641 of file pearl-anglescan-panel.ipf.

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

Definition at line 1497 of file pearl-anglescan-panel.ipf.

+

Definition at line 1609 of file pearl-anglescan-panel.ipf.

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

Definition at line 1513 of file pearl-anglescan-panel.ipf.

+

Definition at line 1625 of file pearl-anglescan-panel.ipf.

@@ -1762,7 +1832,35 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

Definition at line 1449 of file pearl-anglescan-panel.ipf.

+

Definition at line 1545 of file pearl-anglescan-panel.ipf.

+ +
+ + +

◆ pmp_norm_theta_domain()

+ +
+
+ + + + + +
+ + + + + + + + +
static variable pmp_norm_theta_domain (WMPopupAction * pa)
+
+static
+
+ +

Definition at line 1561 of file pearl-anglescan-panel.ipf.

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

Definition at line 1465 of file pearl-anglescan-panel.ipf.

+

Definition at line 1577 of file pearl-anglescan-panel.ipf.

@@ -1818,12 +1916,12 @@ Licensed under the Apache License, Version 2.0 (the "License");
-

Definition at line 1481 of file pearl-anglescan-panel.ipf.

+

Definition at line 1593 of file pearl-anglescan-panel.ipf.

- -

◆ preview_crop_alpha()

+ +

◆ preview_crop()

@@ -1832,7 +1930,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
- + @@ -1845,7 +1943,7 @@ Licensed under the Apache License, Version 2.0 (the "License");
static variable preview_crop_alpha static variable preview_crop ( )
-

Definition at line 786 of file pearl-anglescan-panel.ipf.

+

Definition at line 864 of file pearl-anglescan-panel.ipf.

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

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

+

Definition at line 870 of file pearl-anglescan-panel.ipf.

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

Definition at line 799 of file pearl-anglescan-panel.ipf.

+

Definition at line 877 of file pearl-anglescan-panel.ipf.

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

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

+

Definition at line 884 of file pearl-anglescan-panel.ipf.

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

Definition at line 813 of file pearl-anglescan-panel.ipf.

+

Definition at line 891 of file pearl-anglescan-panel.ipf.

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

save persistent package data to the preferences file.

this function is called when the user clicks the corresponding button.

-

Definition at line 137 of file pearl-anglescan-panel.ipf.

+

Definition at line 142 of file pearl-anglescan-panel.ipf.

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

update the popup menus to reflect the values of the global variables

-

Definition at line 1117 of file pearl-anglescan-panel.ipf.

+

Definition at line 1210 of file pearl-anglescan-panel.ipf.

@@ -2067,32 +2165,6 @@ Licensed under the Apache License, Version 2.0 (the "License");

Definition at line 47 of file pearl-anglescan-panel.ipf.

- - - -

◆ prefs_objects

- -
-
- - - - - -
- - - - -
const string prefs_objects = "theta_offset;tilt_offset;phi_offset;alpha_offset;crop_alpha_enable;crop_alpha_value;norm_alpha_enable;norm_alpha_mode;norm_alpha_smoothing;norm_phi_enable;norm_phi_mode;norm_phi_thetarange;norm_theta_enable;norm_theta_mode;norm_theta_smoothing;norm_thetaphi_enable;norm_thetaphi_mode;norm_theta_smoothing;output_folding;output_horizon;graph_mode;graph_projection;graph_colortable;graph_contrast;"
-
-static
-
- -

semicolon-separated list of persistent variable, string, and wave names

- -

Definition at line 49 of file pearl-anglescan-panel.ipf.

-
@@ -2101,7 +2173,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 version = 1.7
3 #pragma IgorVersion = 6.2
4 #pragma ModuleName = PearlAnglescanPanel
5 #include "pearl-anglescan-process"
6 #include "pearl-pmsco-import"
7 
8 // copyright (c) 2018 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 //
15 // Please acknowledge the use of this code.
16 
38 
43 
45 static strconstant package_name = "pearl_anglescan_panel"
47 static strconstant package_path = "root:packages:pearl_anglescan_panel:"
49 static strconstant prefs_objects = "theta_offset;tilt_offset;phi_offset;alpha_offset;crop_alpha_enable;crop_alpha_value;norm_alpha_enable;norm_alpha_mode;norm_alpha_smoothing;norm_phi_enable;norm_phi_mode;norm_phi_thetarange;norm_theta_enable;norm_theta_mode;norm_theta_smoothing;norm_thetaphi_enable;norm_thetaphi_mode;norm_theta_smoothing;output_folding;output_horizon;graph_mode;graph_projection;graph_colortable;graph_contrast;"
50 
52 static function AfterCompiledHook()
53 
54  dfref savedf = GetDataFolderDFR()
55  variable do_init = 1
56  if (DataFolderExists(package_path))
57  setdatafolder $(package_path)
58  nvar /z init_done
59  if (nvar_exists(init_done))
60  if (init_done)
61  do_init = 0
62  endif
63  endif
64  endif
65 
66  if (do_init)
67  init_package()
68  load_prefs()
69  setdatafolder $(package_path)
70  variable /g init_done = 1
71  endif
72 
73  setdatafolder savedf
74  return 0
75 end
76 
77 static function init_package()
78  dfref savedf = getdatafolderdfr()
79  setdatafolder root:
80  newdatafolder /o/s packages
81  newdatafolder /o/s $package_name
82 
83  // configuration (persistent)
84  string /g graphname = "graph_anglescan_panel"
85 
86  // recently used (persistent)
87  variable /g theta_offset = 0
88  variable /g tilt_offset = 0
89  variable /g phi_offset = 0
90  variable /g alpha_offset = 0
91  variable /g crop_alpha_enable = 0
92  variable /g crop_alpha_value = 25
93  variable /g norm_alpha_enable = 0
94  variable /g norm_alpha_mode = 4
95  variable /g norm_alpha_smoothing = 0.25
96  variable /g norm_theta_enable = 0
97  variable /g norm_theta_mode = 4
98  variable /g norm_theta_smoothing = 0.25
99  variable /g norm_thetaphi_enable = 0
100  variable /g norm_thetaphi_mode = 4
101  variable /g norm_thetaphi_smoothing = 0.25
102  variable /g norm_phi_enable = 0
103  variable /g norm_phi_mode = 4
104  variable /g norm_phi_thetarange = 20
105  string /g output_name = "holo1"
106  variable /g output_folding = 1
107  variable /g output_horizon = 88
108  variable /g graph_mode = 1
109  variable /g graph_projection = kProjStereo
110  string /g graph_colortable = "grays"
111  variable /g graph_contrast = 2
112 
113  // recently used (volatile)
114  string /g source_path = ""
115  string /g export_folderpath = "root:"
116  variable /g export_format = 1
117 
118  // administrative data (volatile)
119  string /g panel_name = ""
120  string /g preview_graphname = ""
121  string /g dist_x_graphname = ""
122  string /g dist_y_graphname = ""
123  string /g output_graphname = ""
124 
125  // data (volatile)
126  make /n=(10,10) /o raw_data, process_data
127  make /o dist_x, dist_x_smoo
128  make /o dist_y, dist_y_smoo
129 
130  setdatafolder savedf
131 end
132 
137 static function save_prefs()
138  dfref saveDF = GetDataFolderDFR()
139 
140  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
141  fullPath += package_name
142  NewPath/O/C/Q tempPackagePrefsPath, fullPath
143  fullPath += ":preferences.pxp"
144 
145  SetDataFolder root:packages
146  SetDataFolder $package_name
147  SaveData /O /Q /J=prefs_objects fullPath
148 
149  KillPath/Z tempPackagePrefsPath
150 
151  SetDataFolder saveDF
152 end
153 
161 static function load_prefs()
162  dfref saveDF = GetDataFolderDFR()
163 
164  variable result = -1
165  setdatafolder root:
166  NewDataFolder /O/S packages
167  NewDataFolder /O/S $package_name
168  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
169  fullPath += package_name
170 
171  GetFileFolderInfo /Q /Z fullPath
172  if (V_Flag == 0) // Disk directory exists?
173  fullPath += ":preferences.pxp"
174  GetFileFolderInfo /Q /Z fullPath
175  if (V_Flag == 0) // Preference file exist?
176  LoadData /O /R /Q fullPath
177  result = 0
178  endif
179  endif
180 
181  SetDataFolder saveDF
182  return result
183 end
184 
197 function asp_import_raw(raw_data)
198  wave raw_data
199 
200  dfref saveDF = GetDataFolderDFR()
201  dfref datadf = GetWavesDataFolderDFR(raw_data)
202  dfref attrdf = datadf:attr
203  if (!DataFolderRefStatus(attrdf))
204  setdatafolder datadf
205  setdatafolder ::
206  dfref parentdf = GetDataFolderDFR()
207  dfref attrdf = parentdf:attr
208  endif
209  setdatafolder $(package_path)
210 
211  // todo : check dimensions and scales
212 
213  svar source_path
214  source_path = GetWavesDataFolder(raw_data, 2)
215 
216  duplicate /o raw_data, raw, process_data
217 
218  wave /sdfr=attrdf /z ManipulatorTheta
219  wave /sdfr=attrdf /z ManipulatorTilt
220  wave /sdfr=attrdf /z ManipulatorPhi
221  if (WaveExists(ManipulatorTheta) && WaveExists(ManipulatorTilt) && WaveExists(ManipulatorPhi))
222  duplicate /o attrdf:ManipulatorTheta, raw_theta, process_theta
223  duplicate /o attrdf:ManipulatorTilt, raw_tilt, process_tilt
224  duplicate /o attrdf:ManipulatorPhi, raw_phi, process_phi
225  else
226  DoAlert 0, "Can't find manipulator angle waves.\rCheck that the attr folder exists, or provide values in the following table."
227  make /n=(dimsize(raw_data, 1)) /o raw_theta, raw_tilt, raw_phi
228  make /n=(dimsize(raw_data, 1)) /o process_theta, process_tilt, process_phi
229  edit /k=1 raw_theta, raw_tilt, raw_phi
230  endif
231 
232  make /o /n=(dimsize(raw_data, 0)) dist_x, dist_x_smoo
233  make /o /n=(dimsize(raw_data, 1)) dist_y, dist_y_smoo
234 
235  SetDataFolder saveDF
236 end
237 
243  dfref df = $(package_path)
244  wave /sdfr=df process_data
245  svar /sdfr=df preview_graphname
246 
247  if (strlen(preview_graphname) && (wintype(preview_graphname) == 1))
248  ad_update_profiles(process_data)
249  DoWindow /F $preview_graphname
250  else
251  preview_graphname = ad_display_profiles(process_data)
252  endif
253 
254  nvar /sdfr=df graph_contrast
255  svar /sdfr=df graph_colortable
256  set_contrast(graph_contrast, graph_contrast, graphname=preview_graphname, colortable=graph_colortable)
257 end
258 
266 function asp_display_dist_check(xdist, ydist)
267  variable xdist, ydist
268 
269  dfref df = $(package_path)
270  wave /sdfr=df dist_x
271  wave /sdfr=df dist_y
272  wave /sdfr=df dist_x_smoo
273  wave /sdfr=df dist_y_smoo
274  svar /sdfr=df dist_x_graphname
275  svar /sdfr=df dist_y_graphname
276 
277  if (xdist)
278  if (strlen(dist_x_graphname) && (wintype(dist_x_graphname) == 1))
279  DoWindow /F $dist_x_graphname
280  else
281  display /k=1 /n=graph_asp_dist_x dist_x, dist_x_smoo
282  dist_x_graphname = s_name
283  ModifyGraph /w=$dist_x_graphname mode(dist_x)=2
284  ModifyGraph /w=$dist_x_graphname lsize(dist_x)=2
285  ModifyGraph /w=$dist_x_graphname rgb(dist_x)=(0,0,0)
286  endif
287  endif
288 
289  if (ydist)
290  if (strlen(dist_y_graphname) && (wintype(dist_y_graphname) == 1))
291  DoWindow /F $dist_y_graphname
292  else
293  display /k=1 /n=graph_asp_dist_y dist_y, dist_y_smoo
294  dist_y_graphname = s_name
295  ModifyGraph /w=$dist_y_graphname mode(dist_y)=2
296  ModifyGraph /w=$dist_y_graphname lsize(dist_y)=2
297  ModifyGraph /w=$dist_y_graphname rgb(dist_y)=(0,0,0)
298  endif
299  endif
300 end
301 
311 static function do_init_process(check)
312  variable check
313 
314  dfref df = $(package_path)
315  wave /sdfr=df raw
316  wave /sdfr=df raw_theta
317  wave /sdfr=df raw_tilt
318  wave /sdfr=df raw_phi
319  nvar /sdfr=df theta_offset
320  nvar /sdfr=df tilt_offset
321  nvar /sdfr=df phi_offset
322  nvar /sdfr=df alpha_offset
323 
324  duplicate /o raw, df:process_data
325  duplicate /o raw_theta, df:process_theta
326  duplicate /o raw_tilt, df:process_tilt
327  duplicate /o raw_phi, df:process_phi
328 
329  wave /sdfr=df process_data
330  wave /sdfr=df process_theta
331  wave /sdfr=df process_tilt
332  wave /sdfr=df process_phi
333 
334  process_theta = raw_theta - theta_offset
335  process_tilt = raw_tilt - tilt_offset
336  process_phi = raw_phi - phi_offset
337  setscale /p x dimoffset(raw, 0) - alpha_offset, dimdelta(raw, 0), waveunits(raw, 0), process_data
338 end
339 
351 static function do_crop_alpha(check, [force])
352  variable check
353  variable force
354 
355  if (ParamIsDefault(force))
356  force = 0
357  endif
358 
359  dfref df = $(package_path)
360  wave /sdfr=df process_data
361  nvar /sdfr=df crop_alpha_enable
362  nvar /sdfr=df crop_alpha_value
363 
364  if ((force || crop_alpha_enable) && (crop_alpha_value > abs(dimdelta(process_data, 0))))
365  crop_strip(process_data, -crop_alpha_value, +crop_alpha_value)
366  endif
367 end
368 
380 static function do_norm_alpha(check, [force])
381  variable check
382  variable force
383 
384  if (ParamIsDefault(force))
385  force = 0
386  endif
387 
388  dfref saveDF = GetDataFolderDFR()
389  dfref df = $(package_path)
390  wave /sdfr=df process_data
391  nvar /sdfr=df norm_alpha_enable
392  nvar /sdfr=df norm_alpha_mode
393  nvar /sdfr=df norm_alpha_smoothing
394 
395  if (force || norm_alpha_enable)
396  dfref temp_df = newfreedatafolder()
397  setdatafolder temp_df
398  normalize_strip_x(process_data, smooth_method=norm_alpha_mode, smooth_factor=norm_alpha_smoothing, check=check)
399  if (check)
400  wave check_dist
401  wave check_smoo
402  duplicate /o check_dist, df:dist_x
403  duplicate /o check_smoo, df:dist_x_smoo
404  endif
405  endif
406 
407  SetDataFolder saveDF
408 end
409 
421 static function do_norm_phi(check, [force])
422  variable check
423  variable force
424 
425  if (ParamIsDefault(force))
426  force = 0
427  endif
428 
429  dfref saveDF = GetDataFolderDFR()
430  dfref df = $(package_path)
431  wave /sdfr=df process_data
432  wave /sdfr=df process_theta
433  wave /sdfr=df process_phi
434  nvar /sdfr=df norm_phi_enable
435  nvar /sdfr=df norm_phi_mode
436  nvar /sdfr=df norm_phi_thetarange
437 
438  if (force || norm_phi_enable)
439  dfref temp_df = newfreedatafolder()
440  setdatafolder temp_df
441  normalize_strip_phi(process_data, process_theta, process_phi, theta_range=norm_phi_thetarange, check=check)
442  if (check)
443  wave check_dist
444  wave check_smoo
445  duplicate /o check_dist, df:dist_y
446  duplicate /o check_smoo, df:dist_y_smoo
447  endif
448  endif
449 
450  SetDataFolder saveDF
451 end
452 
464 static function do_norm_theta(check, [force])
465  variable check
466  variable force
467 
468  if (ParamIsDefault(force))
469  force = 0
470  endif
471 
472  dfref saveDF = GetDataFolderDFR()
473  dfref df = $(package_path)
474  wave /sdfr=df process_data
475  wave /sdfr=df process_theta
476  nvar /sdfr=df norm_theta_enable
477  nvar /sdfr=df norm_theta_mode
478  nvar /sdfr=df norm_theta_smoothing
479 
480  if (force || norm_theta_enable)
481  dfref temp_df = newfreedatafolder()
482  setdatafolder temp_df
483  normalize_strip_theta(process_data, process_theta, smooth_method=norm_theta_mode, smooth_factor=norm_theta_smoothing, check=check)
484  if (check)
485  wave check_dist
486  wave check_smoo
487  duplicate /o check_dist, df:dist_y
488  duplicate /o check_smoo, df:dist_y_smoo
489  endif
490  endif
491 
492  SetDataFolder saveDF
493 end
494 
506 static function do_norm_thetaphi(check, [force])
507  variable check
508  variable force
509 
510  if (ParamIsDefault(force))
511  force = 0
512  endif
513 
514  dfref saveDF = GetDataFolderDFR()
515  dfref df = $(package_path)
516  wave /sdfr=df process_data
517  wave /sdfr=df process_theta
518  wave /sdfr=df process_phi
519  nvar /sdfr=df norm_thetaphi_enable
520  nvar /sdfr=df norm_thetaphi_mode
521  nvar /sdfr=df norm_thetaphi_smoothing
522 
523  if (force || norm_thetaphi_enable)
524  dfref temp_df = newfreedatafolder()
525  setdatafolder temp_df
526  normalize_strip_thetaphi(process_data, process_theta, process_phi, smooth_method=norm_thetaphi_mode, smooth_factor=norm_thetaphi_smoothing, check=check)
527  if (check)
528  wave check_dist
529  wave check_smoo
530  duplicate /o check_dist, df:dist_y
531  duplicate /o check_smoo, df:dist_y_smoo
532  endif
533  endif
534 
535  SetDataFolder saveDF
536 end
537 
543  dfref saveDF = GetDataFolderDFR()
544  setdatafolder $(package_path)
545 
546  svar output_name
547 
548  wave process_data
549  wave process_theta
550  wave process_tilt
551  wave process_phi
552 
553  nvar folding=output_folding
554  nvar horizon=output_horizon
555 
556  do_init_process(0)
557  do_crop_alpha(0)
558  do_norm_alpha(0)
559  do_norm_phi(0)
560  do_norm_theta(0)
562 
563  pizza_service_2(process_data, output_name, process_theta, process_tilt, process_phi, folding=folding, nograph=1)
564 
565  setdatafolder $output_name
566  wave values
567  wave pol
568  if (horizon > 0)
569  values = pol <= horizon ? values : nan
570  endif
571 
572  SetDataFolder saveDF
573 end
574 
588 function /s asp_display_output([data_df, data_name])
589  dfref data_df
590  string data_name
591 
592  dfref pkg_df = $(package_path)
593  svar /sdfr=pkg_df output_name
594  svar /sdfr=pkg_df output_graphname
595  nvar /sdfr=pkg_df graph_projection
596  nvar /sdfr=pkg_df graph_mode
597  svar /sdfr=pkg_df graph_colortable
598  nvar /sdfr=pkg_df graph_contrast
599 
600  if (ParamIsDefault(data_df))
601  dfref data_df = pkg_df
602  endif
603  if (ParamIsDefault(data_name))
604  data_name = output_name
605  endif
606 
607  dfref saveDF = GetDataFolderDFR()
608  setdatafolder data_df
609 
610  if (graph_mode == 3)
611  interpolate_hemi_scan(data_name, projection=graph_projection)
612  endif
613 
614  string graphname = data_name
615  graphname = display_hemi_scan(data_name, projection=graph_projection, graphtype=graph_mode, graphname=graphname)
616  if (ParamIsDefault(data_df))
617  output_graphname = graphname
618  endif
619  SetDataFolder saveDF
620 
621  if (strlen(graphname) && (wintype(graphname) == 1))
622  set_contrast(graph_contrast, graph_contrast, graphname=graphname, colortable=graph_colortable)
623  endif
624 
625  return graphname
626 end
627 
633  dfref df = $(package_path)
634 
635  svar /sdfr=df preview_graphname
636  svar /sdfr=df output_graphname
637  svar /sdfr=df graph_colortable
638  nvar /sdfr=df graph_contrast
639 
640  if (strlen(preview_graphname) && (wintype(preview_graphname) == 1))
641  set_contrast(graph_contrast, graph_contrast, graphname=preview_graphname, colortable=graph_colortable)
642  endif
643  if (strlen(output_graphname) && (wintype(output_graphname) == 1))
644  set_contrast(graph_contrast, graph_contrast, graphname=output_graphname, colortable=graph_colortable)
645  endif
646 end
647 
651  dfref df = $(package_path)
652 
653  svar /sdfr=df preview_graphname
654  svar /sdfr=df output_graphname
655  svar /sdfr=df dist_x_graphname
656  svar /sdfr=df dist_y_graphname
657 
658  if (strlen(preview_graphname) && (wintype(preview_graphname) == 1))
659  killwindow $preview_graphname
660  endif
661  if (strlen(output_graphname) && (wintype(output_graphname) == 1))
662  killwindow $output_graphname
663  endif
664  if (strlen(dist_x_graphname) && (wintype(dist_x_graphname) == 1))
665  killwindow $dist_x_graphname
666  endif
667  if (strlen(dist_y_graphname) && (wintype(dist_y_graphname) == 1))
668  killwindow $dist_y_graphname
669  endif
670 
671  preview_graphname = ""
672  output_graphname = ""
673  dist_x_graphname = ""
674  dist_y_graphname = ""
675 end
676 
690 function /s asp_duplicate_output(dest_name, [do_graph])
691  string dest_name
692  variable do_graph
693 
694  if (ParamIsDefault(do_graph))
695  do_graph = 0
696  endif
697 
698  dfref df = $(package_path)
699  svar /sdfr=df source_path
700  svar /sdfr=df output_name
701  svar /sdfr=df output_graphname
702  wave raw_data = $source_path
703 
704  dfref saveDF = GetDataFolderDFR()
705  dfref raw_df = GetWavesDataFolderDFR(raw_data)
706  setdatafolder raw_df
707  newdatafolder /o /s $dest_name
708  dfref dest_df = GetDataFolderDFR()
709  setdatafolder df
710  duplicate_hemi_scan(output_name, dest_df, "")
711 
712  string graphname = ""
713  if (do_graph)
714  graphname = asp_display_output(data_df=raw_df, data_name=dest_name)
715  endif
716 
717  SetDataFolder saveDF
718  return graphname
719 end
720 
724  dfref df = $(package_path)
725  svar /sdfr=df output_name
726 
727  dfref saveDF = GetDataFolderDFR()
728  setdatafolder df
729  save_hemi_scan(output_name, "", "")
730 
731  SetDataFolder saveDF
732 end
733 
738 function asp_save_output_etpi(ekin)
739  variable ekin
740 
741  dfref df = $(package_path)
742  svar /sdfr=df output_name
743  wave /sdfr=df process_data
744 
745  dfref saveDF = GetDataFolderDFR()
746  setdatafolder df
747  string s_prefix = ""
748  string s_int = "values"
749  dfref data_df = find_hemi_data(output_name, s_prefix, s_int)
750  string s_polar = s_prefix + "pol"
751  string s_azim = s_prefix + "az"
752 
753  pmsco_save_scan("", "", num2str(ekin), s_polar, s_azim, "", s_int, "", sdfr=data_df)
754 
755  SetDataFolder saveDF
756 end
757 
758 static function check_norm_alpha()
759  do_init_process(0)
760  do_crop_alpha(0)
761  do_norm_alpha(2, force=1)
763 end
764 
765 static function check_norm_phi()
766  do_init_process(0)
767  do_crop_alpha(0)
768  do_norm_phi(2, force=1)
769  asp_display_dist_check(0, 1)
770 end
771 
772 static function check_norm_theta()
773  do_init_process(0)
774  do_crop_alpha(0)
775  do_norm_theta(2, force=1)
776  asp_display_dist_check(0, 1)
777 end
778 
779 static function check_norm_thetaphi()
780  do_init_process(0)
781  do_crop_alpha(0)
782  do_norm_thetaphi(2, force=1)
783  asp_display_dist_check(0, 1)
784 end
785 
786 static function preview_crop_alpha()
787  do_init_process(0)
788  do_crop_alpha(0, force=1)
790 end
791 
792 static function preview_norm_alpha()
793  do_init_process(0)
794  do_crop_alpha(0)
795  do_norm_alpha(1, force=1)
797 end
798 
799 static function preview_norm_phi()
800  do_init_process(0)
801  do_crop_alpha(0)
802  do_norm_phi(1, force=1)
804 end
805 
806 static function preview_norm_theta()
807  do_init_process(0)
808  do_crop_alpha(0)
809  do_norm_theta(1, force=1)
811 end
812 
813 static function preview_norm_thetaphi()
814  do_init_process(0)
815  do_crop_alpha(0)
816  do_norm_thetaphi(1, force=1)
818 end
819 
822 function asp_show_panel()
823  dfref df = $(package_path)
824  svar /sdfr=df panel_name
825 
826  if (strlen(panel_name) && (wintype(panel_name) == 7))
827  DoWindow /F $panel_name
828  return 0
829  endif
830 
831  NewPanel /K=1 /N=anglescan_panel /W=(200,100,479,854) as "angle scan processing"
832  panel_name = s_name
833 
834  GroupBox gb_source, title="data source"
835  Button b_source_select, size={50,20},proc=PearlAnglescanPanel#bp_source_select,title="select..."
836  Button b_source_select, help={"select the source wave, e.g. ReducedData1. it must be in the scan or region data folder. the attr folder with the manipulator waves must be in the same folder or one level up."}
837  Button b_source_update, size={50,20},proc=PearlAnglescanPanel#bp_source_update,title="update"
838  Button b_source_update, help={"reload the process data from the previous source (link displayed below)"}
839  TitleBox tb_source_path, size={240,21}
840  TitleBox tb_source_path,variable= root:packages:pearl_anglescan_panel:source_path
841 
842  GroupBox gb_offsets, title="offsets"
843  SetVariable sv_theta_offset, size={88,16},bodyWidth=60,title="theta"
844  SetVariable sv_theta_offset,value= root:packages:pearl_anglescan_panel:theta_offset
845  SetVariable sv_theta_offset, help={"manipulator theta value that corresponds to normal emission."}
846  SetVariable sv_tilt_offset, size={74,16},bodyWidth=60,title="tilt"
847  SetVariable sv_tilt_offset,value= root:packages:pearl_anglescan_panel:tilt_offset
848  SetVariable sv_tilt_offset, help={"manipulator tilt value that corresponds to normal emission."}
849  SetVariable sv_phi_offset, size={78,16},bodyWidth=60,title="phi"
850  SetVariable sv_phi_offset,value= root:packages:pearl_anglescan_panel:phi_offset
851  SetVariable sv_phi_offset, help={"manipulator phi value that should map to the 3 o'clock angle."}
852  SetVariable sv_alpha_offset, size={90,16},bodyWidth=60,title="alpha"
853  SetVariable sv_alpha_offset,value= root:packages:pearl_anglescan_panel:alpha_offset
854  SetVariable sv_alpha_offset, help={"alpha value that corresponds to normal emission (if the sample normal is properly aligned)."}
855  Button b_save_prefs, size={80,20},proc=PearlAnglescanPanel#bp_save_prefs,title="save prefs"
856  Button b_save_prefs, help={"save settings as preferences."}
857  Button b_load_prefs, size={80,20},proc=PearlAnglescanPanel#bp_load_prefs,title="load prefs"
858  Button b_load_prefs, help={"load settings from preferences."}
859 
860  GroupBox gb_crop_alpha, title="crop alpha"
861  CheckBox cb_crop_alpha_enable, size={50,14}, title="enable"
862  CheckBox cb_crop_alpha_enable, help={"enable cropping at +/- alpha"}
863  CheckBox cb_crop_alpha_enable,variable= root:packages:pearl_anglescan_panel:crop_alpha_enable
864  SetVariable sv_crop_alpha_value, size={90,16},bodyWidth=60,title="angle"
865  SetVariable sv_crop_alpha_value,limits={0,30,1},value= root:packages:pearl_anglescan_panel:crop_alpha_value
866  SetVariable sv_crop_alpha_value, help={"alpha (detection angle) cropping angle"}
867  Button b_crop_alpha_preview, size={80,20},proc=PearlAnglescanPanel#bp_crop_alpha_preview,title="preview"
868  Button b_crop_alpha_preview, help={"show a preview of the cropped dataset."}
869 
870  GroupBox gb_norm_alpha, title="normalize alpha"
871  CheckBox cb_norm_alpha_enable, size={50,14}, title="enable"
872  CheckBox cb_norm_alpha_enable,variable= root:packages:pearl_anglescan_panel:norm_alpha_enable
873  CheckBox cb_norm_alpha_enable, help={"enable normalization of the alpha distribution"}
874  PopupMenu pm_norm_alpha_mode, size={138,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_norm_alpha_mode,title="method"
875  PopupMenu pm_norm_alpha_mode, mode=5, popvalue="loess", value= #"\"none;binomial;boxcar;scienta;loess;\""
876  PopupMenu pm_norm_alpha_mode, help={"alpha normalization method. recommended: loess"}
877  SetVariable sv_norm_alpha_smoothing, size={112,16}, bodyWidth=60, title="smoothing"
878  SetVariable sv_norm_alpha_smoothing, limits={0,1,0.05}, value= root:packages:pearl_anglescan_panel:norm_alpha_smoothing
879  SetVariable sv_norm_alpha_smoothing, help={"smoothing parameter (depends on the normalization method)."}
880  Button b_norm_alpha_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_alpha_check,title="check"
881  Button b_norm_alpha_check, help={"show a graph of the normalization function"}
882  Button b_norm_alpha_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_alpha_preview,title="preview"
883  Button b_norm_alpha_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
884 
885  GroupBox gb_norm_phi, title="normalize phi"
886  CheckBox cb_norm_phi_enable, size={50,14}, title="enable"
887  CheckBox cb_norm_phi_enable,variable= root:packages:pearl_anglescan_panel:norm_phi_enable
888  CheckBox cb_norm_phi_enable, help={"enable normalization of the phi distribution to reduce the effect of wobble"}
889  SetVariable sv_norm_phi_range, size={118,16}, bodyWidth=60, title="theta range"
890  SetVariable sv_norm_phi_range, limits={0,90,1}, value= root:packages:pearl_anglescan_panel:norm_phi_thetarange
891  SetVariable sv_norm_phi_range, help={"theta range (from normal) to factor into the normalization function"}
892  Button b_norm_phi_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_phi_check, title="check"
893  Button b_norm_phi_check, help={"show a graph of the normalization function"}
894  Button b_norm_phi_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_phi_preview, title="preview"
895  Button b_norm_phi_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
896 
897  GroupBox gb_norm_theta, title="normalize theta"
898  CheckBox cb_norm_theta_enable, size={50,14},title="enable"
899  CheckBox cb_norm_theta_enable, variable= root:packages:pearl_anglescan_panel:norm_theta_enable
900  CheckBox cb_norm_theta_enable, help={"enable normalization of the theta distribution (integrated over phi)"}
901  PopupMenu pm_norm_theta_mode, size={138,21},bodyWidth=100,proc=PearlAnglescanPanel#pmp_norm_theta_mode,title="method"
902  PopupMenu pm_norm_theta_mode,mode=5,popvalue="loess",value= #"\"none;binomial;boxcar;polynomial;loess;\""
903  PopupMenu pm_norm_theta_mode, help={"theta normalization method. recommended: loess"}
904  SetVariable sv_norm_theta_smoothing, size={112,16}, bodyWidth=60, title="smoothing"
905  SetVariable sv_norm_theta_smoothing, limits={0,1,0.05}, value= root:packages:pearl_anglescan_panel:norm_theta_smoothing
906  SetVariable sv_norm_theta_smoothing, help={"smoothing parameter (depends on the normalization method)."}
907  Button b_norm_theta_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_theta_check, title="check"
908  Button b_norm_theta_check, help={"show a graph of the normalization function"}
909  Button b_norm_theta_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_theta_preview, title="preview"
910  Button b_norm_theta_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
911 
912  GroupBox gb_norm_thetaphi, size={272,97},title="normalize (theta,phi)"
913  CheckBox cb_norm_thetaphi_enable, size={50,14},title="enable"
914  CheckBox cb_norm_thetaphi_enable, variable= root:packages:pearl_anglescan_panel:norm_thetaphi_enable
915  CheckBox cb_norm_thetaphi_enable, help={"enable normalization of the (theta, phi) distribution."}
916  PopupMenu pm_norm_thetaphi_mode, size={138,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_norm_thetaphi_mode,title="method"
917  PopupMenu pm_norm_thetaphi_mode, mode=5, popvalue="loess", value= #"\"none;none;none;none;loess;\""
918  PopupMenu pm_norm_thetaphi_mode, help={"theta normalization method. recommended: loess"}
919  SetVariable sv_norm_thetaphi_smoothing, size={112,16}, bodyWidth=60, title="smoothing"
920  SetVariable sv_norm_thetaphi_smoothing, limits={0,1,0.05}, value= root:packages:pearl_anglescan_panel:norm_thetaphi_smoothing
921  SetVariable sv_norm_thetaphi_smoothing, help={"smoothing parameter (depends on the normalization method)."}
922  Button b_norm_thetaphi_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_thetaphi_check, title="check"
923  Button b_norm_thetaphi_check, help={"show a graph of the normalization function"}
924  Button b_norm_thetaphi_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_thetaphi_preview, title="preview"
925  Button b_norm_thetaphi_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
926 
927  GroupBox gb_output, title="output"
928  SetVariable sv_output_folding, size={95,16}, bodyWidth=60, title="folding"
929  SetVariable sv_output_folding, limits={1,20,1}, value= root:packages:pearl_anglescan_panel:output_folding
930  SetVariable sv_output_folding, help={"n-fold rotational average. 1=no averaging."}
931  SetVariable sv_output_horizon, size={98,16}, bodyWidth=60, title="horizon"
932  SetVariable sv_output_horizon, limits={1,90,1}, value= root:packages:pearl_anglescan_panel:output_horizon
933  SetVariable sv_output_horizon, help={"highest theta to display"}
934  PopupMenu pm_graph_projection, size={149,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_graph_projection, title="projection"
935  PopupMenu pm_graph_projection, mode=2, popvalue="stereographic", value= #"\"equidistant;stereographic;equal area;gnomonic;orthographic;\""
936  PopupMenu pm_graph_projection, help={"projection (theta mapping) mode"}
937  PopupMenu pm_graph_mode, size={129,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_graph_mode,title="mode"
938  PopupMenu pm_graph_mode, mode=2, popvalue="dots", value= #"\"none;dots;none;image;\""
939  PopupMenu pm_graph_mode, help={"graph type: dots = coloured dots on circles; image = interpolated matrix"}
940  Button b_output_calc, size={80,20}, proc=PearlAnglescanPanel#bp_output_calc, title="calc + display"
941  Button b_output_calc, help={"execute data processing with the enabled filters and display the diffractogram."}
942  Button b_output_duplicate, size={80,20}, proc=PearlAnglescanPanel#bp_output_duplicate, title="duplicate ..."
943  Button b_output_duplicate, help={"copy the result to an arbitrary data folder."}
944  Button b_output_itx, size={80,20}, proc=PearlAnglescanPanel#bp_output_itx, title="save ITX ..."
945  Button b_output_itx, help={"save the result to an igor text file (itx)."}
946  Button b_output_etpi, size={80,20}, proc=PearlAnglescanPanel#bp_output_etpi, title="save ETPI ..."
947  Button b_output_etpi, help={"save the result to a pmsco angle scan file (etpi)."}
948 
949  GroupBox gb_graph, title="graph"
950  PopupMenu pm_graph_colortable, size={152,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_graph_colortable, title="color table"
951  PopupMenu pm_graph_colortable, mode=0, value= #"\"*COLORTABLEPOPNONAMES*\""
952  PopupMenu pm_graph_colortable, help={"color table to use in pseudocolor graphs."}
953  SetVariable sv_graph_contrast, size={119,16}, bodyWidth=60, title="contrast (%)"
954  SetVariable sv_graph_contrast, limits={0,25,1}, value= root:packages:pearl_anglescan_panel:graph_contrast
955  SetVariable sv_graph_contrast, help={"contrast value (percentile)."}
956  Button b_graph_update, size={80,20}, proc=PearlAnglescanPanel#bp_graph_update, title="update"
957  Button b_graph_update, help={"update the existing graph."}
958  Button b_graph_png, size={80,20}, proc=PearlAnglescanPanel#bp_graph_png, title="save PNG ..."
959  Button b_graph_png, help={"save the graph in png format."}
960 
962  update_menus()
963 end
964 
965 static function arrange_controls()
966  dfref df = $(package_path)
967  svar /sdfr=df panel_name
968 
969  variable gb_space = 2
970  variable gb_internal_top = 16
971  variable gb_internal_bot = 4
972  variable line_space = 22
973 
974  variable cb_adj = 2
975  variable sv_adj = 2
976  variable pm_adj = 0
977  variable b_adj = 0
978  variable tb_adj = 0
979 
980  variable gb_top = 4
981  variable gb_ht = 0
982 
983  // ht = line + 30
984  // gb = gb + ht + 2
985  // cb = gb + 18
986  // pm = gb + 38
987  // line += 26
988  // sv = line + 2
989 
990  GroupBox gb_source,pos={4,gb_top}
991  gb_ht = gb_internal_top
992  Button b_source_select,pos={17, gb_top + gb_ht + b_adj},size={50,20}
993  Button b_source_update, pos={67, gb_top + gb_ht + b_adj},size={50,20}
994  gb_ht += line_space
995  TitleBox tb_source_path,pos={18, gb_top + gb_ht + tb_adj},size={240,21}
996  gb_ht += line_space
997  gb_ht += gb_internal_bot
998  GroupBox gb_source, size={272,gb_ht}
999 
1000  gb_top += gb_ht + gb_space
1001  GroupBox gb_offsets,pos={4,gb_top}
1002  gb_ht = gb_internal_top
1003  SetVariable sv_theta_offset,pos={46, gb_top + gb_ht + sv_adj},size={88,16}
1004  Button b_save_prefs,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1005  gb_ht += line_space
1006  SetVariable sv_tilt_offset,pos={60, gb_top + gb_ht + sv_adj},size={74,16}
1007  Button b_load_prefs,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1008  gb_ht += line_space
1009  SetVariable sv_phi_offset,pos={56, gb_top + gb_ht + sv_adj},size={78,16}
1010  gb_ht += line_space
1011  SetVariable sv_alpha_offset,pos={44, gb_top + gb_ht + sv_adj},size={90,16}
1012  gb_ht += line_space
1013  gb_ht += gb_internal_bot
1014  GroupBox gb_offsets, size={272,gb_ht}
1015 
1016  gb_top += gb_ht + gb_space
1017  GroupBox gb_crop_alpha,pos={4,gb_top}
1018  gb_ht = gb_internal_top
1019  CheckBox cb_crop_alpha_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1020  gb_ht += line_space
1021  SetVariable sv_crop_alpha_value,pos={44, gb_top + gb_ht + sv_adj},size={90,16}
1022  Button b_crop_alpha_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1023  gb_ht += line_space
1024  gb_ht += gb_internal_bot
1025  GroupBox gb_crop_alpha, size={272,gb_ht}
1026 
1027  gb_top += gb_ht + gb_space
1028  GroupBox gb_norm_alpha,pos={4,gb_top}
1029  gb_ht = gb_internal_top
1030  CheckBox cb_norm_alpha_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1031  gb_ht += line_space
1032  PopupMenu pm_norm_alpha_mode,pos={36, gb_top + gb_ht + pm_adj},size={138,21}
1033  Button b_norm_alpha_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1034  gb_ht += line_space
1035  SetVariable sv_norm_alpha_smoothing,pos={22, gb_top + gb_ht + sv_adj},size={112,16}
1036  Button b_norm_alpha_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1037  gb_ht += line_space
1038  gb_ht += gb_internal_bot
1039  GroupBox gb_norm_alpha, size={272,gb_ht}
1040 
1041  gb_top += gb_ht + gb_space
1042  GroupBox gb_norm_phi,pos={4,gb_top}
1043  gb_ht = gb_internal_top
1044  CheckBox cb_norm_phi_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1045  Button b_norm_phi_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1046  gb_ht += line_space
1047  SetVariable sv_norm_phi_range,pos={15, gb_top + gb_ht + sv_adj},size={118,16}
1048  Button b_norm_phi_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1049  gb_ht += line_space
1050  gb_ht += gb_internal_bot
1051  GroupBox gb_norm_phi, size={272,gb_ht}
1052 
1053  gb_top += gb_ht + gb_space
1054  GroupBox gb_norm_theta,pos={4,gb_top}
1055  gb_ht = gb_internal_top
1056  CheckBox cb_norm_theta_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1057  gb_ht += line_space
1058  PopupMenu pm_norm_theta_mode,pos={35, gb_top + gb_ht + pm_adj},size={138,21}
1059  Button b_norm_theta_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1060  gb_ht += line_space
1061  SetVariable sv_norm_theta_smoothing,pos={21, gb_top + gb_ht + sv_adj},size={112,16}
1062  Button b_norm_theta_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1063  gb_ht += line_space
1064  gb_ht += gb_internal_bot
1065  GroupBox gb_norm_theta, size={272,gb_ht}
1066 
1067  gb_top += gb_ht + gb_space
1068  GroupBox gb_norm_thetaphi,pos={4,gb_top}
1069  gb_ht = gb_internal_top
1070  CheckBox cb_norm_thetaphi_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1071  gb_ht += line_space
1072  PopupMenu pm_norm_thetaphi_mode,pos={35, gb_top + gb_ht + pm_adj},size={138,21}
1073  Button b_norm_thetaphi_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1074  gb_ht += line_space
1075  SetVariable sv_norm_thetaphi_smoothing,pos={21, gb_top + gb_ht + sv_adj},size={112,16}
1076  Button b_norm_thetaphi_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1077  gb_ht += line_space
1078  gb_ht += gb_internal_bot
1079  GroupBox gb_norm_thetaphi, size={272,gb_ht}
1080 
1081  gb_top += gb_ht + gb_space
1082  GroupBox gb_output,pos={4,gb_top}
1083  gb_ht = gb_internal_top
1084  SetVariable sv_output_folding,pos={38, gb_top + gb_ht + sv_adj},size={95,16}
1085  Button b_output_calc,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1086  gb_ht += line_space
1087  SetVariable sv_output_horizon,pos={35, gb_top + gb_ht + sv_adj},size={98,16}
1088  Button b_output_duplicate,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1089  gb_ht += line_space
1090  PopupMenu pm_graph_projection,pos={24, gb_top + gb_ht + pm_adj},size={149,21}
1091  Button b_output_itx,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1092  gb_ht += line_space
1093  PopupMenu pm_graph_mode,pos={44, gb_top + gb_ht + pm_adj},size={129,21}
1094  Button b_output_etpi,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1095  gb_ht += line_space
1096  gb_ht += gb_internal_bot
1097  GroupBox gb_output, size={272,gb_ht}
1098 
1099  gb_top += gb_ht + gb_space
1100  GroupBox gb_graph,pos={4,gb_top}
1101  gb_ht = gb_internal_top
1102  PopupMenu pm_graph_colortable,pos={21, gb_top + gb_ht + pm_adj},size={152,21}
1103  Button b_graph_update,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1104  gb_ht += line_space
1105  SetVariable sv_graph_contrast,pos={14, gb_top + gb_ht + sv_adj},size={119,16}
1106  Button b_graph_png,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1107  gb_ht += line_space
1108  gb_ht += gb_internal_bot
1109  GroupBox gb_graph, size={272,gb_ht}
1110 
1111  gb_top += gb_ht + gb_space
1112  //MoveWindow 200, 100, 479, 100 + gb_top
1113 end
1114 
1117 static function update_menus()
1118  dfref df = $(package_path)
1119  svar /sdfr=df panel_name
1120  if (wintype(panel_name) == 7)
1121  variable m
1122  nvar /sdfr=df norm_alpha_mode
1123  m = norm_alpha_mode + 1
1124  PopupMenu pm_norm_alpha_mode win=$panel_name, mode=m
1125  nvar /sdfr=df norm_theta_mode
1126  m = norm_theta_mode + 1
1127  PopupMenu pm_norm_theta_mode win=$panel_name, mode=m
1128  nvar /sdfr=df norm_thetaphi_mode
1129  m = norm_thetaphi_mode + 1
1130  PopupMenu pm_norm_thetaphi_mode win=$panel_name, mode=m
1131  nvar /sdfr=df graph_mode
1132  m = graph_mode + 1
1133  PopupMenu pm_graph_mode win=$panel_name, mode=m
1134  nvar /sdfr=df graph_projection
1135  m = graph_projection + 1
1136  PopupMenu pm_graph_projection win=$panel_name, mode=m
1137  svar /sdfr=df graph_colortable
1138  m = 1 + WhichListItem(graph_colortable, CTabList())
1139  PopupMenu pm_graph_colortable win=$panel_name, mode=m
1140  endif
1141 end
1142 
1143 static function bp_load_prefs(ba) : ButtonControl
1144  STRUCT WMButtonAction &ba
1145 
1146  switch( ba.eventCode )
1147  case 2: // mouse up
1148  load_prefs()
1149  break
1150  case -1: // control being killed
1151  break
1152  endswitch
1153 
1154  return 0
1155 End
1156 
1157 static function bp_save_prefs(ba) : ButtonControl
1158  STRUCT WMButtonAction &ba
1159 
1160  switch( ba.eventCode )
1161  case 2: // mouse up
1162  save_prefs()
1163  break
1164  case -1: // control being killed
1165  break
1166  endswitch
1167 
1168  return 0
1169 End
1170 
1171 static function bp_source_select(ba) : ButtonControl
1172  STRUCT WMButtonAction &ba
1173 
1174  switch( ba.eventCode )
1175  case 2: // mouse up
1176  dfref dfBefore = GetDataFolderDFR()
1177  Execute /q/z "CreateBrowser prompt=\"Select 2D holo scan wave\", showWaves=1, showVars=0, showStrs=0"
1178  dfref dfAfter = GetDataFolderDFR()
1179  SetDataFolder dfBefore
1180 
1181  SVAR list = S_BrowserList
1182  NVAR flag = V_Flag
1183  if ((flag != 0) && (ItemsInList(list) >= 1))
1184  string wname = StringFromList(0, list)
1185  wave w = $wname
1186  asp_import_raw(w)
1187  endif
1188 
1189  break
1190  case -1: // control being killed
1191  break
1192  endswitch
1193 
1194  return 0
1195 End
1196 
1197 static function bp_source_update(ba) : ButtonControl
1198  STRUCT WMButtonAction &ba
1199 
1200  switch( ba.eventCode )
1201  case 2: // mouse up
1202  dfref packdf = $package_path
1203  svar /sdfr=packdf source_path
1204  wave /z w = $source_path
1205  if (waveexists(w))
1206  asp_import_raw(w)
1207  else
1208  DoAlert 0, "can't find source data."
1209  endif
1210  break
1211  case -1: // control being killed
1212  break
1213  endswitch
1214 
1215  return 0
1216 End
1217 
1218 static function bp_norm_alpha_check(ba) : ButtonControl
1219  STRUCT WMButtonAction &ba
1220 
1221  switch( ba.eventCode )
1222  case 2: // mouse up
1224  break
1225  case -1: // control being killed
1226  break
1227  endswitch
1228 
1229  return 0
1230 End
1231 
1232 static function bp_norm_theta_check(ba) : ButtonControl
1233  STRUCT WMButtonAction &ba
1234 
1235  switch( ba.eventCode )
1236  case 2: // mouse up
1238  break
1239  case -1: // control being killed
1240  break
1241  endswitch
1242 
1243  return 0
1244 End
1245 
1246 static function bp_norm_phi_check(ba) : ButtonControl
1247  STRUCT WMButtonAction &ba
1248 
1249  switch( ba.eventCode )
1250  case 2: // mouse up
1251  check_norm_phi()
1252  break
1253  case -1: // control being killed
1254  break
1255  endswitch
1256 
1257  return 0
1258 End
1259 
1260 static function bp_norm_thetaphi_check(ba) : ButtonControl
1261  STRUCT WMButtonAction &ba
1262 
1263  switch( ba.eventCode )
1264  case 2: // mouse up
1266  break
1267  case -1: // control being killed
1268  break
1269  endswitch
1270 
1271  return 0
1272 End
1273 
1274 static function bp_crop_alpha_preview(ba) : ButtonControl
1275  STRUCT WMButtonAction &ba
1276 
1277  switch( ba.eventCode )
1278  case 2: // mouse up
1280  break
1281  case -1: // control being killed
1282  break
1283  endswitch
1284 
1285  return 0
1286 End
1287 
1288 static function bp_norm_alpha_preview(ba) : ButtonControl
1289  STRUCT WMButtonAction &ba
1290 
1291  switch( ba.eventCode )
1292  case 2: // mouse up
1294  break
1295  case -1: // control being killed
1296  break
1297  endswitch
1298 
1299  return 0
1300 End
1301 
1302 static function bp_norm_phi_preview(ba) : ButtonControl
1303  STRUCT WMButtonAction &ba
1304 
1305  switch( ba.eventCode )
1306  case 2: // mouse up
1308  break
1309  case -1: // control being killed
1310  break
1311  endswitch
1312 
1313  return 0
1314 End
1315 
1316 static function bp_norm_theta_preview(ba) : ButtonControl
1317  STRUCT WMButtonAction &ba
1318 
1319  switch( ba.eventCode )
1320  case 2: // mouse up
1322  break
1323  case -1: // control being killed
1324  break
1325  endswitch
1326 
1327  return 0
1328 End
1329 
1330 static function bp_norm_thetaphi_preview(ba) : ButtonControl
1331  STRUCT WMButtonAction &ba
1332 
1333  switch( ba.eventCode )
1334  case 2: // mouse up
1336  break
1337  case -1: // control being killed
1338  break
1339  endswitch
1340 
1341  return 0
1342 End
1343 
1344 static function bp_output_calc(ba) : ButtonControl
1345  STRUCT WMButtonAction &ba
1346 
1347  switch( ba.eventCode )
1348  case 2: // mouse up
1351  break
1352  case -1: // control being killed
1353  break
1354  endswitch
1355 
1356  return 0
1357 End
1358 
1359 static function bp_output_duplicate(ba) : ButtonControl
1360  STRUCT WMButtonAction &ba
1361 
1362  switch( ba.eventCode )
1363  case 2: // mouse up
1364  string dest_folder
1365  variable do_graph = 1
1366  prompt dest_folder, "destination folder name (relative to data source)"
1367  prompt do_graph, "duplicate graph (yes = 1, no = 0)"
1368  doprompt "duplicate", dest_folder, do_graph
1369  if (!v_flag)
1370  asp_duplicate_output(dest_folder, do_graph=do_graph)
1371  endif
1372  break
1373  case -1: // control being killed
1374  break
1375  endswitch
1376 
1377  return 0
1378 End
1379 
1380 static function bp_output_etpi(ba) : ButtonControl
1381  STRUCT WMButtonAction &ba
1382 
1383  switch( ba.eventCode )
1384  case 2: // mouse up
1385  dfref df = $(package_path)
1386  wave /sdfr=df process_data
1387  variable ekin
1388  ekin = NumberByKey("KineticEnergy", note(process_data), "=", "\r")
1389  prompt ekin, "kinetic energy"
1390  doprompt "save etpi", ekin
1391  if (!v_flag)
1392  asp_save_output_etpi(ekin)
1393  endif
1394  break
1395  case -1: // control being killed
1396  break
1397  endswitch
1398 
1399  return 0
1400 End
1401 
1402 static function bp_output_itx(ba) : ButtonControl
1403  STRUCT WMButtonAction &ba
1404 
1405  switch( ba.eventCode )
1406  case 2: // mouse up
1408  break
1409  case -1: // control being killed
1410  break
1411  endswitch
1412 
1413  return 0
1414 End
1415 
1416 static function bp_graph_update(ba) : ButtonControl
1417  STRUCT WMButtonAction &ba
1418 
1419  switch( ba.eventCode )
1420  case 2: // mouse up
1422  break
1423  case -1: // control being killed
1424  break
1425  endswitch
1426 
1427  return 0
1428 End
1429 
1430 static function bp_graph_png(ba) : ButtonControl
1431  STRUCT WMButtonAction &ba
1432 
1433  switch( ba.eventCode )
1434  case 2: // mouse up
1435  dfref df = $(package_path)
1436  svar /sdfr=df source_path
1437  svar /sdfr=df output_graphname
1438  if (WinType(output_graphname) == 1)
1439  SavePICT /WIN=$output_graphname /E=-5 /B=144 /TRAN=0
1440  endif
1441  break
1442  case -1: // control being killed
1443  break
1444  endswitch
1445 
1446  return 0
1447 End
1448 
1449 static function pmp_norm_alpha_mode(pa) : PopupMenuControl
1450  STRUCT WMPopupAction &pa
1451 
1452  switch( pa.eventCode )
1453  case 2: // mouse up
1454  dfref df = $(package_path)
1455  nvar /sdfr=df norm_alpha_mode
1456  norm_alpha_mode = pa.popNum - 1
1457  break
1458  case -1: // control being killed
1459  break
1460  endswitch
1461 
1462  return 0
1463 End
1464 
1465 static function pmp_norm_theta_mode(pa) : PopupMenuControl
1466  STRUCT WMPopupAction &pa
1467 
1468  switch( pa.eventCode )
1469  case 2: // mouse up
1470  dfref df = $(package_path)
1471  nvar /sdfr=df norm_theta_mode
1472  norm_theta_mode = pa.popNum - 1
1473  break
1474  case -1: // control being killed
1475  break
1476  endswitch
1477 
1478  return 0
1479 End
1480 
1481 static function pmp_norm_thetaphi_mode(pa) : PopupMenuControl
1482  STRUCT WMPopupAction &pa
1483 
1484  switch( pa.eventCode )
1485  case 2: // mouse up
1486  dfref df = $(package_path)
1487  nvar /sdfr=df norm_thetaphi_mode
1488  norm_thetaphi_mode = pa.popNum - 1
1489  break
1490  case -1: // control being killed
1491  break
1492  endswitch
1493 
1494  return 0
1495 End
1496 
1497 static function pmp_graph_mode(pa) : PopupMenuControl
1498  STRUCT WMPopupAction &pa
1499 
1500  switch( pa.eventCode )
1501  case 2: // mouse up
1502  dfref df = $(package_path)
1503  nvar /sdfr=df graph_mode
1504  graph_mode = pa.popNum - 1
1505  break
1506  case -1: // control being killed
1507  break
1508  endswitch
1509 
1510  return 0
1511 End
1512 
1513 static function pmp_graph_projection(pa) : PopupMenuControl
1514  STRUCT WMPopupAction &pa
1515 
1516  switch( pa.eventCode )
1517  case 2: // mouse up
1518  dfref df = $(package_path)
1519  nvar /sdfr=df graph_projection
1520  graph_projection = pa.popNum - 1
1521  break
1522  case -1: // control being killed
1523  break
1524  endswitch
1525 
1526  return 0
1527 End
1528 
1529 static function pmp_graph_colortable(pa) : PopupMenuControl
1530  STRUCT WMPopupAction &pa
1531 
1532  switch( pa.eventCode )
1533  case 2: // mouse up
1534  dfref df = $(package_path)
1535  svar /sdfr=df graph_colortable
1536  graph_colortable = StringFromList(pa.popNum - 1, CTabList())
1538  break
1539  case -1: // control being killed
1540  break
1541  endswitch
1542 
1543  return 0
1544 End
static variable bp_norm_phi_preview(WMButtonAction *ba)
-
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
+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 = PearlAnglescanPanel
5 #include "pearl-anglescan-process"
6 #include "pearl-pmsco-import"
7 
8 // copyright (c) 2018-20 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 //
15 // Please acknowledge the use of this code.
16 
38 
43 
45 static strconstant package_name = "pearl_anglescan_panel"
47 static strconstant package_path = "root:packages:pearl_anglescan_panel:"
48 
50 static function AfterCompiledHook()
51 
52  dfref savedf = GetDataFolderDFR()
53  variable do_init = 1
54  if (DataFolderExists(package_path))
55  setdatafolder $(package_path)
56  nvar /z init_done
57  if (nvar_exists(init_done))
58  if (init_done)
59  do_init = 0
60  endif
61  endif
62  endif
63 
64  if (do_init)
65  init_package()
66  load_prefs()
67  setdatafolder $(package_path)
68  variable /g init_done = 1
69  endif
70 
71  setdatafolder savedf
72  return 0
73 end
74 
75 static function init_package()
76  dfref savedf = getdatafolderdfr()
77  setdatafolder root:
78  newdatafolder /o/s packages
79  newdatafolder /o/s $package_name
80 
81  // configuration (persistent)
82  string /g graphname = "graph_anglescan_panel"
83  string /g prefs_objects = "prefs_objects;theta_offset;tilt_offset;phi_offset;alpha_offset;crop_enable;crop_alpha;crop_theta;"
84  prefs_objects += "norm_alpha_enable;norm_alpha_mode;norm_alpha_smoothing;norm_phi_enable;norm_phi_mode;norm_phi_thetarange;"
85  prefs_objects += "norm_theta_enable;norm_theta_mode;norm_theta_domain;norm_theta_smoothing;norm_thetaphi_enable;norm_thetaphi_mode;norm_thetaphi_smoothing;"
86  prefs_objects += "output_folding;output_horizon;graph_mode;graph_projection;graph_colortable;graph_contrast;"
87 
88  // recently used (persistent)
89  variable /g theta_offset = 0
90  variable /g tilt_offset = 0
91  variable /g phi_offset = 0
92  variable /g alpha_offset = 0
93  variable /g crop_enable = 0
94  variable /g crop_alpha = 25
95  variable /g crop_theta = 88
96  string /g crop_rows = ""
97  variable /g norm_alpha_enable = 0
98  variable /g norm_alpha_mode = 4
99  variable /g norm_alpha_smoothing = 0.25
100  variable /g norm_theta_enable = 0
101  variable /g norm_theta_mode = 4
102  variable /g norm_theta_domain = 0
103  variable /g norm_theta_smoothing = 0.25
104  variable /g norm_thetaphi_enable = 0
105  variable /g norm_thetaphi_mode = 4
106  variable /g norm_thetaphi_smoothing = 0.25
107  variable /g norm_phi_enable = 0
108  variable /g norm_phi_mode = 4
109  variable /g norm_phi_thetarange = 20
110  string /g output_name = "holo1"
111  variable /g output_folding = 1
112  variable /g output_horizon = 88
113  variable /g graph_mode = 1
114  variable /g graph_projection = kProjStereo
115  string /g graph_colortable = "grays"
116  variable /g graph_contrast = 2
117 
118  // recently used (volatile)
119  string /g source_path = ""
120  string /g export_folderpath = "root:"
121  variable /g export_format = 1
122 
123  // administrative data (volatile)
124  string /g panel_name = ""
125  string /g preview_graphname = ""
126  string /g dist_x_graphname = ""
127  string /g dist_y_graphname = ""
128  string /g output_graphname = ""
129 
130  // data (volatile)
131  make /n=(10,10) /o raw_data, process_data
132  make /o dist_x, dist_x_smoo
133  make /o dist_y, dist_y_smoo
134 
135  setdatafolder savedf
136 end
137 
142 static function save_prefs()
143  dfref saveDF = GetDataFolderDFR()
144  dfref df = $(package_path)
145  svar /sdfr=df prefs_objects
146 
147  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
148  fullPath += package_name
149  NewPath/O/C/Q tempPackagePrefsPath, fullPath
150  fullPath += ":preferences.pxp"
151 
152  SetDataFolder root:packages
153  SetDataFolder $package_name
154  SaveData /O /Q /J=prefs_objects fullPath
155 
156  KillPath/Z tempPackagePrefsPath
157 
158  SetDataFolder saveDF
159 end
160 
168 static function load_prefs()
169  dfref saveDF = GetDataFolderDFR()
170 
171  variable result = -1
172  setdatafolder root:
173  NewDataFolder /O/S packages
174  NewDataFolder /O/S $package_name
175  string fullPath = SpecialDirPath("Packages", 0, 0, 0)
176  fullPath += package_name
177 
178  GetFileFolderInfo /Q /Z fullPath
179  if (V_Flag == 0) // Disk directory exists?
180  fullPath += ":preferences.pxp"
181  GetFileFolderInfo /Q /Z fullPath
182  if (V_Flag == 0) // Preference file exist?
183  LoadData /O /R /Q fullPath
184  result = 0
185  endif
186  endif
187 
188  SetDataFolder saveDF
189  return result
190 end
191 
204 function asp_import_raw(raw_data)
205  wave raw_data
206 
207  dfref saveDF = GetDataFolderDFR()
208  dfref datadf = GetWavesDataFolderDFR(raw_data)
209  dfref attrdf = datadf:attr
210  if (!DataFolderRefStatus(attrdf))
211  setdatafolder datadf
212  setdatafolder ::
213  dfref parentdf = GetDataFolderDFR()
214  dfref attrdf = parentdf:attr
215  endif
216  setdatafolder $(package_path)
217 
218  // todo : check dimensions and scales
219 
220  svar source_path
221  source_path = GetWavesDataFolder(raw_data, 2)
222 
223  duplicate /o raw_data, raw, process_data
224 
225  wave /sdfr=attrdf /z ManipulatorTheta
226  wave /sdfr=attrdf /z ManipulatorTilt
227  wave /sdfr=attrdf /z ManipulatorPhi
228  if (WaveExists(ManipulatorTheta) && WaveExists(ManipulatorTilt) && WaveExists(ManipulatorPhi))
229  duplicate /o attrdf:ManipulatorTheta, raw_theta, process_theta
230  duplicate /o attrdf:ManipulatorTilt, raw_tilt, process_tilt
231  duplicate /o attrdf:ManipulatorPhi, raw_phi, process_phi
232  else
233  DoAlert 0, "Can't find manipulator angle waves.\rCheck that the attr folder exists, or provide values in the following table."
234  make /n=(dimsize(raw_data, 1)) /o raw_theta, raw_tilt, raw_phi
235  make /n=(dimsize(raw_data, 1)) /o process_theta, process_tilt, process_phi
236  edit /k=1 raw_theta, raw_tilt, raw_phi
237  endif
238 
239  make /o /n=(dimsize(raw_data, 0)) dist_x, dist_x_smoo
240  make /o /n=(dimsize(raw_data, 1)) dist_y, dist_y_smoo
241 
242  SetDataFolder saveDF
243 end
244 
250  dfref df = $(package_path)
251  wave /sdfr=df process_data
252  svar /sdfr=df preview_graphname
253 
254  if (strlen(preview_graphname) && (wintype(preview_graphname) == 1))
255  ad_update_profiles(process_data)
256  DoWindow /F $preview_graphname
257  else
258  preview_graphname = ad_display_profiles(process_data)
259  endif
260 
261  nvar /sdfr=df graph_contrast
262  svar /sdfr=df graph_colortable
263  set_contrast(graph_contrast, graph_contrast, graphname=preview_graphname, colortable=graph_colortable)
264 end
265 
273 function asp_display_dist_check(xdist, ydist)
274  variable xdist, ydist
275 
276  dfref df = $(package_path)
277  wave /sdfr=df dist_x
278  wave /sdfr=df dist_y
279  wave /sdfr=df dist_x_smoo
280  wave /sdfr=df dist_y_smoo
281  svar /sdfr=df dist_x_graphname
282  svar /sdfr=df dist_y_graphname
283 
284  if (xdist)
285  if (strlen(dist_x_graphname) && (wintype(dist_x_graphname) == 1))
286  DoWindow /F $dist_x_graphname
287  else
288  display /k=1 /n=graph_asp_dist_x dist_x, dist_x_smoo
289  dist_x_graphname = s_name
290  ModifyGraph /w=$dist_x_graphname mode(dist_x)=2
291  ModifyGraph /w=$dist_x_graphname lsize(dist_x)=2
292  ModifyGraph /w=$dist_x_graphname rgb(dist_x)=(0,0,0)
293  endif
294  endif
295 
296  if (ydist)
297  if (strlen(dist_y_graphname) && (wintype(dist_y_graphname) == 1))
298  DoWindow /F $dist_y_graphname
299  else
300  display /k=1 /n=graph_asp_dist_y dist_y, dist_y_smoo
301  dist_y_graphname = s_name
302  ModifyGraph /w=$dist_y_graphname mode(dist_y)=2
303  ModifyGraph /w=$dist_y_graphname lsize(dist_y)=2
304  ModifyGraph /w=$dist_y_graphname rgb(dist_y)=(0,0,0)
305  endif
306  endif
307 end
308 
318 static function do_init_process(check)
319  variable check
320 
321  dfref df = $(package_path)
322  wave /sdfr=df raw
323  wave /sdfr=df raw_theta
324  wave /sdfr=df raw_tilt
325  wave /sdfr=df raw_phi
326  nvar /sdfr=df theta_offset
327  nvar /sdfr=df tilt_offset
328  nvar /sdfr=df phi_offset
329  nvar /sdfr=df alpha_offset
330 
331  duplicate /o raw, df:process_data
332  duplicate /o raw_theta, df:process_theta
333  duplicate /o raw_tilt, df:process_tilt
334  duplicate /o raw_phi, df:process_phi
335 
336  wave /sdfr=df process_data
337  wave /sdfr=df process_theta
338  wave /sdfr=df process_tilt
339  wave /sdfr=df process_phi
340 
341  process_theta = raw_theta - theta_offset
342  process_tilt = raw_tilt - tilt_offset
343  process_phi = raw_phi - phi_offset
344  setscale /p x dimoffset(raw, 0) - alpha_offset, dimdelta(raw, 0), waveunits(raw, 0), process_data
345 end
346 
358 static function do_crop(check, [force])
359  variable check
360  variable force
361 
362  if (ParamIsDefault(force))
363  force = 0
364  endif
365 
366  dfref df = $(package_path)
367  wave /sdfr=df process_data
368  wave /sdfr=df process_theta
369  wave /sdfr=df process_tilt
370  wave /sdfr=df process_phi
371  nvar /sdfr=df crop_enable
372  nvar /sdfr=df crop_alpha
373  nvar /sdfr=df crop_theta
374  svar /sdfr=df crop_rows
375 
376  if (force || crop_enable)
377 
378  if (crop_alpha > abs(dimdelta(process_data, 0)))
379  crop_strip(process_data, -crop_alpha, +crop_alpha)
380  endif
381 
382  if ((crop_theta >= 10) && (crop_theta < 90))
383  crop_strip_theta(process_data, 0, crop_theta, process_theta, process_tilt, process_phi)
384  endif
385 
386  if (strlen(crop_rows) > 0)
387  delete_rows(crop_rows, process_data, process_theta, process_tilt, process_phi)
388  endif
389  endif
390 end
391 
406 static function delete_rows(rows, data, theta, tilt, phi)
407  string rows
408  wave data
409  wave theta
410  wave tilt
411  wave phi
412 
413  make /n=(numpnts(theta)) /i /free idx
414  idx = p
415  variable nrows = ItemsInList(rows, ",")
416  variable irow
417  string srow
418  variable q1, q2
419  for (irow = 0; irow < nrows; irow += 1)
420  srow = StringFromList(irow, rows, ",")
421  q1 = str2num(StringFromList(0, srow, "-"))
422  q2 = str2num(StringFromList(1, srow, "-"))
423  if (numtype(q2))
424  q2 = q1
425  endif
426  if (q1 <= q2)
427  idx[q1,q2] = -1
428  endif
429  endfor
430  extract /free idx, idx, idx >= 0
431  variable nx = dimsize(data, 0)
432  variable ny = numpnts(idx)
433  theta = theta[idx]
434  tilt = tilt[idx]
435  phi = phi[idx]
436  redimension /n=(ny) theta, tilt, phi
437  duplicate /free data, data_copy
438  redimension /n=(nx,ny) data
439  data = data_copy[p][idx[q]]
440 end
441 
453 static function do_norm_alpha(check, [force])
454  variable check
455  variable force
456 
457  if (ParamIsDefault(force))
458  force = 0
459  endif
460 
461  dfref saveDF = GetDataFolderDFR()
462  dfref df = $(package_path)
463  wave /sdfr=df process_data
464  nvar /sdfr=df norm_alpha_enable
465  nvar /sdfr=df norm_alpha_mode
466  nvar /sdfr=df norm_alpha_smoothing
467 
468  if (force || norm_alpha_enable)
469  dfref temp_df = newfreedatafolder()
470  setdatafolder temp_df
471  normalize_strip_x(process_data, smooth_method=norm_alpha_mode, smooth_factor=norm_alpha_smoothing, check=check)
472  if (check)
473  wave check_dist
474  wave check_smoo
475  duplicate /o check_dist, df:dist_x
476  duplicate /o check_smoo, df:dist_x_smoo
477  endif
478  endif
479 
480  SetDataFolder saveDF
481 end
482 
494 static function do_norm_phi(check, [force])
495  variable check
496  variable force
497 
498  if (ParamIsDefault(force))
499  force = 0
500  endif
501 
502  dfref saveDF = GetDataFolderDFR()
503  dfref df = $(package_path)
504  wave /sdfr=df process_data
505  wave /sdfr=df process_theta
506  wave /sdfr=df process_phi
507  nvar /sdfr=df norm_phi_enable
508  nvar /sdfr=df norm_phi_mode
509  nvar /sdfr=df norm_phi_thetarange
510 
511  if (force || norm_phi_enable)
512  dfref temp_df = newfreedatafolder()
513  setdatafolder temp_df
514  normalize_strip_phi(process_data, process_theta, process_phi, theta_range=norm_phi_thetarange, check=check)
515  if (check)
516  wave check_dist
517  wave check_smoo
518  duplicate /o check_dist, df:dist_y
519  duplicate /o check_smoo, df:dist_y_smoo
520  endif
521  endif
522 
523  SetDataFolder saveDF
524 end
525 
537 static function do_norm_theta(check, [force])
538  variable check
539  variable force
540 
541  if (ParamIsDefault(force))
542  force = 0
543  endif
544 
545  dfref saveDF = GetDataFolderDFR()
546  dfref df = $(package_path)
547  wave /sdfr=df process_data
548  wave /sdfr=df process_theta
549  nvar /sdfr=df norm_theta_enable
550  nvar /sdfr=df norm_theta_mode
551  nvar /sdfr=df norm_theta_domain
552  nvar /sdfr=df norm_theta_smoothing
553 
554  if (force || norm_theta_enable)
555  dfref temp_df = newfreedatafolder()
556  setdatafolder temp_df
557  if (norm_theta_domain==1)
558  normalize_strip_theta_scans(process_data, process_theta, smooth_method=norm_theta_mode, smooth_factor=norm_theta_smoothing, check=check)
559  else
560  normalize_strip_theta(process_data, process_theta, smooth_method=norm_theta_mode, smooth_factor=norm_theta_smoothing, check=check)
561  endif
562  if (check)
563  wave check_dist
564  wave check_smoo
565  duplicate /o check_dist, df:dist_y
566  duplicate /o check_smoo, df:dist_y_smoo
567  endif
568  endif
569 
570  SetDataFolder saveDF
571 end
572 
584 static function do_norm_thetaphi(check, [force])
585  variable check
586  variable force
587 
588  if (ParamIsDefault(force))
589  force = 0
590  endif
591 
592  dfref saveDF = GetDataFolderDFR()
593  dfref df = $(package_path)
594  wave /sdfr=df process_data
595  wave /sdfr=df process_theta
596  wave /sdfr=df process_phi
597  nvar /sdfr=df norm_thetaphi_enable
598  nvar /sdfr=df norm_thetaphi_mode
599  nvar /sdfr=df norm_thetaphi_smoothing
600 
601  if (force || norm_thetaphi_enable)
602  dfref temp_df = newfreedatafolder()
603  setdatafolder temp_df
604  normalize_strip_thetaphi(process_data, process_theta, process_phi, smooth_method=norm_thetaphi_mode, smooth_factor=norm_thetaphi_smoothing, check=check)
605  if (check)
606  wave check_dist
607  wave check_smoo
608  duplicate /o check_dist, df:dist_y
609  duplicate /o check_smoo, df:dist_y_smoo
610  endif
611  endif
612 
613  SetDataFolder saveDF
614 end
615 
621  dfref saveDF = GetDataFolderDFR()
622  setdatafolder $(package_path)
623 
624  svar output_name
625 
626  wave process_data
627  wave process_theta
628  wave process_tilt
629  wave process_phi
630 
631  nvar folding=output_folding
632  nvar horizon=output_horizon
633 
634  do_init_process(0)
635  do_crop(0)
636  do_norm_alpha(0)
637  do_norm_phi(0)
638  do_norm_theta(0)
640 
641  pizza_service_2(process_data, output_name, process_theta, process_tilt, process_phi, folding=folding, nograph=1)
642 
643  setdatafolder $output_name
644  wave values
645  wave pol
646  if (horizon > 0)
647  values = pol <= horizon ? values : nan
648  endif
649 
650  SetDataFolder saveDF
651 end
652 
666 function /s asp_display_output([data_df, data_name])
667  dfref data_df
668  string data_name
669 
670  dfref pkg_df = $(package_path)
671  svar /sdfr=pkg_df output_name
672  svar /sdfr=pkg_df output_graphname
673  nvar /sdfr=pkg_df graph_projection
674  nvar /sdfr=pkg_df graph_mode
675  svar /sdfr=pkg_df graph_colortable
676  nvar /sdfr=pkg_df graph_contrast
677 
678  if (ParamIsDefault(data_df))
679  dfref data_df = pkg_df
680  endif
681  if (ParamIsDefault(data_name))
682  data_name = output_name
683  endif
684 
685  dfref saveDF = GetDataFolderDFR()
686  setdatafolder data_df
687 
688  if (graph_mode == 3)
689  interpolate_hemi_scan(data_name, projection=graph_projection)
690  endif
691 
692  string graphname = data_name
693  graphname = display_hemi_scan(data_name, projection=graph_projection, graphtype=graph_mode, graphname=graphname)
694  if (ParamIsDefault(data_df))
695  output_graphname = graphname
696  endif
697  SetDataFolder saveDF
698 
699  if (strlen(graphname) && (wintype(graphname) == 1))
700  set_contrast(graph_contrast, graph_contrast, graphname=graphname, colortable=graph_colortable)
701  endif
702 
703  return graphname
704 end
705 
711  dfref df = $(package_path)
712 
713  svar /sdfr=df preview_graphname
714  svar /sdfr=df output_graphname
715  svar /sdfr=df graph_colortable
716  nvar /sdfr=df graph_contrast
717 
718  if (strlen(preview_graphname) && (wintype(preview_graphname) == 1))
719  set_contrast(graph_contrast, graph_contrast, graphname=preview_graphname, colortable=graph_colortable)
720  endif
721  if (strlen(output_graphname) && (wintype(output_graphname) == 1))
722  set_contrast(graph_contrast, graph_contrast, graphname=output_graphname, colortable=graph_colortable)
723  endif
724 end
725 
729  dfref df = $(package_path)
730 
731  svar /sdfr=df preview_graphname
732  svar /sdfr=df output_graphname
733  svar /sdfr=df dist_x_graphname
734  svar /sdfr=df dist_y_graphname
735 
736  if (strlen(preview_graphname) && (wintype(preview_graphname) == 1))
737  killwindow $preview_graphname
738  endif
739  if (strlen(output_graphname) && (wintype(output_graphname) == 1))
740  killwindow $output_graphname
741  endif
742  if (strlen(dist_x_graphname) && (wintype(dist_x_graphname) == 1))
743  killwindow $dist_x_graphname
744  endif
745  if (strlen(dist_y_graphname) && (wintype(dist_y_graphname) == 1))
746  killwindow $dist_y_graphname
747  endif
748 
749  preview_graphname = ""
750  output_graphname = ""
751  dist_x_graphname = ""
752  dist_y_graphname = ""
753 end
754 
768 function /s asp_duplicate_output(dest_name, [do_graph])
769  string dest_name
770  variable do_graph
771 
772  if (ParamIsDefault(do_graph))
773  do_graph = 0
774  endif
775 
776  dfref df = $(package_path)
777  svar /sdfr=df source_path
778  svar /sdfr=df output_name
779  svar /sdfr=df output_graphname
780  wave raw_data = $source_path
781 
782  dfref saveDF = GetDataFolderDFR()
783  dfref raw_df = GetWavesDataFolderDFR(raw_data)
784  setdatafolder raw_df
785  newdatafolder /o /s $dest_name
786  dfref dest_df = GetDataFolderDFR()
787  setdatafolder df
788  duplicate_hemi_scan(output_name, dest_df, "")
789 
790  string graphname = ""
791  if (do_graph)
792  graphname = asp_display_output(data_df=raw_df, data_name=dest_name)
793  endif
794 
795  SetDataFolder saveDF
796  return graphname
797 end
798 
802  dfref df = $(package_path)
803  svar /sdfr=df output_name
804 
805  dfref saveDF = GetDataFolderDFR()
806  setdatafolder df
807  save_hemi_scan(output_name, "", "")
808 
809  SetDataFolder saveDF
810 end
811 
816 function asp_save_output_etpi(ekin)
817  variable ekin
818 
819  dfref df = $(package_path)
820  svar /sdfr=df output_name
821  wave /sdfr=df process_data
822 
823  dfref saveDF = GetDataFolderDFR()
824  setdatafolder df
825  string s_prefix = ""
826  string s_int = "values"
827  dfref data_df = find_hemi_data(output_name, s_prefix, s_int)
828  string s_polar = s_prefix + "pol"
829  string s_azim = s_prefix + "az"
830 
831  pmsco_save_scan("", "", num2str(ekin), s_polar, s_azim, "", s_int, "", sdfr=data_df)
832 
833  SetDataFolder saveDF
834 end
835 
836 static function check_norm_alpha()
837  do_init_process(0)
838  do_crop(0)
839  do_norm_alpha(2, force=1)
841 end
842 
843 static function check_norm_phi()
844  do_init_process(0)
845  do_crop(0)
846  do_norm_phi(2, force=1)
847  asp_display_dist_check(0, 1)
848 end
849 
850 static function check_norm_theta()
851  do_init_process(0)
852  do_crop(0)
853  do_norm_theta(2, force=1)
854  asp_display_dist_check(0, 1)
855 end
856 
857 static function check_norm_thetaphi()
858  do_init_process(0)
859  do_crop(0)
860  do_norm_thetaphi(2, force=1)
861  asp_display_dist_check(0, 1)
862 end
863 
864 static function preview_crop()
865  do_init_process(0)
866  do_crop(0, force=1)
868 end
869 
870 static function preview_norm_alpha()
871  do_init_process(0)
872  do_crop(0)
873  do_norm_alpha(1, force=1)
875 end
876 
877 static function preview_norm_phi()
878  do_init_process(0)
879  do_crop(0)
880  do_norm_phi(1, force=1)
882 end
883 
884 static function preview_norm_theta()
885  do_init_process(0)
886  do_crop(0)
887  do_norm_theta(1, force=1)
889 end
890 
891 static function preview_norm_thetaphi()
892  do_init_process(0)
893  do_crop(0)
894  do_norm_thetaphi(1, force=1)
896 end
897 
900 function asp_show_panel()
901  dfref df = $(package_path)
902  svar /sdfr=df panel_name
903 
904  if (strlen(panel_name) && (wintype(panel_name) == 7))
905  DoWindow /F $panel_name
906  return 0
907  endif
908 
909  NewPanel /K=1 /N=anglescan_panel /W=(200,50,480,874) as "angle scan processing"
910  panel_name = s_name
911 
912  GroupBox gb_source, title="data source"
913  Button b_source_select, size={50,20},proc=PearlAnglescanPanel#bp_source_select,title="select..."
914  Button b_source_select, help={"select the source wave, e.g. ReducedData1. it must be in the scan or region data folder. the attr folder with the manipulator waves must be in the same folder or one level up."}
915  Button b_source_update, size={50,20},proc=PearlAnglescanPanel#bp_source_update,title="update"
916  Button b_source_update, help={"reload the process data from the previous source (link displayed below)"}
917  TitleBox tb_source_path, size={240,21}
918  TitleBox tb_source_path,variable= root:packages:pearl_anglescan_panel:source_path
919 
920  GroupBox gb_offsets, title="offsets"
921  SetVariable sv_theta_offset, size={88,16},bodyWidth=60,title="theta"
922  SetVariable sv_theta_offset,value= root:packages:pearl_anglescan_panel:theta_offset
923  SetVariable sv_theta_offset, help={"manipulator theta value that corresponds to normal emission."}
924  SetVariable sv_tilt_offset, size={74,16},bodyWidth=60,title="tilt"
925  SetVariable sv_tilt_offset,value= root:packages:pearl_anglescan_panel:tilt_offset
926  SetVariable sv_tilt_offset, help={"manipulator tilt value that corresponds to normal emission."}
927  SetVariable sv_phi_offset, size={78,16},bodyWidth=60,title="phi"
928  SetVariable sv_phi_offset,value= root:packages:pearl_anglescan_panel:phi_offset
929  SetVariable sv_phi_offset, help={"manipulator phi value that should map to the 3 o'clock angle."}
930  SetVariable sv_alpha_offset, size={90,16},bodyWidth=60,title="alpha"
931  SetVariable sv_alpha_offset,value= root:packages:pearl_anglescan_panel:alpha_offset
932  SetVariable sv_alpha_offset, help={"alpha value that corresponds to normal emission (if the sample normal is properly aligned)."}
933  Button b_save_prefs, size={80,20},proc=PearlAnglescanPanel#bp_save_prefs,title="save prefs"
934  Button b_save_prefs, help={"save settings as preferences."}
935  Button b_load_prefs, size={80,20},proc=PearlAnglescanPanel#bp_load_prefs,title="load prefs"
936  Button b_load_prefs, help={"load settings from preferences."}
937 
938  GroupBox gb_crop, title="crop and delete"
939  CheckBox cb_crop_enable, size={50,14}, title="enable"
940  CheckBox cb_crop_enable, help={"crop at +/-alpha and +theta, delete arbitrary rows"}
941  CheckBox cb_crop_enable, variable= root:packages:pearl_anglescan_panel:crop_enable
942  SetVariable sv_crop_alpha, size={90,16},bodyWidth=60,title="alpha"
943  SetVariable sv_crop_alpha, limits={0,30,1},value= root:packages:pearl_anglescan_panel:crop_alpha
944  SetVariable sv_crop_alpha, help={"alpha (detection angle) cropping angle (positive boundary), relative to normal emission"}
945  SetVariable sv_crop_theta, size={90,16},bodyWidth=60,title="theta"
946  SetVariable sv_crop_theta, limits={10,90,1},value= root:packages:pearl_anglescan_panel:crop_theta
947  SetVariable sv_crop_theta, help={"theta (polar angle) upper limit, relative to normal emission"}
948  SetVariable sv_crop_rows, size={200,16},bodyWidth=160,title="rows"
949  SetVariable sv_crop_rows, limits={10,90,1},value= root:packages:pearl_anglescan_panel:crop_rows
950  SetVariable sv_crop_rows, help={"rows to delete from the raw data. comma-separated point indices, hyphen for range."}
951  Button b_crop_preview, size={80,20},proc=PearlAnglescanPanel#bp_crop_preview,title="preview"
952  Button b_crop_preview, help={"show a preview of the cropped dataset."}
953 
954  GroupBox gb_norm_alpha, title="normalize alpha"
955  CheckBox cb_norm_alpha_enable, size={50,14}, title="enable"
956  CheckBox cb_norm_alpha_enable,variable= root:packages:pearl_anglescan_panel:norm_alpha_enable
957  CheckBox cb_norm_alpha_enable, help={"enable normalization of the alpha distribution"}
958  PopupMenu pm_norm_alpha_mode, size={138,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_norm_alpha_mode,title="method"
959  PopupMenu pm_norm_alpha_mode, mode=5, popvalue="loess", value= #"\"none;binomial;boxcar;scienta;loess;\""
960  PopupMenu pm_norm_alpha_mode, help={"alpha normalization method. recommended: loess"}
961  SetVariable sv_norm_alpha_smoothing, size={112,16}, bodyWidth=60, title="smoothing"
962  SetVariable sv_norm_alpha_smoothing, limits={0,1,0.05}, value= root:packages:pearl_anglescan_panel:norm_alpha_smoothing
963  SetVariable sv_norm_alpha_smoothing, help={"smoothing parameter (depends on the normalization method)."}
964  Button b_norm_alpha_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_alpha_check,title="check"
965  Button b_norm_alpha_check, help={"show a graph of the normalization function"}
966  Button b_norm_alpha_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_alpha_preview,title="preview"
967  Button b_norm_alpha_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
968 
969  GroupBox gb_norm_phi, title="normalize phi"
970  CheckBox cb_norm_phi_enable, size={50,14}, title="enable"
971  CheckBox cb_norm_phi_enable,variable= root:packages:pearl_anglescan_panel:norm_phi_enable
972  CheckBox cb_norm_phi_enable, help={"enable normalization of the phi distribution to reduce the effect of wobble"}
973  SetVariable sv_norm_phi_range, size={118,16}, bodyWidth=60, title="theta range"
974  SetVariable sv_norm_phi_range, limits={0,90,1}, value= root:packages:pearl_anglescan_panel:norm_phi_thetarange
975  SetVariable sv_norm_phi_range, help={"theta range (from normal) to factor into the normalization function"}
976  Button b_norm_phi_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_phi_check, title="check"
977  Button b_norm_phi_check, help={"show a graph of the normalization function"}
978  Button b_norm_phi_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_phi_preview, title="preview"
979  Button b_norm_phi_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
980 
981  GroupBox gb_norm_theta, title="normalize theta"
982  CheckBox cb_norm_theta_enable, size={50,14},title="enable"
983  CheckBox cb_norm_theta_enable, variable= root:packages:pearl_anglescan_panel:norm_theta_enable
984  CheckBox cb_norm_theta_enable, help={"enable normalization of the theta distribution (integrated over phi)"}
985  PopupMenu pm_norm_theta_domain, size={138,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_norm_theta_domain, title="domain"
986  PopupMenu pm_norm_theta_domain, mode=5, popvalue="loess", value= #"\"global;scans;\""
987  PopupMenu pm_norm_theta_domain, help={"smoothing domain: global or individual scans. use global unless there is a stronga or irregular phi variation."}
988  PopupMenu pm_norm_theta_mode, size={138,21},bodyWidth=100,proc=PearlAnglescanPanel#pmp_norm_theta_mode,title="method"
989  PopupMenu pm_norm_theta_mode,mode=5,popvalue="loess",value= #"\"none;binomial;boxcar;polynomial;loess;\""
990  PopupMenu pm_norm_theta_mode, help={"theta normalization method. recommended: loess"}
991  SetVariable sv_norm_theta_smoothing, size={112,16}, bodyWidth=60, title="smoothing"
992  SetVariable sv_norm_theta_smoothing, limits={0,1,0.05}, value= root:packages:pearl_anglescan_panel:norm_theta_smoothing
993  SetVariable sv_norm_theta_smoothing, help={"smoothing parameter (depends on the normalization method)."}
994  Button b_norm_theta_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_theta_check, title="check"
995  Button b_norm_theta_check, help={"show a graph of the normalization function"}
996  Button b_norm_theta_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_theta_preview, title="preview"
997  Button b_norm_theta_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
998 
999  GroupBox gb_norm_thetaphi, size={272,97},title="normalize (theta,phi)"
1000  CheckBox cb_norm_thetaphi_enable, size={50,14},title="enable"
1001  CheckBox cb_norm_thetaphi_enable, variable= root:packages:pearl_anglescan_panel:norm_thetaphi_enable
1002  CheckBox cb_norm_thetaphi_enable, help={"enable normalization of the (theta, phi) distribution."}
1003  PopupMenu pm_norm_thetaphi_mode, size={138,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_norm_thetaphi_mode,title="method"
1004  PopupMenu pm_norm_thetaphi_mode, mode=5, popvalue="loess", value= #"\"none;none;none;none;loess;\""
1005  PopupMenu pm_norm_thetaphi_mode, help={"theta normalization method. recommended: loess"}
1006  SetVariable sv_norm_thetaphi_smoothing, size={112,16}, bodyWidth=60, title="smoothing"
1007  SetVariable sv_norm_thetaphi_smoothing, limits={0,1,0.05}, value= root:packages:pearl_anglescan_panel:norm_thetaphi_smoothing
1008  SetVariable sv_norm_thetaphi_smoothing, help={"smoothing parameter (depends on the normalization method)."}
1009  Button b_norm_thetaphi_check, size={80,20}, proc=PearlAnglescanPanel#bp_norm_thetaphi_check, title="check"
1010  Button b_norm_thetaphi_check, help={"show a graph of the normalization function"}
1011  Button b_norm_thetaphi_preview, size={80,20}, proc=PearlAnglescanPanel#bp_norm_thetaphi_preview, title="preview"
1012  Button b_norm_thetaphi_preview, help={"show a preview of the normalized dataset (without other normalizations)."}
1013 
1014  GroupBox gb_output, title="output"
1015  SetVariable sv_output_folding, size={95,16}, bodyWidth=60, title="folding"
1016  SetVariable sv_output_folding, limits={1,20,1}, value= root:packages:pearl_anglescan_panel:output_folding
1017  SetVariable sv_output_folding, help={"n-fold rotational average. 1=no averaging."}
1018  SetVariable sv_output_horizon, size={98,16}, bodyWidth=60, title="horizon"
1019  SetVariable sv_output_horizon, limits={1,90,1}, value= root:packages:pearl_anglescan_panel:output_horizon
1020  SetVariable sv_output_horizon, help={"highest theta to display"}
1021  PopupMenu pm_graph_projection, size={149,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_graph_projection, title="projection"
1022  PopupMenu pm_graph_projection, mode=2, popvalue="stereographic", value= #"\"equidistant;stereographic;equal area;gnomonic;orthographic;\""
1023  PopupMenu pm_graph_projection, help={"projection (theta mapping) mode"}
1024  PopupMenu pm_graph_mode, size={129,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_graph_mode,title="mode"
1025  PopupMenu pm_graph_mode, mode=2, popvalue="dots", value= #"\"none;dots;none;image;\""
1026  PopupMenu pm_graph_mode, help={"graph type: dots = coloured dots on circles; image = interpolated matrix"}
1027  Button b_output_calc, size={80,20}, proc=PearlAnglescanPanel#bp_output_calc, title="calc + display"
1028  Button b_output_calc, help={"execute data processing with the enabled filters and display the diffractogram."}
1029  Button b_output_duplicate, size={80,20}, proc=PearlAnglescanPanel#bp_output_duplicate, title="duplicate ..."
1030  Button b_output_duplicate, help={"copy the result to an arbitrary data folder."}
1031  Button b_output_itx, size={80,20}, proc=PearlAnglescanPanel#bp_output_itx, title="save ITX ..."
1032  Button b_output_itx, help={"save the result to an igor text file (itx)."}
1033  Button b_output_etpi, size={80,20}, proc=PearlAnglescanPanel#bp_output_etpi, title="save ETPI ..."
1034  Button b_output_etpi, help={"save the result to a pmsco angle scan file (etpi)."}
1035 
1036  GroupBox gb_graph, title="graph"
1037  PopupMenu pm_graph_colortable, size={152,21}, bodyWidth=100, proc=PearlAnglescanPanel#pmp_graph_colortable, title="color table"
1038  PopupMenu pm_graph_colortable, mode=0, value= #"\"*COLORTABLEPOPNONAMES*\""
1039  PopupMenu pm_graph_colortable, help={"color table to use in pseudocolor graphs."}
1040  SetVariable sv_graph_contrast, size={119,16}, bodyWidth=60, title="contrast (%)"
1041  SetVariable sv_graph_contrast, limits={0,25,1}, value= root:packages:pearl_anglescan_panel:graph_contrast
1042  SetVariable sv_graph_contrast, help={"contrast value (percentile)."}
1043  Button b_graph_update, size={80,20}, proc=PearlAnglescanPanel#bp_graph_update, title="update"
1044  Button b_graph_update, help={"update the existing graph."}
1045  Button b_graph_png, size={80,20}, proc=PearlAnglescanPanel#bp_graph_png, title="save PNG ..."
1046  Button b_graph_png, help={"save the graph in png format."}
1047 
1049  update_menus()
1050 end
1051 
1052 static function arrange_controls()
1053  dfref df = $(package_path)
1054  svar /sdfr=df panel_name
1055 
1056  variable gb_space = 2
1057  variable gb_internal_top = 16
1058  variable gb_internal_bot = 4
1059  variable line_space = 22
1060 
1061  variable cb_adj = 2
1062  variable sv_adj = 2
1063  variable pm_adj = 0
1064  variable b_adj = 0
1065  variable tb_adj = 0
1066 
1067  variable gb_top = 4
1068  variable gb_ht = 0
1069 
1070  // ht = line + 30
1071  // gb = gb + ht + 2
1072  // cb = gb + 18
1073  // pm = gb + 38
1074  // line += 26
1075  // sv = line + 2
1076 
1077  GroupBox gb_source,pos={4,gb_top}
1078  gb_ht = gb_internal_top
1079  Button b_source_select,pos={17, gb_top + gb_ht + b_adj},size={50,20}
1080  Button b_source_update, pos={67, gb_top + gb_ht + b_adj},size={50,20}
1081  gb_ht += line_space
1082  TitleBox tb_source_path,pos={18, gb_top + gb_ht + tb_adj},size={240,21}
1083  gb_ht += line_space
1084  gb_ht += gb_internal_bot
1085  GroupBox gb_source, size={272,gb_ht}
1086 
1087  gb_top += gb_ht + gb_space
1088  GroupBox gb_offsets,pos={4,gb_top}
1089  gb_ht = gb_internal_top
1090  SetVariable sv_theta_offset,pos={46, gb_top + gb_ht + sv_adj},size={88,16}
1091  Button b_save_prefs,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1092  gb_ht += line_space
1093  SetVariable sv_tilt_offset,pos={60, gb_top + gb_ht + sv_adj},size={74,16}
1094  Button b_load_prefs,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1095  gb_ht += line_space
1096  SetVariable sv_phi_offset,pos={56, gb_top + gb_ht + sv_adj},size={78,16}
1097  gb_ht += line_space
1098  SetVariable sv_alpha_offset,pos={44, gb_top + gb_ht + sv_adj},size={90,16}
1099  gb_ht += line_space
1100  gb_ht += gb_internal_bot
1101  GroupBox gb_offsets, size={272,gb_ht}
1102 
1103  gb_top += gb_ht + gb_space
1104  GroupBox gb_crop,pos={4,gb_top}
1105  gb_ht = gb_internal_top
1106  CheckBox cb_crop_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1107  gb_ht += line_space
1108  SetVariable sv_crop_alpha, pos={44, gb_top + gb_ht + sv_adj}, size={90,16}
1109  Button b_crop_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1110  gb_ht += line_space
1111  SetVariable sv_crop_theta, pos={44, gb_top + gb_ht + sv_adj}, size={90,16}
1112  gb_ht += line_space
1113  SetVariable sv_crop_rows, pos={44, gb_top + gb_ht + sv_adj}, size={190,16}
1114  gb_ht += line_space
1115  gb_ht += gb_internal_bot
1116  GroupBox gb_crop, size={272,gb_ht}
1117 
1118  gb_top += gb_ht + gb_space
1119  GroupBox gb_norm_alpha,pos={4,gb_top}
1120  gb_ht = gb_internal_top
1121  CheckBox cb_norm_alpha_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1122  gb_ht += line_space
1123  PopupMenu pm_norm_alpha_mode,pos={36, gb_top + gb_ht + pm_adj},size={138,21}
1124  Button b_norm_alpha_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1125  gb_ht += line_space
1126  SetVariable sv_norm_alpha_smoothing,pos={22, gb_top + gb_ht + sv_adj},size={112,16}
1127  Button b_norm_alpha_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1128  gb_ht += line_space
1129  gb_ht += gb_internal_bot
1130  GroupBox gb_norm_alpha, size={272,gb_ht}
1131 
1132  gb_top += gb_ht + gb_space
1133  GroupBox gb_norm_phi,pos={4,gb_top}
1134  gb_ht = gb_internal_top
1135  CheckBox cb_norm_phi_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1136  Button b_norm_phi_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1137  gb_ht += line_space
1138  SetVariable sv_norm_phi_range,pos={15, gb_top + gb_ht + sv_adj},size={118,16}
1139  Button b_norm_phi_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1140  gb_ht += line_space
1141  gb_ht += gb_internal_bot
1142  GroupBox gb_norm_phi, size={272,gb_ht}
1143 
1144  gb_top += gb_ht + gb_space
1145  GroupBox gb_norm_theta,pos={4,gb_top}
1146  gb_ht = gb_internal_top
1147  CheckBox cb_norm_theta_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1148  gb_ht += line_space
1149  PopupMenu pm_norm_theta_domain, pos={35, gb_top + gb_ht + pm_adj}, size={138,21}
1150  Button b_norm_theta_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1151  gb_ht += line_space
1152  PopupMenu pm_norm_theta_mode,pos={35, gb_top + gb_ht + pm_adj},size={138,21}
1153  Button b_norm_theta_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1154  gb_ht += line_space
1155  SetVariable sv_norm_theta_smoothing,pos={21, gb_top + gb_ht + sv_adj},size={112,16}
1156  gb_ht += line_space
1157  gb_ht += gb_internal_bot
1158  GroupBox gb_norm_theta, size={272,gb_ht}
1159 
1160  gb_top += gb_ht + gb_space
1161  GroupBox gb_norm_thetaphi,pos={4,gb_top}
1162  gb_ht = gb_internal_top
1163  CheckBox cb_norm_thetaphi_enable,pos={73, gb_top + gb_ht + cb_adj},size={50,14}
1164  gb_ht += line_space
1165  PopupMenu pm_norm_thetaphi_mode,pos={35, gb_top + gb_ht + pm_adj},size={138,21}
1166  Button b_norm_thetaphi_check,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1167  gb_ht += line_space
1168  SetVariable sv_norm_thetaphi_smoothing,pos={21, gb_top + gb_ht + sv_adj},size={112,16}
1169  Button b_norm_thetaphi_preview,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1170  gb_ht += line_space
1171  gb_ht += gb_internal_bot
1172  GroupBox gb_norm_thetaphi, size={272,gb_ht}
1173 
1174  gb_top += gb_ht + gb_space
1175  GroupBox gb_output,pos={4,gb_top}
1176  gb_ht = gb_internal_top
1177  SetVariable sv_output_folding,pos={38, gb_top + gb_ht + sv_adj},size={95,16}
1178  Button b_output_calc,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1179  gb_ht += line_space
1180  SetVariable sv_output_horizon,pos={35, gb_top + gb_ht + sv_adj},size={98,16}
1181  Button b_output_duplicate,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1182  gb_ht += line_space
1183  PopupMenu pm_graph_projection,pos={24, gb_top + gb_ht + pm_adj},size={149,21}
1184  Button b_output_itx,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1185  gb_ht += line_space
1186  PopupMenu pm_graph_mode,pos={44, gb_top + gb_ht + pm_adj},size={129,21}
1187  Button b_output_etpi,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1188  gb_ht += line_space
1189  gb_ht += gb_internal_bot
1190  GroupBox gb_output, size={272,gb_ht}
1191 
1192  gb_top += gb_ht + gb_space
1193  GroupBox gb_graph,pos={4,gb_top}
1194  gb_ht = gb_internal_top
1195  PopupMenu pm_graph_colortable,pos={21, gb_top + gb_ht + pm_adj},size={152,21}
1196  Button b_graph_update,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1197  gb_ht += line_space
1198  SetVariable sv_graph_contrast,pos={14, gb_top + gb_ht + sv_adj},size={119,16}
1199  Button b_graph_png,pos={186, gb_top + gb_ht + b_adj},size={80,20}
1200  gb_ht += line_space
1201  gb_ht += gb_internal_bot
1202  GroupBox gb_graph, size={272,gb_ht}
1203 
1204  gb_top += gb_ht + gb_space
1205  //MoveWindow 200, 100, 479, 100 + gb_top
1206 end
1207 
1210 static function update_menus()
1211  dfref df = $(package_path)
1212  svar /sdfr=df panel_name
1213  if (wintype(panel_name) == 7)
1214  variable m
1215  nvar /sdfr=df norm_alpha_mode
1216  m = norm_alpha_mode + 1
1217  PopupMenu pm_norm_alpha_mode win=$panel_name, mode=m
1218  nvar /sdfr=df norm_theta_domain
1219  m = norm_theta_domain + 1
1220  PopupMenu pm_norm_theta_domain win=$panel_name, mode=m
1221  nvar /sdfr=df norm_theta_mode
1222  m = norm_theta_mode + 1
1223  PopupMenu pm_norm_theta_mode win=$panel_name, mode=m
1224  nvar /sdfr=df norm_thetaphi_mode
1225  m = norm_thetaphi_mode + 1
1226  PopupMenu pm_norm_thetaphi_mode win=$panel_name, mode=m
1227  nvar /sdfr=df graph_mode
1228  m = graph_mode + 1
1229  PopupMenu pm_graph_mode win=$panel_name, mode=m
1230  nvar /sdfr=df graph_projection
1231  m = graph_projection + 1
1232  PopupMenu pm_graph_projection win=$panel_name, mode=m
1233  svar /sdfr=df graph_colortable
1234  m = 1 + WhichListItem(graph_colortable, CTabList())
1235  PopupMenu pm_graph_colortable win=$panel_name, mode=m
1236  endif
1237 end
1238 
1239 static function bp_load_prefs(ba) : ButtonControl
1240  STRUCT WMButtonAction &ba
1241 
1242  switch( ba.eventCode )
1243  case 2: // mouse up
1244  load_prefs()
1245  break
1246  case -1: // control being killed
1247  break
1248  endswitch
1249 
1250  return 0
1251 End
1252 
1253 static function bp_save_prefs(ba) : ButtonControl
1254  STRUCT WMButtonAction &ba
1255 
1256  switch( ba.eventCode )
1257  case 2: // mouse up
1258  save_prefs()
1259  break
1260  case -1: // control being killed
1261  break
1262  endswitch
1263 
1264  return 0
1265 End
1266 
1267 static function bp_source_select(ba) : ButtonControl
1268  STRUCT WMButtonAction &ba
1269 
1270  switch( ba.eventCode )
1271  case 2: // mouse up
1272  dfref dfBefore = GetDataFolderDFR()
1273  Execute /q/z "CreateBrowser prompt=\"Select 2D holo scan wave\", showWaves=1, showVars=0, showStrs=0"
1274  dfref dfAfter = GetDataFolderDFR()
1275  SetDataFolder dfBefore
1276 
1277  SVAR list = S_BrowserList
1278  NVAR flag = V_Flag
1279  if ((flag != 0) && (ItemsInList(list) >= 1))
1280  string wname = StringFromList(0, list)
1281  wave w = $wname
1282  asp_import_raw(w)
1283  endif
1284 
1285  break
1286  case -1: // control being killed
1287  break
1288  endswitch
1289 
1290  return 0
1291 End
1292 
1293 static function bp_source_update(ba) : ButtonControl
1294  STRUCT WMButtonAction &ba
1295 
1296  switch( ba.eventCode )
1297  case 2: // mouse up
1298  dfref packdf = $package_path
1299  svar /sdfr=packdf source_path
1300  wave /z w = $source_path
1301  if (waveexists(w))
1302  asp_import_raw(w)
1303  else
1304  DoAlert 0, "can't find source data."
1305  endif
1306  break
1307  case -1: // control being killed
1308  break
1309  endswitch
1310 
1311  return 0
1312 End
1313 
1314 static function bp_norm_alpha_check(ba) : ButtonControl
1315  STRUCT WMButtonAction &ba
1316 
1317  switch( ba.eventCode )
1318  case 2: // mouse up
1320  break
1321  case -1: // control being killed
1322  break
1323  endswitch
1324 
1325  return 0
1326 End
1327 
1328 static function bp_norm_theta_check(ba) : ButtonControl
1329  STRUCT WMButtonAction &ba
1330 
1331  switch( ba.eventCode )
1332  case 2: // mouse up
1334  break
1335  case -1: // control being killed
1336  break
1337  endswitch
1338 
1339  return 0
1340 End
1341 
1342 static function bp_norm_phi_check(ba) : ButtonControl
1343  STRUCT WMButtonAction &ba
1344 
1345  switch( ba.eventCode )
1346  case 2: // mouse up
1347  check_norm_phi()
1348  break
1349  case -1: // control being killed
1350  break
1351  endswitch
1352 
1353  return 0
1354 End
1355 
1356 static function bp_norm_thetaphi_check(ba) : ButtonControl
1357  STRUCT WMButtonAction &ba
1358 
1359  switch( ba.eventCode )
1360  case 2: // mouse up
1362  break
1363  case -1: // control being killed
1364  break
1365  endswitch
1366 
1367  return 0
1368 End
1369 
1370 static function bp_crop_preview(ba) : ButtonControl
1371  STRUCT WMButtonAction &ba
1372 
1373  switch( ba.eventCode )
1374  case 2: // mouse up
1375  preview_crop()
1376  break
1377  case -1: // control being killed
1378  break
1379  endswitch
1380 
1381  return 0
1382 End
1383 
1384 static function bp_norm_alpha_preview(ba) : ButtonControl
1385  STRUCT WMButtonAction &ba
1386 
1387  switch( ba.eventCode )
1388  case 2: // mouse up
1390  break
1391  case -1: // control being killed
1392  break
1393  endswitch
1394 
1395  return 0
1396 End
1397 
1398 static function bp_norm_phi_preview(ba) : ButtonControl
1399  STRUCT WMButtonAction &ba
1400 
1401  switch( ba.eventCode )
1402  case 2: // mouse up
1404  break
1405  case -1: // control being killed
1406  break
1407  endswitch
1408 
1409  return 0
1410 End
1411 
1412 static function bp_norm_theta_preview(ba) : ButtonControl
1413  STRUCT WMButtonAction &ba
1414 
1415  switch( ba.eventCode )
1416  case 2: // mouse up
1418  break
1419  case -1: // control being killed
1420  break
1421  endswitch
1422 
1423  return 0
1424 End
1425 
1426 static function bp_norm_thetaphi_preview(ba) : ButtonControl
1427  STRUCT WMButtonAction &ba
1428 
1429  switch( ba.eventCode )
1430  case 2: // mouse up
1432  break
1433  case -1: // control being killed
1434  break
1435  endswitch
1436 
1437  return 0
1438 End
1439 
1440 static function bp_output_calc(ba) : ButtonControl
1441  STRUCT WMButtonAction &ba
1442 
1443  switch( ba.eventCode )
1444  case 2: // mouse up
1447  break
1448  case -1: // control being killed
1449  break
1450  endswitch
1451 
1452  return 0
1453 End
1454 
1455 static function bp_output_duplicate(ba) : ButtonControl
1456  STRUCT WMButtonAction &ba
1457 
1458  switch( ba.eventCode )
1459  case 2: // mouse up
1460  string dest_folder
1461  variable do_graph = 1
1462  prompt dest_folder, "destination folder name (relative to data source)"
1463  prompt do_graph, "duplicate graph (yes = 1, no = 0)"
1464  doprompt "duplicate", dest_folder, do_graph
1465  if (!v_flag)
1466  asp_duplicate_output(dest_folder, do_graph=do_graph)
1467  endif
1468  break
1469  case -1: // control being killed
1470  break
1471  endswitch
1472 
1473  return 0
1474 End
1475 
1476 static function bp_output_etpi(ba) : ButtonControl
1477  STRUCT WMButtonAction &ba
1478 
1479  switch( ba.eventCode )
1480  case 2: // mouse up
1481  dfref df = $(package_path)
1482  wave /sdfr=df process_data
1483  variable ekin
1484  ekin = NumberByKey("KineticEnergy", note(process_data), "=", "\r")
1485  prompt ekin, "kinetic energy"
1486  doprompt "save etpi", ekin
1487  if (!v_flag)
1488  asp_save_output_etpi(ekin)
1489  endif
1490  break
1491  case -1: // control being killed
1492  break
1493  endswitch
1494 
1495  return 0
1496 End
1497 
1498 static function bp_output_itx(ba) : ButtonControl
1499  STRUCT WMButtonAction &ba
1500 
1501  switch( ba.eventCode )
1502  case 2: // mouse up
1504  break
1505  case -1: // control being killed
1506  break
1507  endswitch
1508 
1509  return 0
1510 End
1511 
1512 static function bp_graph_update(ba) : ButtonControl
1513  STRUCT WMButtonAction &ba
1514 
1515  switch( ba.eventCode )
1516  case 2: // mouse up
1518  break
1519  case -1: // control being killed
1520  break
1521  endswitch
1522 
1523  return 0
1524 End
1525 
1526 static function bp_graph_png(ba) : ButtonControl
1527  STRUCT WMButtonAction &ba
1528 
1529  switch( ba.eventCode )
1530  case 2: // mouse up
1531  dfref df = $(package_path)
1532  svar /sdfr=df source_path
1533  svar /sdfr=df output_graphname
1534  if (WinType(output_graphname) == 1)
1535  SavePICT /WIN=$output_graphname /E=-5 /B=144 /TRAN=0
1536  endif
1537  break
1538  case -1: // control being killed
1539  break
1540  endswitch
1541 
1542  return 0
1543 End
1544 
1545 static function pmp_norm_alpha_mode(pa) : PopupMenuControl
1546  STRUCT WMPopupAction &pa
1547 
1548  switch( pa.eventCode )
1549  case 2: // mouse up
1550  dfref df = $(package_path)
1551  nvar /sdfr=df norm_alpha_mode
1552  norm_alpha_mode = pa.popNum - 1
1553  break
1554  case -1: // control being killed
1555  break
1556  endswitch
1557 
1558  return 0
1559 End
1560 
1561 static function pmp_norm_theta_domain(pa) : PopupMenuControl
1562  STRUCT WMPopupAction &pa
1563 
1564  switch( pa.eventCode )
1565  case 2: // mouse up
1566  dfref df = $(package_path)
1567  nvar /sdfr=df norm_theta_domain
1568  norm_theta_domain = pa.popNum - 1
1569  break
1570  case -1: // control being killed
1571  break
1572  endswitch
1573 
1574  return 0
1575 End
1576 
1577 static function pmp_norm_theta_mode(pa) : PopupMenuControl
1578  STRUCT WMPopupAction &pa
1579 
1580  switch( pa.eventCode )
1581  case 2: // mouse up
1582  dfref df = $(package_path)
1583  nvar /sdfr=df norm_theta_mode
1584  norm_theta_mode = pa.popNum - 1
1585  break
1586  case -1: // control being killed
1587  break
1588  endswitch
1589 
1590  return 0
1591 End
1592 
1593 static function pmp_norm_thetaphi_mode(pa) : PopupMenuControl
1594  STRUCT WMPopupAction &pa
1595 
1596  switch( pa.eventCode )
1597  case 2: // mouse up
1598  dfref df = $(package_path)
1599  nvar /sdfr=df norm_thetaphi_mode
1600  norm_thetaphi_mode = pa.popNum - 1
1601  break
1602  case -1: // control being killed
1603  break
1604  endswitch
1605 
1606  return 0
1607 End
1608 
1609 static function pmp_graph_mode(pa) : PopupMenuControl
1610  STRUCT WMPopupAction &pa
1611 
1612  switch( pa.eventCode )
1613  case 2: // mouse up
1614  dfref df = $(package_path)
1615  nvar /sdfr=df graph_mode
1616  graph_mode = pa.popNum - 1
1617  break
1618  case -1: // control being killed
1619  break
1620  endswitch
1621 
1622  return 0
1623 End
1624 
1625 static function pmp_graph_projection(pa) : PopupMenuControl
1626  STRUCT WMPopupAction &pa
1627 
1628  switch( pa.eventCode )
1629  case 2: // mouse up
1630  dfref df = $(package_path)
1631  nvar /sdfr=df graph_projection
1632  graph_projection = pa.popNum - 1
1633  break
1634  case -1: // control being killed
1635  break
1636  endswitch
1637 
1638  return 0
1639 End
1640 
1641 static function pmp_graph_colortable(pa) : PopupMenuControl
1642  STRUCT WMPopupAction &pa
1643 
1644  switch( pa.eventCode )
1645  case 2: // mouse up
1646  dfref df = $(package_path)
1647  svar /sdfr=df graph_colortable
1648  graph_colortable = StringFromList(pa.popNum - 1, CTabList())
1650  break
1651  case -1: // control being killed
1652  break
1653  endswitch
1654 
1655  return 0
1656 End
static variable bp_norm_phi_preview(WMButtonAction *ba)
+
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
variable normalize_strip_theta(wave strip, wave theta, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by the average polar distribution.
-
static variable do_init_process(variable check)
initialize the process data with a copy of the raw data.
-
static variable preview_norm_alpha()
-
variable asp_calculate_output()
calculate the output using all enabled processing filters.
-
static variable check_norm_alpha()
-
variable asp_import_raw(wave raw_data)
import raw data
-
variable crop_strip(wave strip, variable xlo, variable xhi)
crop a strip at the sides.
-
variable ad_update_profiles(wave image)
update a profiles graph with new data.
-
static variable bp_save_prefs(WMButtonAction *ba)
-
variable asp_save_output_itx()
save the output diffractogram to an igor text file
-
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 pmp_graph_colortable(WMPopupAction *pa)
-
static variable save_prefs()
save persistent package data to the preferences file.
-
static variable bp_graph_update(WMButtonAction *ba)
-
dfr find_hemi_data(string nickname, string *prefix, string *intwave)
finds the folder, prefix and name of holo waves given their nick name
-
static variable bp_norm_alpha_preview(WMButtonAction *ba)
-
static variable preview_crop_alpha()
-
static variable pmp_norm_alpha_mode(WMPopupAction *pa)
-
static variable init_package()
-
static variable preview_norm_theta()
-
static variable bp_source_update(WMButtonAction *ba)
-
static variable bp_norm_thetaphi_check(WMButtonAction *ba)
-
static variable bp_norm_theta_preview(WMButtonAction *ba)
-
static variable do_crop_alpha(variable check, variable force=defaultValue)
alpha-crop the process data.
+
static variable do_init_process(variable check)
initialize the process data with a copy of the raw data.
+
static variable preview_norm_alpha()
+
variable asp_calculate_output()
calculate the output using all enabled processing filters.
+
static variable check_norm_alpha()
+
variable asp_import_raw(wave raw_data)
import raw data
+
variable crop_strip(wave strip, variable xlo, variable xhi)
crop a strip at the sides.
+
variable ad_update_profiles(wave image)
update a profiles graph with new data.
+
static variable bp_save_prefs(WMButtonAction *ba)
+
static variable preview_crop()
+
variable asp_save_output_itx()
save the output diffractogram to an igor text file
+
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 pmp_graph_colortable(WMPopupAction *pa)
+
static variable save_prefs()
save persistent package data to the preferences file.
+
static variable bp_graph_update(WMButtonAction *ba)
+
dfr find_hemi_data(string nickname, string *prefix, string *intwave)
finds the folder, prefix and name of holo waves given their nick name
+
static variable bp_norm_alpha_preview(WMButtonAction *ba)
+
static const string prefs_objects
semicolon-separated list of persistent variable, string, and wave names
+
static variable pmp_norm_alpha_mode(WMPopupAction *pa)
+
static variable init_package()
+
static variable preview_norm_theta()
+
static variable delete_rows(string rows, wave data, wave theta, wave tilt, wave phi)
delete individual rows from the data strip
+
static variable pmp_norm_theta_domain(WMPopupAction *pa)
+
static variable bp_source_update(WMButtonAction *ba)
+
static variable bp_norm_thetaphi_check(WMButtonAction *ba)
+
static variable bp_norm_theta_preview(WMButtonAction *ba)
static const string package_path
data folder path
-
static variable bp_crop_alpha_preview(WMButtonAction *ba)
-
static variable do_norm_thetaphi(variable check, variable force=defaultValue)
theta,phi-normalize the process data.
-
static variable bp_load_prefs(WMButtonAction *ba)
-
static variable bp_output_etpi(WMButtonAction *ba)
-
variable asp_display_dist_check(variable xdist, variable ydist)
display a graph window of the distribution checks.
-
static variable bp_graph_png(WMButtonAction *ba)
-
static variable pmp_graph_mode(WMPopupAction *pa)
-
static variable preview_norm_phi()
+
static variable bp_crop_preview(WMButtonAction *ba)
+
variable crop_strip_theta(wave strip, variable theta_lo, variable theta_hi, wave theta, wave tilt, wave phi)
crop a strip in theta.
+
static variable do_norm_thetaphi(variable check, variable force=defaultValue)
theta,phi-normalize the process data.
+
static variable bp_load_prefs(WMButtonAction *ba)
+
static variable bp_output_etpi(WMButtonAction *ba)
+
variable asp_display_dist_check(variable xdist, variable ydist)
display a graph window of the distribution checks.
+
static variable bp_graph_png(WMButtonAction *ba)
+
static variable pmp_graph_mode(WMPopupAction *pa)
+
static variable preview_norm_phi()
string pmsco_save_scan(string pathname, string filename, string energy, string theta, string phi, string alpha, string intensity, string sigma, dfref sdfr=defaultValue)
save waves in a PMSCO scan data file.
-
static variable pmp_norm_theta_mode(WMPopupAction *pa)
-
variable interpolate_hemi_scan(string nickname, variable projection=defaultValue)
interpolate a hemispherical scan onto a rectangular grid
-
static variable do_norm_phi(variable check, variable force=defaultValue)
phi-normalize the process data.
-
static variable bp_norm_thetaphi_preview(WMButtonAction *ba)
-
static variable do_norm_theta(variable check, variable force=defaultValue)
theta-normalize the process data.
-
static variable check_norm_phi()
-
static const string prefs_objects
semicolon-separated list of persistent variable, string, and wave names
-
variable asp_show_panel()
create the angle scan processing panel
-
static variable bp_output_calc(WMButtonAction *ba)
-
static variable arrange_controls()
-
static variable bp_norm_theta_check(WMButtonAction *ba)
-
variable save_hemi_scan(string nickname, string pathname, string filename)
save a hemispherical scan to an Igor text file
-
string asp_duplicate_output(string dest_name, variable do_graph=defaultValue)
copy the output data to a new folder
+
static variable pmp_norm_theta_mode(WMPopupAction *pa)
+
variable interpolate_hemi_scan(string nickname, variable projection=defaultValue)
interpolate a hemispherical scan onto a rectangular grid
+
variable normalize_strip_theta_scans(wave strip, wave theta, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip piecewise by a smooth polar distribution.
+
static variable do_norm_phi(variable check, variable force=defaultValue)
phi-normalize the process data.
+
static variable bp_norm_thetaphi_preview(WMButtonAction *ba)
+
static variable do_norm_theta(variable check, variable force=defaultValue)
theta-normalize the process data.
+
static variable check_norm_phi()
+
variable asp_show_panel()
create the angle scan processing panel
+
static variable bp_output_calc(WMButtonAction *ba)
+
static variable arrange_controls()
+
static variable bp_norm_theta_check(WMButtonAction *ba)
+
variable save_hemi_scan(string nickname, string pathname, string filename)
save a hemispherical scan to an Igor text file
+
string asp_duplicate_output(string dest_name, variable do_graph=defaultValue)
copy the output data to a new folder
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).
variable normalize_strip_thetaphi(wave strip, wave theta, wave phi, variable theta_offset=defaultValue, variable smooth_method=defaultValue, variable smooth_factor=defaultValue, variable check=defaultValue)
divide the strip by a smooth polar-azimuthal distribution.
-
const variable kProjStereo
-
static variable update_menus()
update the popup menus to reflect the values of the global variables
-
static variable bp_output_itx(WMButtonAction *ba)
-
variable asp_close_graphs()
close all graphs created by the angle scan panel
-
static variable do_norm_alpha(variable check, variable force=defaultValue)
alpha-normalize the process data.
+
const variable kProjStereo
+
static variable update_menus()
update the popup menus to reflect the values of the global variables
+
static variable bp_output_itx(WMButtonAction *ba)
+
variable asp_close_graphs()
close all graphs created by the angle scan panel
+
static variable do_norm_alpha(variable check, variable force=defaultValue)
alpha-normalize the process data.
string ad_display_profiles(wave image, string filter=defaultValue)
open a new profiles graph window.
-
static variable load_prefs()
load persistent package data from the preferences file.
-
static variable check_norm_theta()
-
variable set_contrast(variable pcmin, variable pcmax, string graphname=defaultValue, string colortable=defaultValue)
set the pseudocolor contrast by percentile.
-
variable asp_display_previews()
display a graph window of the processed data.
-
variable asp_save_output_etpi(variable ekin)
save the output diffractogram to a PMSCO ETPI file
-
static variable bp_output_duplicate(WMButtonAction *ba)
-
static variable bp_norm_alpha_check(WMButtonAction *ba)
-
static variable check_norm_thetaphi()
-
static variable bp_norm_phi_check(WMButtonAction *ba)
-
static variable bp_source_select(WMButtonAction *ba)
-
static variable AfterCompiledHook()
initialize package data once when the procedure is first loaded
-
variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot=defaultValue)
duplicate a hemispherical scan dataset.
-
static variable pmp_norm_thetaphi_mode(WMPopupAction *pa)
-
static variable preview_norm_thetaphi()
-
string asp_display_output(dfref data_df=defaultValue, string data_name=defaultValue)
display the output diffractogram
+
static variable load_prefs()
load persistent package data from the preferences file.
+
static variable check_norm_theta()
+
variable set_contrast(variable pcmin, variable pcmax, string graphname=defaultValue, string colortable=defaultValue)
set the pseudocolor contrast by percentile.
+
variable asp_display_previews()
display a graph window of the processed data.
+
variable asp_save_output_etpi(variable ekin)
save the output diffractogram to a PMSCO ETPI file
+
static variable bp_output_duplicate(WMButtonAction *ba)
+
static variable bp_norm_alpha_check(WMButtonAction *ba)
+
static variable check_norm_thetaphi()
+
static variable bp_norm_phi_check(WMButtonAction *ba)
+
static variable bp_source_select(WMButtonAction *ba)
+
static variable AfterCompiledHook()
initialize package data once when the procedure is first loaded
+
variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot=defaultValue)
duplicate a hemispherical scan dataset.
+
static variable do_crop(variable check, variable force=defaultValue)
crop the process data.
+
static variable pmp_norm_thetaphi_mode(WMPopupAction *pa)
+
static variable preview_norm_thetaphi()
+
string asp_display_output(dfref data_df=defaultValue, string data_name=defaultValue)
display the output diffractogram
static const string package_name
package name is used as data folder name
-
variable asp_update_graph()
update graphs with new color table or contrast
+
variable asp_update_graph()
update graphs with new color table or contrast
interactive processing of angle scanned XPD data.
-
static variable pmp_graph_projection(WMPopupAction *pa)
+
static variable pmp_graph_projection(WMPopupAction *pa)
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.
@@ -168,7 +172,7 @@ $(document).ready(function(){initNavTree('pearl-anglescan-panel_8ipf_source.html
+ +

k-space mapping of 2D angle-energy distribution (scienta image)

+

courtesy of F. Matsui

+
Parameters
+ + +
inwave2D wave, x = kinetic energy (eV), y = polar angle (deg) note: the kinetic energy is with reference to the vacuum level at the sample. if the work functions of the analyser and the sample differ: Ekin,sample = Ekin,analyser + WFanalyser - WFsample where WFanalyser = Ephot - EFermi
+
+
+
Returns
the output wave has the name of the input wave with the suffix "_k".
+ +

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

+ +
+

◆ calc_graph_azi()

@@ -353,7 +392,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
polar angle in degrees
-

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

+

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

@@ -407,7 +446,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
polar angle in degrees
-

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

+

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

@@ -454,7 +493,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
projected radius. the radius is scaled such that grazing emission maps to 2.
-

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

+

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

@@ -519,7 +558,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

calculate the number of phis for a given theta

adapted from XPDplot 8.03

-

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

+

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

@@ -584,7 +623,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

calculate delta-phi for a given theta

adapted from XPDplot 8.03

-

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

+

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

@@ -631,7 +670,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

calculate delta-theta for a given theta

adapted from XPDplot 8.03

-

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

+

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

@@ -684,7 +723,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

calculate the number of thetas for a pattern

adapted from XPDplot 8.03

-

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

+

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

@@ -740,7 +779,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
-

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

+

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

@@ -769,7 +808,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to -

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

+

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

@@ -838,7 +877,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

for the output parameters polar and azi, you need to pass in existing numeric waves. dimension size does not matter, the waves are redimensioned by the function so that they have the same dimensions as the intensity data set. X dimension = analyser scale, Y dimension = manipulator scan.

-

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

+

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

@@ -895,7 +934,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

convert angles from TTPA (theta-tilt-phi-analyser) scheme to polar coordinates.

similar to convert_angles_ttpa2polar() but reads the analyser angles from the X scale of data

-

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

+

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

@@ -943,7 +982,75 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Remarks
cropping should be done after smoothing and normalization operations to reduce artefacts.
-

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

+

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

+ + + + +

◆ crop_strip_theta()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variable crop_strip_theta (wave strip,
variable theta_lo,
variable theta_hi,
wave theta,
wave tilt,
wave phi 
)
+
+ +

crop a strip in theta.

+

the strip is cropped in place, data outside the region of interest is lost.

+
Parameters
+ + + + + + + +
[in,out]strip2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
[in]ylolowest polar angle to keep (will be rounded to nearest existing point)
[in]yhihighest polar angle to keep (will be rounded to nearest existing point)
[in,out]thetapolar angle along the Y dimension of strip. this wave is modified: cropped rows are deleted.
[in,out]tilttilt angle along the Y dimension of strip. this wave is modified: cropped rows are deleted.
[in,out]phiazimuthal angle along the Y dimension of strip. this wave is modified: cropped rows are deleted.
+
+
+ +

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

@@ -1034,7 +1141,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
the name of the graph window
-

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

+

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

@@ -1104,7 +1211,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
the name of the graph window.
Version
1.7 interface change: the trace drawing code is moved to display_hemi_scan, so that this function can be reused by other graph types, e.g. display_scanlines.
-

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

+

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

@@ -1186,7 +1293,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Remarks
this function is extremely slow.
-

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

+

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

@@ -1248,7 +1355,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Warning
EXPERIMENTAL! this function is under development. the interface and behaviour of this function may change significantly in future versions.
-

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

+

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

@@ -1307,7 +1414,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Warning
EXPERIMENTAL! this function is under development. the interface and behaviour of this function may change significantly in future versions.
-

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

+

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

@@ -1366,7 +1473,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to -

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

+

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

@@ -1419,7 +1526,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
reference of the data folder which contains the waves
-

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

+

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

@@ -1443,7 +1550,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

the nick name is either the name of a child folder in the current data folder (PEARL specification), or a prefix of the hemi wave names (XPDplot specification).

Returns
the nick name
-

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

+

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

@@ -1467,7 +1574,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

the prefix is the part of the wave name before the first underscore. the prefix is used by XPDplot where it is identical to the nick name. the prefix is empty in the PEARL specification.

Returns
the prefix
-

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

+

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

@@ -1518,7 +1625,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

add an arbitrary angle scan to a hemispherical scan grid.

the hemi grid must have been created in the current data folder by the make_hemi_grid function. the function determines the bin size at the given polar angle, and adds all data points which fall into a bin. a point which lies exactly on the upper boundary falls into the next bin. this function does not clear previous values before adding new data. values are added to the _tot wave, weights to the _wt wave. the intensity (_i) wave is calculated as _tot / _wt.

-

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

+

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

@@ -1569,7 +1676,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

add an azimuthal scan to a hemispherical scan grid.

the hemi grid must have been created in the current data folder by the make_hemi_grid function. the function determines the bin size at the given polar angle, and calculates the mean values of the data points which fall into a bin. a point which lies exactly on the upper boundary falls into the next bin.

-

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

+

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

@@ -1611,7 +1718,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
reference of the created wave. the wave has the same name as the intensity wave of the dataset with the suffix "_azi" and the azimuthal angle rounded to integer. it is created in the same datafolder as the original data.
-

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

+

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

@@ -1653,7 +1760,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
Returns
reference of the created wave. the wave has the same name as the intensity wave of the dataset with the suffix "_azi" and the azimuthal angle rounded to integer. it is created in the same datafolder as the original data.
-

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

+

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

@@ -1747,7 +1854,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to -

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

+

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

@@ -1797,7 +1904,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to -

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

+

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

@@ -1835,7 +1942,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to
-

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

+

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

@@ -1874,7 +1981,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to

load a hemispherical scan from an Igor text file

Todo:
function not implemented
-

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

+

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

@@ -1926,7 +2033,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to -

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

+

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

@@ -1999,7 +2106,7 @@ data imported with version 1.5 and earlier, must be offset by 180 deg in phi to -

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

+

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

@@ -2170,6 +2277,63 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp

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

+ + + +

◆ normalize_strip_theta_scans()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variable normalize_strip_theta_scans (wave strip,
wave theta,
variable theta_offset = defaultValue,
variable smooth_method = defaultValue,
variable smooth_factor = defaultValue,
variable check = defaultValue 
)
+
+ +

divide the strip piecewise by a smooth polar distribution.

+
Warning
experimental. this function is under development.
+ +

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

+
@@ -2440,7 +2604,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
Attention
if you modify the structure of the data wave, e.g. delete some angles, this function cannot be used because the manipulator settings do not correspond to the original manipulator waves! instead, create your own manipulator waves and use pizza_service_2().
-

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

+

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

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

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

+

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

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

polar graph window hook

this hook converts the cursor positions to polar coordinates and displays them in a text box on the graph. the text box is visible while the cursor info box is visible.

-

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

+

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

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

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

+

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

@@ -2701,7 +2865,7 @@ caution: binomial and boxcar smoothing are not aware of theta. this may give unp
Precondition
manipulator angles as attributes in attr folder next to the data wave
Warning
EXPERIMENTAL
-

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

+

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

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

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

+

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

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

save a hemispherical scan to an Igor text file

-

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

+

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

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

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

+

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

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

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

+

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

@@ -2981,7 +3145,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 861 of file pearl-anglescan-process.ipf.

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

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

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

+

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

@@ -3328,7 +3492,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 2269 of file pearl-anglescan-process.ipf.

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

callback function for new detector state from EPICS.

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

-

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

+

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

@@ -429,7 +429,7 @@ Variables

callback function for new manipulator position from EPICS.

-

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

+

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

@@ -722,7 +722,7 @@ Variables

window hook

disconnects from EPICS when the window is closed.

-

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

+

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

@@ -750,7 +750,7 @@ Variables
-

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

+

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

@@ -777,7 +777,7 @@ Variables
-

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

+

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

@@ -804,7 +804,7 @@ Variables
-

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

+

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

@@ -921,7 +921,7 @@ Variables

export tracker data (with prompt)

-

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

+

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

@@ -1017,7 +1017,7 @@ Variables

import tracker data (with prompt)

-

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

+

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

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

import tracker data from file (with prompt)

-

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

+

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

@@ -1132,7 +1132,7 @@ Variables
-

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

+

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

@@ -1160,7 +1160,7 @@ Variables
-

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

+

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

@@ -1188,7 +1188,7 @@ Variables
-

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

+

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

@@ -1216,7 +1216,7 @@ Variables
-

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

+

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

@@ -1304,7 +1304,7 @@ Variables

save tracker data to file (with prompt)

-

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

+

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

@@ -1414,7 +1414,7 @@ Variables
-

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

+

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

@@ -1441,7 +1441,7 @@ Variables
-

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

+

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

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

Function Documentation

+ +

◆ ad_add_overlay()

+ +
+
+ + + + + + + + + + + + + + + + + + +
wave ad_add_overlay (wave image,
string rgba = defaultValue 
)
+
+ +

add an overlay on top of the displayed image

+

the function creates the overlay wave and returns it as function result. the name of the wave is "view_overlay" and is created in the same folder as the "view_image" wave.

+
Parameters
+ + +
imageimage wave that identifies the profiles window.
+
+
+
Returns
overlay overlay wave. same dimensions and scales as image, but unsigned binary. pixels that are 0 are overlaid with semi-transparent color. other pixels should be 64 (igor's mask convention).
+ +

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

+ +
+

◆ ad_box_filter()

@@ -268,7 +311,7 @@ Functions -

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

+

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

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

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

+

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

@@ -326,7 +369,7 @@ Functions

the function expects further objects as created by ad_display_profiles() in the same data folder as the image wave. the most recent profiles graph of the image must exist, and the cursors A and B must be set on the image.

-

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

+

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

@@ -354,7 +397,7 @@ Functions -

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

+

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

@@ -417,7 +460,7 @@ Functions

the function expects further objects as created by ad_display_profiles() in the same data folder as the image wave.

this function does not require that the graph exists as long as the data folder is complete.

-

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

+

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

@@ -458,7 +501,7 @@ Functions
Returns
the result must be written to the incoming image wave.
-

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

+

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

@@ -517,7 +560,7 @@ Functions
Returns
name of the gizmo window.
-

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

+

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

@@ -618,7 +661,7 @@ Functions
Returns
name of the graph window.
-

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

+

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

@@ -693,7 +736,7 @@ Functions -

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

+

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

@@ -740,7 +783,7 @@ Functions
Returns
0 if successful, non-zero otherwise
-

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

+

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

@@ -780,7 +823,7 @@ Functions -

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

+

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

@@ -825,7 +868,7 @@ Functions -

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

+

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

@@ -847,7 +890,7 @@ Functions

hook function for user events in the profiles window.

-

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

+

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

@@ -912,7 +955,7 @@ Functions -

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

+

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

@@ -959,7 +1002,7 @@ Functions
Returns
0 if successful, non-zero otherwise
-

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

+

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

@@ -980,7 +1023,7 @@ Functions

initialize the slice animation background task.

-

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

+

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

@@ -1010,7 +1053,7 @@ Functions

move a slice by one step (background task).

-

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

+

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

@@ -1063,7 +1106,7 @@ Functions -

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

+

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

@@ -1091,7 +1134,7 @@ Functions -

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

+

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

@@ -1131,7 +1174,7 @@ Functions -

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

+

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

@@ -1159,7 +1202,7 @@ Functions -

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

+

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

@@ -1190,7 +1233,7 @@ Functions

export a slice (button procedure).

extract a slice and saves it in a separate wave.

-

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

+

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

@@ -1220,7 +1263,7 @@ Functions

move slice (button procedure).

-

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

+

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

@@ -1266,7 +1309,7 @@ Functions

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

-

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

+

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

@@ -1294,7 +1337,7 @@ Functions
-

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

+

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

@@ -1325,7 +1368,7 @@ Functions

find the source image wave corresponding to the given view.

Returns
wave reference of the original data wave. the reference may be invalid if the source wave cannot be found.
-

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

+

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

@@ -1362,7 +1405,7 @@ Functions -

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

+

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

@@ -1398,7 +1441,7 @@ Functions -

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

+

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

@@ -1468,7 +1511,7 @@ Functions

create a view data folder.

-

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

+

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

@@ -1496,7 +1539,7 @@ Functions
-

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

+

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

@@ -1524,7 +1567,7 @@ Functions
-

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

+

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

@@ -1554,7 +1597,7 @@ Functions

set slice coordinate (slider procedure).

-

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

+

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

@@ -1584,7 +1627,7 @@ Functions

set slice coordinate (button procedure).

-

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

+

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

@@ -1612,7 +1655,7 @@ Functions
-

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

+

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

@@ -1642,7 +1685,7 @@ Functions

update controls with data scale limits.

current folder must be slicer info

-

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

+

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

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

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

+

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

@@ -340,7 +341,7 @@ Variables
-

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

+

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

@@ -368,7 +369,7 @@ Variables
-

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

+

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

@@ -396,7 +397,7 @@ Variables
-

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

+

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

@@ -424,7 +425,7 @@ Variables
-

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

+

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

@@ -452,7 +453,7 @@ Variables
-

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

+

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

@@ -480,7 +481,7 @@ Variables
-

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

+

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

@@ -508,7 +509,7 @@ Variables
-

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

+

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

@@ -536,7 +537,7 @@ Variables
-

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

+

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

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

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

+

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

@@ -592,7 +593,7 @@ Variables
-

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

+

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

@@ -620,7 +621,7 @@ Variables
-

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

+

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

@@ -648,7 +649,7 @@ Variables
-

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

+

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

@@ -676,7 +677,7 @@ Variables
-

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

+

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

@@ -704,7 +705,7 @@ Variables
-

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

+

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

@@ -742,7 +743,7 @@ Variables
-

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

+

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

@@ -780,7 +781,7 @@ Variables
-

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

+

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

@@ -852,7 +853,7 @@ Variables
-

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

+

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

@@ -880,7 +881,7 @@ Variables
-

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

+

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

@@ -908,7 +909,7 @@ Variables
-

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

+

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

@@ -946,7 +947,7 @@ Variables
-

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

+

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

@@ -984,7 +985,7 @@ Variables
-

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

+

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

@@ -1022,7 +1023,7 @@ Variables
-

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

+

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

@@ -1062,7 +1063,7 @@ Variables

load a matrix (STM) data file

-

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

+

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

@@ -1089,7 +1090,7 @@ Variables
-

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

+

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

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

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

+

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

@@ -1155,7 +1156,7 @@ Variables
-

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

+

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

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

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

+

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

@@ -1263,7 +1264,7 @@ Variables -

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

+

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

@@ -1282,7 +1283,7 @@ Variables
-

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

+

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

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

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

+

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

@@ -1365,7 +1366,7 @@ Variables
-

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

+

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

@@ -1393,7 +1394,7 @@ Variables
-

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

+

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

@@ -1421,7 +1422,7 @@ Variables
-

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

+

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

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

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

+

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

@@ -1500,7 +1501,7 @@ Variables
Returns
wave reference of the preview trace. empty wave reference if the function failed.
-

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

+

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

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

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

+

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

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

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

+

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

@@ -1617,7 +1618,7 @@ Variables
-

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

+

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

@@ -1642,7 +1643,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 1069 of file pearl-data-explorer.ipf.

+

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

@@ -1672,7 +1673,7 @@ Variables
-

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

+

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

@@ -1700,7 +1701,7 @@ Variables
-

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

+

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

@@ -1727,7 +1728,10 @@ Variables
-

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

+

save persistent package data to the preferences file.

+

this function is called when the user clicks the corresponding button. the data saved in the file are: data file path, attributes filter

+ +

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

@@ -1765,7 +1769,7 @@ Variables
-

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

+

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

@@ -1784,7 +1788,7 @@ Variables
-

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

+

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

@@ -1811,7 +1815,7 @@ Variables
-

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

+

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

@@ -1841,7 +1845,7 @@ Variables

read a list of PEARL files from the file system

wtFiles and wSelectedFiles in the package data folder are updated. only files for which pearl_file_type() returns non-zero are listed.

-

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

+

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

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

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

+

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

@@ -434,7 +434,7 @@ Variables

select/deselect all graph windows for attachment

-

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

+

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

@@ -464,7 +464,7 @@ Variables

select top graph window for attachment

-

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

+

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

@@ -494,7 +494,7 @@ Variables

button procedure for the attachment up and down buttons

-

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

+

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

@@ -522,7 +522,7 @@ Variables
-

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

+

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

@@ -550,7 +550,7 @@ Variables
-

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

+

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

@@ -578,7 +578,7 @@ Variables
-

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

+

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

@@ -606,7 +606,7 @@ Variables
-

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

+

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

@@ -636,7 +636,7 @@ Variables

button procedure for the Submit and Reply buttons

-

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

+

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

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

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

+

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

@@ -1263,7 +1263,7 @@ Variables
-

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

+

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

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

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

+

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

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

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

+

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

@@ -1455,7 +1455,7 @@ Variables
Returns
message text
-

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

+

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

@@ -1729,7 +1729,7 @@ Variables

move an attachment item in the list of attachments

-

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

+

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

@@ -1979,7 +1979,7 @@ Variables -

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

+

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

@@ -2026,7 +2026,7 @@ Variables -

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

+

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

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

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

+

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

@@ -2104,7 +2104,7 @@ Variables

update the list of attachments

-

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

+

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

@@ -2177,7 +2177,7 @@ Variables
-

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

+

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

@@ -2201,7 +2201,7 @@ Variables
-

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

+

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

@@ -2225,7 +2225,7 @@ Variables
-

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

+

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

@@ -2379,7 +2379,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.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 strconstant package_name = "pearl_elog"
86 static strconstant package_path = "root:packages:pearl_elog:"
87 
97 function pearl_elog(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 end
125 
127 static function IgorBeforeNewHook(igorApplicationNameStr)
128  string igorApplicationNameStr
129  save_prefs()
131  return 0
132 end
133 
135 static function IgorQuitHook(igorApplicationNameStr)
136  string igorApplicationNameStr
137  save_prefs()
139  return 0
140 end
141 
143 static function AfterFileOpenHook(refNum,file,pathName,type,creator,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 end
152 
153 static constant kdfRoot = 0
154 static constant kdfVolatile = 1
155 static constant kdfPersistent = 2
156 static constant kdfTemplates = 3
157 
170 static function /df get_elog_df(name, 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 end
207 
217 static function init_package([clean])
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 end
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 end
331 
340 static function 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 end
387 
401 
414 function elog_create_logbook(name, [template])
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 end
470 
473 function elog_config([elog_path, hostname, port, subdir])
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 end
498 
513 function elog_login(logbook, username, 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 end
524 
533 function elog_logout(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 end
559 
564 static function 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 end
580 
584 static function 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 end
608 
618 static function /s list_logbooks([templates])
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 end
645 
653 function elog_validate_attributes(logbook, 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 end
661 
685 function elog_create_entry(logbook, attributes, message, [encoding, graphs, replyto])
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 end
784 
792 function elog_add_attachment(logbook, id, 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 end
845 
853 static function /s prepare_command_line(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 end
896 
902 static function /s format_url(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 end
929 
939 static function /s prepare_graph_attachments(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 end
957 
958 static function /s get_timestamp(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 end
965 
982 static function /s create_message_file(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 end
1003 
1023 static function /s create_graph_file(graphname, 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 end
1050 
1059 static function /s create_cmd_file(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 end
1094 
1095 static function /s 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 end
1106 
1115 static function 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 end
1132 
1133 static strconstant elog_success_msg = "Message successfully transmitted"
1134 static strconstant elog_parse_id = "ID=%u"
1135 
1141 static function 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 end
1181 
1184 function /s elog_prompt_logbook()
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 end
1211 
1214 function elog_prompt_login(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 end
1233 
1241 function /s PearlElogPanel(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 end
1393 
1394 static function elog_panel_hook(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 end
1427 
1428 static constant kAttachColSel = 0
1429 static constant kAttachColTitle = 1
1430 static constant kAttachColName = 2
1431 
1433 static function update_attach_items(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 end
1492 
1494 static function move_attach_item(logbook, item, 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 end
1516 
1518 static function bp_attach_updown(ba) : ButtonControl
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 end
1548 
1550 static function bp_submit(ba) : ButtonControl
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 end
1595 
1597 static function bp_attach_top(ba) : ButtonControl
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 end
1611 
1613 static function bp_attach_allnone(ba) : ButtonControl
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 end
1633 
1634 static function bp_attach(ba) : ButtonControl
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 end
1666 
1667 static function bp_save_graphs(ba) : ButtonControl
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 end
1694 
1695 static function bp_clear(ba) : ButtonControl
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 end
1710 
1711 static function bp_login(ba) : ButtonControl
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 end
1728 
1729 static function bp_logout(ba) : ButtonControl
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 end
1745 
1746 static function /s get_default_panel_name()
1747  string windowname
1748  windowname = StringFromList(0, WinList("*ElogPanel*", ";", "WIN:64"), ";")
1749  return windowname
1750 end
1751 
1759 static function /s get_panel_attributes(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 end
1794 
1806 static function /s set_panel_attributes(windowname, attributes, [clear])
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 end
1860 
1868 static function /s get_panel_message(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 end
1884 
1894 static function /s set_panel_message(windowname, 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 end
1907 
1914 static function /s get_panel_graphs(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 end
1947 
1954 static function /s set_panel_graphs(windowname, 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 end
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 strconstant package_name = "pearl_elog"
86 static strconstant package_path = "root:packages:pearl_elog:"
87 
97 function pearl_elog(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 end
125 
127 static function IgorBeforeNewHook(igorApplicationNameStr)
128  string igorApplicationNameStr
129  save_prefs()
131  return 0
132 end
133 
135 static function IgorQuitHook(igorApplicationNameStr)
136  string igorApplicationNameStr
137  save_prefs()
139  return 0
140 end
141 
143 static function AfterFileOpenHook(refNum,file,pathName,type,creator,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 end
152 
153 static constant kdfRoot = 0
154 static constant kdfVolatile = 1
155 static constant kdfPersistent = 2
156 static constant kdfTemplates = 3
157 
170 static function /df get_elog_df(name, 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 end
207 
217 static function init_package([clean])
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 end
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;p-group;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_pgroup;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;p-group;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;p-group;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_pgroup;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;Other"
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 end
331 
340 static function 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 end
387 
401 
414 function elog_create_logbook(name, [template])
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 end
470 
473 function elog_config([elog_path, hostname, port, subdir])
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 end
498 
513 function elog_login(logbook, username, 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 end
524 
533 function elog_logout(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 end
559 
564 static function 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 end
580 
584 static function 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 end
608 
618 static function /s list_logbooks([templates])
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 end
645 
653 function elog_validate_attributes(logbook, 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 end
661 
685 function elog_create_entry(logbook, attributes, message, [encoding, graphs, replyto])
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 end
784 
792 function elog_add_attachment(logbook, id, 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 end
845 
853 static function /s prepare_command_line(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 end
896 
902 static function /s format_url(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 end
929 
939 static function /s prepare_graph_attachments(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 end
957 
958 static function /s get_timestamp(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 end
965 
982 static function /s create_message_file(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 end
1003 
1023 static function /s create_graph_file(graphname, 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 end
1050 
1059 static function /s create_cmd_file(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 end
1094 
1095 static function /s 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 end
1106 
1115 static function 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 end
1132 
1133 static strconstant elog_success_msg = "Message successfully transmitted"
1134 static strconstant elog_parse_id = "ID=%u"
1135 
1141 static function 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 end
1181 
1184 function /s elog_prompt_logbook()
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 end
1211 
1214 function elog_prompt_login(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 end
1233 
1241 function /s PearlElogPanel(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  ypos = max(ypos, 80)
1302 
1303  TitleBox t_attach, win=$win_name, pos={308,5}, size={70,14}, title="Attachments", frame=0
1304  height = ypos - 21 - 4
1305  ListBox lb_attach, win=$win_name, pos={308,21}, size={264,height}
1306  ListBox lb_attach, win=$win_name, listWave=attach_list
1307  ListBox lb_attach, win=$win_name, mode=1, selWave=attach_sel, selRow=-1
1308  ListBox lb_attach, win=$win_name, widths={20,160,80}
1309  ListBox lb_attach, win=$win_name, help={"Choose graphs to attach to the message."}
1310 
1311  Button b_attach_top, win=$win_name, pos={420,2}, size={40,18}, title="top"
1312  Button b_attach_top, win=$win_name, fcolor=(56576,60928,47872)
1313  Button b_attach_top, win=$win_name, proc=PearlElog#bp_attach_top
1314  Button b_attach_top, win=$win_name, help={"Select top graph for attachment."}
1315  Button b_attach_all, win=$win_name, pos={460,2}, size={40,18}, title="all"
1316  Button b_attach_all, win=$win_name, fcolor=(56576,60928,47872)
1317  Button b_attach_all, win=$win_name, proc=PearlElog#bp_attach_allnone
1318  Button b_attach_all, win=$win_name, help={"Select all graphs for attachment."}
1319  Button b_attach_none, win=$win_name, pos={500,2}, size={40,18}, title="none"
1320  Button b_attach_none, win=$win_name, fcolor=(56576,60928,47872)
1321  Button b_attach_none, win=$win_name, proc=PearlElog#bp_attach_allnone
1322  Button b_attach_none, win=$win_name, help={"Deselect all attachments."}
1323  Button b_save_graphs, win=$win_name, pos={540,2}, size={40,18}, title="save"
1324  Button b_save_graphs, win=$win_name, fcolor=(56576,60928,47872)
1325  Button b_save_graphs, win=$win_name, proc=PearlElog#bp_save_graphs
1326  Button b_save_graphs, win=$win_name, help={"Save selected graphs as PNG bitmap files."}
1327  Button b_attach_up, win=$win_name, pos={576,20}, size={20,20}, title="\\W517"
1328  Button b_attach_up, win=$win_name, fcolor=(56576,60928,47872)
1329  Button b_attach_up, win=$win_name, proc=PearlElog#bp_attach_updown
1330  Button b_attach_up, win=$win_name, help={"Move selected graph up."}
1331  Button b_attach_dw, win=$win_name, pos={576,40}, size={20,20}, title="\\W523"
1332  Button b_attach_dw, win=$win_name, fcolor=(56576,60928,47872)
1333  Button b_attach_dw, win=$win_name, proc=PearlElog#bp_attach_updown
1334  Button b_attach_dw, win=$win_name, help={"Move selected graph down."}
1335 
1336  ypos += 246-160
1337  Button b_submit,win=$win_name, pos={70,ypos},size={46,20},proc=PearlElog#bp_submit,title="Submit"
1338  Button b_submit,win=$win_name, help={"Submit form data to ELOG (new entry)."}
1339  Button b_submit,win=$win_name, fcolor=(56576,60928,47872)
1340  Button b_clear,win=$win_name, pos={120,ypos},size={46,20},proc=PearlElog#bp_clear,title="Clear"
1341  Button b_clear,win=$win_name, help={"Clear the form fields"}
1342  Button b_clear,win=$win_name, fcolor=(56576,60928,47872)
1343 
1344  ypos += 272-246
1345  variable_path = volatile_path + "msg_id"
1346  SetVariable sv_id,win=$win_name, pos={51,ypos},size={119,16},bodyWidth=77
1347  SetVariable sv_id,win=$win_name, title="ID",value=$variable_path
1348  SetVariable sv_id,win=$win_name, help={"ID of last submitted message, or message to attach or reply to."}
1349 
1350  TitleBox t_host, win=$win_name, pos={170,ypos+4}, size={112.00,14.00}, frame=0
1351  TitleBox t_host, win=$win_name, variable=url
1352 
1353  ypos += 270-272
1354  Button b_attach,win=$win_name, pos={170,ypos},size={48,20},proc=PearlElog#bp_attach,title="Attach"
1355  Button b_attach,win=$win_name, help={"Attach the selected graph to an existing ELOG entry (correct ID required)."}
1356  Button b_attach,win=$win_name, fcolor=(56576,60928,47872)
1357  Button b_reply,win=$win_name, pos={220,ypos},size={48,20},proc=PearlElog#bp_submit,title="Reply"
1358  Button b_reply,win=$win_name, help={"Submit form data to ELOG as a reply to an existing message (correct ID required)."}
1359  Button b_reply,win=$win_name, fcolor=(56576,60928,47872)
1360  Button b_login,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_login,title="Login"
1361  Button b_login,win=$win_name, help={"Enter user name and password."}
1362  Button b_login,win=$win_name, fcolor=(56576,60928,47872)
1363  Button b_logout,win=$win_name, pos={550,ypos},size={46,20},proc=PearlElog#bp_logout,title="Logout"
1364  Button b_logout,win=$win_name, help={"Clear user name and password."}
1365  Button b_logout,win=$win_name, fcolor=(56576,60928,47872), disable=3
1366 
1367  SetWindow $win_name, hook(elogPanelHook)=PearlElog#elog_panel_hook
1368  SetWindow $win_name, userdata(logbook)=logbook
1369 
1370  ypos += 160-270
1371  TitleBox t_message,win=$win_name, pos={10,ypos},size={58,16},fixedSize=1,frame=0,anchor=RT,title="Message"
1372  DefineGuide UGH0={FT,ypos},UGV0={FL,70},UGH1={FB,-52},UGV1={FR,-2}
1373  NewNotebook /F=0 /N=Message /OPTS=3 /W=(115,404,345,341)/FG=(UGV0,UGH0,UGV1,UGH1) /HOST=#
1374  Notebook kwTopWin, defaultTab=20, statusWidth=0, autoSave=0
1375  Notebook kwTopWin fSize=10, fStyle=0, textRGB=(0,0,0)
1376  RenameWindow #,Message
1377  string nb_name = win_name + "#Message"
1378  SetActiveSubwindow ##
1379 
1380  // restore recently used attributes and message
1381  svar /z /sdfr=df_persistent recent
1382  if (svar_exists(recent) && (strlen(recent) > 0))
1383  set_panel_attributes(win_name, recent)
1384  endif
1385  svar /z /sdfr=df_persistent recent_message
1386  if (svar_exists(recent_message) && (strlen(recent_message) > 0))
1387  set_panel_message(win_name, recent_message)
1388  endif
1389  Notebook $nb_name selection={startOfFile,startOfFile}, findText={"",1}
1390 
1391  setdatafolder savedf
1392  return win_name
1393 end
1394 
1395 static function elog_panel_hook(s)
1396  STRUCT WMWinHookStruct &s
1397 
1398  Variable hookResult = 0
1399 
1400  switch(s.eventCode)
1401  case 0: // activate
1402  string logbook = GetUserData(s.winName, "", "logbook")
1403  if (strlen(logbook) > 0)
1404  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1405  svar /sdfr=df_volatile url
1406  url = format_url(logbook)
1407  update_attach_items(logbook)
1408  endif
1409  break
1410  case 6: // resize
1411  // move bottom-aligned controls when the window is resized
1412  variable b_top = s.winRect.bottom + 4
1413  Button b_submit,pos={70,b_top}
1414  Button b_clear,pos={120,b_top}
1415  TitleBox t_host, pos={170,b_top+4}
1416  b_top += 24
1417  Button b_attach,pos={170,b_top}
1418  Button b_reply,pos={220,b_top}
1419  Button b_login, pos={550,b_top}
1420  Button b_logout, pos={550,b_top}
1421  b_top += 2
1422  SetVariable sv_id,pos={51,b_top}
1423  break
1424  endswitch
1425 
1426  return hookResult // 0 if nothing done, else 1
1427 end
1428 
1429 static constant kAttachColSel = 0
1430 static constant kAttachColTitle = 1
1431 static constant kAttachColName = 2
1432 
1434 static function update_attach_items(logbook)
1435  string logbook
1436 
1437  dfref savedf = getdatafolderdfr()
1438  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1439  wave /t /sdfr=df_volatile attach_list
1440  wave /sdfr=df_volatile attach_sel
1441 
1442  if (!waveexists(attach_list))
1443  return -1
1444  endif
1445  string names = WinList("*", ";", "WIN:1;VISIBLE:1")
1446  names = SortList(names, ";", 16)
1447 
1448  // remove closed graphs
1449  variable i
1450  variable k
1451  variable n = DimSize(attach_list, 0)
1452  string s
1453  for (i = n-1; i >= 0; i -= 1)
1454  s = attach_list[i][kAttachColName]
1455  if (WhichListItem(s, names) < 0)
1456  DeletePoints /M=0 i, 1, attach_list, attach_sel
1457  endif
1458  endfor
1459 
1460  // add new graphs
1461  n = ItemsInList(names)
1462  for (i = 0; i < n; i += 1)
1463  s = StringFromList(i, names)
1464  FindValue /text=s /txop=4 /z attach_list
1465  if (v_value < 0)
1466  k = DimSize(attach_list, 0)
1467  Redimension /n=(k+1,3) attach_list, attach_sel
1468  //InsertPoints /M=0 k, 1, attach_list, attach_sel
1469  attach_list[k][kAttachColSel] = ""
1470  attach_list[k][kAttachColTitle] = ""
1471  attach_list[k][kAttachColName] = s
1472  attach_sel[k][kAttachColSel] = 32
1473  attach_sel[k][kAttachColTitle] = 0
1474  attach_sel[k][kAttachColName] = 0
1475  endif
1476  endfor
1477 
1478  // update titles
1479  n = DimSize(attach_list, 0)
1480  for (i = n-1; i >= 0; i -= 1)
1481  s = attach_list[i][kAttachColName]
1482  getwindow /z $s, wtitle
1483  if (v_flag == 0)
1484  attach_list[i][kAttachColTitle] = s_value
1485  else
1486  attach_list[i][kAttachColTitle] = s
1487  endif
1488  endfor
1489 
1490  setdatafolder savedf
1491  return 0
1492 end
1493 
1495 static function move_attach_item(logbook, item, distance)
1496  string logbook
1497  variable item
1498  variable distance
1499 
1500  dfref savedf = getdatafolderdfr()
1501  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1502  wave /t /sdfr=df_volatile attach_list
1503  wave /sdfr=df_volatile attach_sel
1504  variable n = DimSize(attach_list, 0)
1505  variable dest = item + distance
1506 
1507  if ((item >= 0) && (item < n) && (dest >= 0) && (dest < n))
1508  string name = attach_list[item][kAttachColName]
1509  variable sel = attach_sel[item][kAttachColSel]
1510  DeletePoints /M=0 item, 1, attach_list, attach_sel
1511  InsertPoints /M=0 dest, 1, attach_list, attach_sel
1512  attach_list[dest][kAttachColName] = name
1513  update_attach_items(logbook)
1514  attach_sel[dest][kAttachColSel] = sel
1515  endif
1516 end
1517 
1519 static function bp_attach_updown(ba) : ButtonControl
1520  STRUCT WMButtonAction &ba
1521 
1522  switch( ba.eventCode )
1523  case 2: // mouse up
1524  string logbook = GetUserData(ba.win, "", "logbook")
1525  ControlInfo /w=$ba.win lb_attach
1526  variable row = v_value
1527  dfref df = $s_datafolder
1528  wave /t /sdfr=df attach_list = $s_value
1529  if (cmpstr(ba.ctrlName, "b_attach_up") == 0)
1530  // up button
1531  if (row >= 1)
1532  move_attach_item(logbook, row, -1)
1533  ListBox lb_attach, win=$ba.win, selRow=(row-1)
1534  endif
1535  else
1536  // down button
1537  if (row < DimSize(attach_list, 0) - 1)
1538  move_attach_item(logbook, row, +1)
1539  ListBox lb_attach, win=$ba.win, selRow=(row+1)
1540  endif
1541  endif
1542  break
1543  case -1: // control being killed
1544  break
1545  endswitch
1546 
1547  return 0
1548 end
1549 
1551 static function bp_submit(ba) : ButtonControl
1552  STRUCT WMButtonAction &ba
1553 
1554  switch( ba.eventCode )
1555  case 2: // mouse up
1556  string logbook = GetUserData(ba.win, "", "logbook")
1557  string attributes
1558  string message
1559  string graphs
1560  attributes = get_panel_attributes(ba.win)
1561  message = get_panel_message(ba.win)
1562  graphs = get_panel_graphs(ba.win)
1563 
1564  variable id
1565  if (cmpstr(ba.ctrlName, "b_reply") == 0)
1566  // Reply button
1567  ControlInfo /w=$ba.win sv_id
1568  id = v_value
1569  else
1570  // Submit button
1571  id = 0
1572  endif
1573 
1574  if ((elog_validate_attributes(logbook, attributes) == 0) && (strlen(message) > 0))
1575  variable result
1576  result = elog_create_entry(logbook, attributes, message, graphs=graphs, replyto=id)
1577  if (result == 0)
1578  dfref df = get_elog_df(logbook, kdfPersistent)
1579  svar /sdfr=df recent
1580  recent = attributes
1581  svar /sdfr=df recent_message
1582  recent_message = message
1583  else
1584  abort "Submission failed. Error code " + num2str(result) + "."
1585  endif
1586  else
1587  abort "Submission failed due to missing/invalid attribute."
1588  endif
1589  break
1590  case -1: // control being killed
1591  break
1592  endswitch
1593 
1594  return 0
1595 end
1596 
1598 static function bp_attach_top(ba) : ButtonControl
1599  STRUCT WMButtonAction &ba
1600 
1601  switch( ba.eventCode )
1602  case 2: // mouse up
1603  string graphs = WinName(0, 1, 1)
1604  set_panel_graphs(ba.win, graphs)
1605  break
1606  case -1: // control being killed
1607  break
1608  endswitch
1609 
1610  return 0
1611 end
1612 
1614 static function bp_attach_allnone(ba) : ButtonControl
1615  STRUCT WMButtonAction &ba
1616 
1617  switch( ba.eventCode )
1618  case 2: // mouse up
1619  string logbook = GetUserData(ba.win, "", "logbook")
1620  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1621  wave /sdfr=df_volatile attach_sel
1622  if (cmpstr(ba.ctrlName, "b_attach_all") == 0)
1623  attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] | 16
1624  else
1625  attach_sel[][kAttachColSel] = attach_sel[p][kAttachColSel] & ~16
1626  endif
1627  break
1628  case -1: // control being killed
1629  break
1630  endswitch
1631 
1632  return 0
1633 end
1634 
1635 static function bp_attach(ba) : ButtonControl
1636  STRUCT WMButtonAction &ba
1637 
1638  switch( ba.eventCode )
1639  case 2: // mouse up
1640  string logbook = GetUserData(ba.win, "", "logbook")
1641  string graphs
1642  graphs = get_panel_graphs(ba.win)
1643 
1644  variable id
1645  ControlInfo /w=$ba.win sv_id
1646  id = v_value
1647 
1648  // TODO : is there a way around this restriction?
1649  DoAlert /T="ELOG" 1, "This operation will replace all existing attachments. Do you want to continue?"
1650 
1651  if ((id > 0) && (v_flag == 1))
1652  variable result
1653  result = elog_add_attachment(logbook, id, graphs)
1654  if (result != 0)
1655  abort "Submission failed. Error code " + num2str(result) + "."
1656  endif
1657  else
1658  abort "Submission failed due to missing/invalid attribute."
1659  endif
1660  break
1661  case -1: // control being killed
1662  break
1663  endswitch
1664 
1665  return 0
1666 end
1667 
1668 static function bp_save_graphs(ba) : ButtonControl
1669  STRUCT WMButtonAction &ba
1670 
1671  switch( ba.eventCode )
1672  case 2: // mouse up
1673  string logbook = GetUserData(ba.win, "", "logbook")
1674  string graphs = get_panel_graphs(ba.win)
1675  variable ngraphs = ItemsInList(graphs, ";")
1676 
1677  variable igraph
1678  string sgraph
1679  string graph_path
1680  for (igraph = 0; igraph < ngraphs; igraph += 1)
1681  sgraph = StringFromList(igraph, graphs, ";")
1682  graph_path = create_graph_file(sgraph, igraph)
1683  if (strlen(graph_path) > 0)
1684  print graph_path
1685  endif
1686  endfor
1687 
1688  break
1689  case -1: // control being killed
1690  break
1691  endswitch
1692 
1693  return 0
1694 end
1695 
1696 static function bp_clear(ba) : ButtonControl
1697  STRUCT WMButtonAction &ba
1698 
1699  switch( ba.eventCode )
1700  case 2: // mouse up
1701  set_panel_attributes(ba.win, "", clear=1)
1702  set_panel_message(ba.win, "")
1703  set_panel_graphs(ba.win, "")
1704  break
1705  case -1: // control being killed
1706  break
1707  endswitch
1708 
1709  return 0
1710 end
1711 
1712 static function bp_login(ba) : ButtonControl
1713  STRUCT WMButtonAction &ba
1714 
1715  switch( ba.eventCode )
1716  case 2: // mouse up
1717  string logbook = GetUserData(ba.win, "", "logbook")
1718  if (elog_prompt_login(logbook) == 0)
1719  Button b_login, win=$ba.win, disable=3
1720  Button b_logout, win=$ba.win, disable=0
1721  endif
1722  break
1723  case -1: // control being killed
1724  break
1725  endswitch
1726 
1727  return 0
1728 end
1729 
1730 static function bp_logout(ba) : ButtonControl
1731  STRUCT WMButtonAction &ba
1732 
1733  switch( ba.eventCode )
1734  case 2: // mouse up
1735  string logbook = GetUserData(ba.win, "", "logbook")
1736  elog_logout(logbook)
1737  Button b_login, win=$ba.win, disable=0
1738  Button b_logout, win=$ba.win, disable=3
1739  break
1740  case -1: // control being killed
1741  break
1742  endswitch
1743 
1744  return 0
1745 end
1746 
1747 static function /s get_default_panel_name()
1748  string windowname
1749  windowname = StringFromList(0, WinList("*ElogPanel*", ";", "WIN:64"), ";")
1750  return windowname
1751 end
1752 
1760 static function /s get_panel_attributes(windowname)
1761  string windowname
1762 
1763  if (strlen(windowname) == 0)
1764  windowname = get_default_panel_name()
1765  endif
1766  if (strlen(windowname) == 0)
1767  return ""
1768  endif
1769 
1770  string controls = ControlNameList(windowname, ";")
1771  string attributes = ""
1772  string control
1773  string attribute
1774  variable ico
1775  variable nco = ItemsInList(controls, ";")
1776  for (ico = 0; ico < nco; ico += 1)
1777  control = StringFromList(ico, controls, ";")
1778  attribute = GetUserData(windowname, control, "attribute")
1779  if (strlen(attribute) > 0)
1780  ControlInfo /w=$windowname $control
1781  switch(v_flag)
1782  case 2: // checkbox
1783  attributes = ReplaceNumberByKey(attribute, attributes, v_value, "=", ";")
1784  break
1785  case 3: // popupmenu
1786  case 5: // setvariable
1787  attributes = ReplaceStringByKey(attribute, attributes, s_value, "=", ";")
1788  break
1789  endswitch
1790  endif
1791  endfor
1792 
1793  return attributes
1794 end
1795 
1807 static function /s set_panel_attributes(windowname, attributes, [clear])
1808  string windowname
1809  string attributes
1810  variable clear
1811 
1812  if (strlen(windowname) == 0)
1813  windowname = get_default_panel_name()
1814  endif
1815  if (strlen(windowname) == 0)
1816  return ""
1817  endif
1818  if (ParamIsDefault(clear))
1819  clear = 0
1820  endif
1821 
1822  string path
1823 
1824  string logbook = GetUserData(windowname, "", "logbook")
1825  dfref df_persistent = get_elog_df(logbook, kdfPersistent)
1826  string persistent_path = GetDataFolder(1, df_persistent)
1827  svar /sdfr=df_persistent options
1828  string options_path
1829 
1830  string controls = ControlNameList(windowname, ";")
1831  string control
1832  string attribute
1833  string value
1834  variable numval
1835  variable ico
1836  variable nco = ItemsInList(controls, ";")
1837  for (ico = 0; ico < nco; ico += 1)
1838  control = StringFromList(ico, controls, ";")
1839  attribute = GetUserData(windowname, control, "attribute")
1840  if (strlen(attribute))
1841  value = StringByKey(attribute, attributes, "=", ";")
1842  if (strlen(value) || clear)
1843  ControlInfo /w=$windowname $control
1844  switch(v_flag)
1845  case 2: // checkbox
1846  numval = NumberByKey(attribute, attributes, "=", ";")
1847  if ((numtype(numval) != 0) && clear)
1848  numval = 0
1849  endif
1850  if (numtype(numval) == 0)
1851  CheckBox $control, value=numval, win=$windowname
1852  endif
1853  break
1854  case 3: // popupmenu
1855  options_path = persistent_path + StringByKey(attribute, options, "=", ";")
1856  svar values = $options_path
1857  numval = WhichListItem(value, values, ";") + 1
1858  if (numval >= 1)
1859  PopupMenu $control, mode=numval, win=$windowname
1860  endif
1861  break
1862  case 5: // setvariable
1863  SetVariable /z $control, value= _STR:value, win=$windowname
1864  break
1865  endswitch
1866  endif
1867  endif
1868  endfor
1869 
1870  return attributes
1871 end
1872 
1880 static function /s get_panel_message(windowname)
1881  string windowname
1882 
1883  if (strlen(windowname) == 0)
1884  windowname = get_default_panel_name()
1885  endif
1886  if (strlen(windowname) == 0)
1887  return ""
1888  endif
1889 
1890  string nb = windowname + "#Message"
1891  notebook $nb selection={startOfFile, endOfFile}
1892  getselection notebook, $nb, 2
1893 
1894  return s_selection
1895 end
1896 
1906 static function /s set_panel_message(windowname, message)
1907  string windowname
1908  string message
1909 
1910  if (strlen(windowname) == 0)
1911  windowname = get_default_panel_name()
1912  endif
1913 
1914  string nb = windowname + "#Message"
1915  notebook $nb selection={startOfFile, endOfFile},text=message
1916 
1917  return message
1918 end
1919 
1926 static function /s get_panel_graphs(windowname)
1927  string windowname // panel window name
1928 
1929  dfref savedf = getdatafolderdfr()
1930  if (strlen(windowname) == 0)
1931  windowname = get_default_panel_name()
1932  endif
1933  if (strlen(windowname) == 0)
1934  return ""
1935  endif
1936 
1937  string logbook = GetUserData(windowname, "", "logbook")
1938  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1939  wave /t /sdfr=df_volatile attach_list
1940  wave /sdfr=df_volatile attach_sel
1941  string graphs = ""
1942  string windows = ""
1943  string graphname
1944 
1945  variable n = DimSize(attach_sel, 0)
1946  variable i
1947  for (i = 0; i < n; i += 1)
1948  if (attach_sel[i][kAttachColSel] & 16)
1949  graphname = attach_list[i][kAttachColName]
1950  windows = WinList(graphname, ";", "WIN:1")
1951  if (ItemsInList(windows) == 1)
1952  graphs = AddListItem(graphname, graphs, ";", inf)
1953  endif
1954  endif
1955  endfor
1956 
1957  return graphs
1958 end
1959 
1966 static function /s set_panel_graphs(windowname, graphs)
1967  string windowname
1968  string graphs
1969 
1970  if (strlen(windowname) == 0)
1971  windowname = get_default_panel_name()
1972  endif
1973  if (strlen(windowname) == 0)
1974  return ""
1975  endif
1976 
1977  string logbook = GetUserData(windowname, "", "logbook")
1978  update_attach_items(logbook)
1979  dfref df_volatile = get_elog_df(logbook, kdfVolatile)
1980  wave /t /sdfr=df_volatile attach_list
1981  wave /sdfr=df_volatile attach_sel
1982 
1983  variable n = DimSize(attach_sel, 0)
1984  variable i
1985  string graphname
1986  for (i = 0; i < n; i += 1)
1987  graphname = attach_list[i][kAttachColName]
1988  if (WhichListItem(graphname, graphs)>= 0)
1989  attach_sel[i][kAttachColSel] = 48
1990  else
1991  attach_sel[i][kAttachColSel] = 32
1992  endif
1993  endfor
1994 end
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: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 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)
save a graph to a temporary graphics file
-
static const variable kAttachColName
-
static variable bp_clear(WMButtonAction *ba)
+
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
+
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: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)
+
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: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 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 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
@@ -136,11 +136,11 @@ $(document).ready(function(){initNavTree('pearl-elog_8ipf_source.html','');});
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
+
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 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
@@ -153,7 +153,7 @@ $(document).ready(function(){initNavTree('pearl-elog_8ipf_source.html','');}); + +

◆ ShirleyBG()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
variable ShirleyBG (wave w,
wave bg,
variable p1,
variable p2 
)
+
+ +

calculate the shirley background

+ +

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

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

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

+

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

@@ -184,7 +193,7 @@ Functions
-

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

+

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

@@ -203,7 +212,7 @@ Functions
-

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

+

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

@@ -222,7 +231,7 @@ Functions
-

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

+

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

@@ -252,7 +261,63 @@ Functions
-

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

+

display the angle scan tracker window

+
Parameters
+ + + +
epicsnamebase name of the detector, e.g. X03DA-SCIENTA: image1: and cam1: are appended by the function. see ad_connect().
wbRGBwindow background color, e.g. "(32768,49152,55296)"
+
+
+ +

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

+ +
+ + +

◆ PearlCameraDisplay()

+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
variable PearlCameraDisplay (string epicsname,
string nickname,
string wbRGB 
)
+
+ +

area detector surveillance camera display

+

display an area detector channel in a simple image window without any interactive controls.

+
Parameters
+ + + + +
epicsnamebase name of the detector, e.g. X03DA-SCIENTA: image1: and cam1: are appended by the function. see ad_connect().
nicknamenick name under which this detector is referred to in Igor. must be a valid name for a data folder. see ad_connect().
wbRGBwindow background color, e.g. "(32768,49152,55296)"
+
+
+ +

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

@@ -288,7 +353,18 @@ Functions
-

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

+

area detector live display

+

display an area detector channel in an ad_display_profiles() window.

+
Parameters
+ + + + +
epicsnamebase name of the detector, e.g. X03DA-SCIENTA: image1: and cam1: are appended by the function. see ad_connect().
nicknamenick name under which this detector is referred to in Igor. must be a valid name for a data folder. see ad_connect().
wbRGBwindow background color, e.g. "(32768,49152,55296)"
+
+
+ +

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

@@ -308,7 +384,39 @@ Functions
-

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

+

check whether a function name exists

+

return a prefix which disables the menu item if the function does not exist

+ +

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

+ +
+ + +

◆ PearlSampleTracker()

+ +
+
+ + + + + + + + +
variable PearlSampleTracker (variable action)
+
+ +

display the sample tracker window

+
Parameters
+ + + +
epicsnamebase name of the detector, e.g. X03DA-SCIENTA: image1: and cam1: are appended by the function. see ad_connect().
wbRGBwindow background color, e.g. "(32768,49152,55296)"
+
+
+ +

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

@@ -318,7 +426,7 @@ Functions
-Go to the documentation of this file.
1 #pragma rtGlobals=1 // Use modern global access method.
2 #pragma ModuleName = PearlMenu
3 #pragma version = 1.02
4 
5 // main menu for PEARL data acquisition and analysis packages
6 
7 // $Id$
8 // author: matthias.muntwiler@psi.ch
9 // Copyright (c) 2013-14 Paul Scherrer Institut
10 
11 // Licensed under the Apache License, Version 2.0 (the "License");
12 // you may not use this file except in compliance with the License.
13 // You may obtain a copy of the License at
14 // http://www.apache.org/licenses/LICENSE-2.0
15 
16 menu "PEARL"
17 
18  submenu "Data Files"
19  PearlMenuEnableFunc("pearl_data_explorer") + "Data Explorer", /Q, pearl_data_explorer()
20  help = {"Data explorer panel with file import and preview", "Requires ARPES package and HDF5 XOP"}
21  PearlMenuEnableFunc("ad_load_dialog") + "AD HDF5", /Q, ad_load_dialog("")
22  help = {"Import area detector HDF5 data file", "Requires ARPES package and HDF5 XOP"}
23  end
24 
25  submenu "On-the-Fly Data"
26  PearlMenuEnableFunc("otf_rename_folders") + "Shorten OTF Folder Names", /Q, otf_rename_folders("010")
27  help = {"Renames otf_xxxxxx_yyyyyy_zzzz data folders to otf_yyyyyy (removing date and suffix)", "Requires Optics package"}
28  PearlMenuEnableFunc("otf_gather_batch") + "Gather OTF Batch", /Q, otf_gather_batch("current_ch1", "photonenergy", "otf_batch")
29  help = {"Copies data from all otf_* folders into otf_batch folder", "Requires Optics package"}
30  PearlMenuEnableFunc("PearlOpticsPreviewPanel") + "OTF Preview", /Q, PearlOpticsPreviewPanel()
31  help = {"Opens a preview panel for OTF data in otf_* folders", "Requires Optics package"}
32  end
33 
34  submenu "Scienta Analyser"
35  PearlMenuEnableFunc("ad_display_profiles") + "Scienta Live View", /Q, PearlLiveDisplay("X03DA-SCIENTA:", "EA", "(65280,54528,48896)")
36  help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
37  PearlMenuEnableFunc("ast_setup") + "Angle Scan Tracker", /Q, PearlAnglescanTracker("X03DA-SCIENTA:", "(65280,54528,48896)")
38  help = {"Preview of acquired angle scan data and current detection angles.", "Requires ARPES package and EPICS XOP"}
39  end
40 
41  submenu "Cameras"
42  PearlMenuEnableFunc("ad_display_profiles") + "Exit Slit Live View", /Q, PearlLiveDisplay("X03DA-OP-PS1:", "OP", "(65280,54528,48896)")
43  help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
44  PearlMenuEnableFunc("ad_display_profiles") + "Manipulator Live View", /Q, PearlLiveDisplay("X03DA-ES-PS1:", "ES", "(65280,54528,48896)")
45  help = {"Display live panel of the exit slit camera", "Requires ARPES package and EPICS XOP"}
46  end
47 
48  submenu "Display"
49  PearlMenuEnableFunc("ad_display_profiles") + "2D Profiles", /Q, Display2dProfiles()
50  help = {"Profiles display of 2D data", "Requires ARPES package"}
51  PearlMenuEnableFunc("ad_display_brick") + "3D Slicer", /Q, Display3dSlicer()
52  help = {"Slice and profiles display of 3D data", "Requires ARPES package"}
53  PearlMenuEnableFunc("ad_display_brick") + "3D Gizmo", /Q, DisplayGizmoSlicer()
54  help = {"Gizmo display of 3D data", "Requires ARPES package"}
55  end
56 
57  submenu "Process"
58  PearlMenuEnableFunc("asp_show_panel") + "XPD scans", /Q, asp_show_panel()
59  help = {"Data processing of two-pi angle scans", "Requires ARPES package"}
60  end
61 
62  submenu "Services"
63  PearlMenuEnableFunc("pearl_elog") + "Open ELOG Panel", /Q, pearl_elog("")
64  help = {"Open an ELOG panel to send entries to an ELOG logbook"}
65  end
66 
67  submenu "Sample Preparation"
68  PearlMenuEnableFunc("ann_ramp_start") + "Annealing Ramp", /Q, panel_ramp_gen()
69  help = {"Sample annealing ramp generator"}
70  end
71 
72  submenu "Packages"
73  "Load ARPES Package", /Q, LoadPearlArpes()
74  help = {"Data processing and analysis for ARPES experiments"}
75  "Load Preparation Package", /Q, LoadPearlPreparation()
76  help = {"Process control for sample preparation"}
77  "Load Optics Package", /Q, LoadPearlOptics()
78  help = {"Data processing and analysis for beamline commissioning"}
79  end
80 end
81 
82 function /s PearlMenuEnableFunc(funcname)
83  // checks whether a function name exists
84  // and conditionally returns a prefix which disables the menu item
85  // if the function does not exist
86  string funcname
87  if (exists(funcname) >= 3)
88  return ""
89  else
90  return "("
91  endif
92 end
93 
94 function LoadPearlOptics()
95  execute /p/q/z "INSERTINCLUDE \"pearl-optics\""
96  execute /p/q/z "COMPILEPROCEDURES "
97  execute /p/q/z "PearlOpticsPanel#po_InitPanel()"
98  execute /p/q/z "BuildMenu \"PEARL\""
99 end
100 
101 function LoadPearlArpes()
102  execute /p/q/z "INSERTINCLUDE \"pearl-arpes\""
103  execute /p/q/z "COMPILEPROCEDURES "
104  execute /p/q/z "BuildMenu \"PEARL\""
105 end
106 
108  execute /p/q/z "INSERTINCLUDE \"pearl-preparation\""
109  execute /p/q/z "COMPILEPROCEDURES "
110  execute /p/q/z "BuildMenu \"PEARL\""
111 end
112 
114  dfref dfBefore = GetDataFolderDFR()
115  Execute /q/z "CreateBrowser prompt=\"Select 2D wave\", showWaves=1, showVars=0, showStrs=0"
116  dfref dfAfter = GetDataFolderDFR()
117  SetDataFolder dfBefore
118 
119  SVAR list = S_BrowserList
120  NVAR flag = V_Flag
121 
122  if ((flag != 0) && (ItemsInList(list) >= 1))
123  string brickname = StringFromList(0, list)
124  string cmd
125  sprintf cmd, "ad_display_profiles(%s)", brickname
126  execute /q/z cmd
127  endif
128 end
129 
130 function Display3dSlicer()
131  dfref dfBefore = GetDataFolderDFR()
132  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
133  dfref dfAfter = GetDataFolderDFR()
134  SetDataFolder dfBefore
135 
136  SVAR list = S_BrowserList
137  NVAR flag = V_Flag
138 
139  if ((flag != 0) && (ItemsInList(list) >= 1))
140  string brickname = StringFromList(0, list)
141  string cmd
142  sprintf cmd, "ad_display_slice(%s)", brickname
143  execute /q/z cmd
144  sprintf cmd, "ad_brick_slicer(%s)", brickname
145  execute /q/z cmd
146  endif
147 end
148 
150  dfref dfBefore = GetDataFolderDFR()
151  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
152  dfref dfAfter = GetDataFolderDFR()
153  SetDataFolder dfBefore
154 
155  SVAR list = S_BrowserList
156  NVAR flag = V_Flag
157 
158  if ((flag != 0) && (ItemsInList(list) >= 1))
159  string brickname = StringFromList(0, list)
160  string cmd
161  sprintf cmd, "ad_display_brick(%s)", brickname
162  execute /q/z cmd
163  sprintf cmd, "ad_brick_slicer(%s)", brickname
164  execute /q/z cmd
165  endif
166 end
167 
168 function PearlLiveDisplay(epicsname, nickname, wbRGB)
169  string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
170  // image1: and cam1: are appended by the function
171  // see ad_connect
172  string nickname // nick name under which this detector is referred to in Igor
173  // must be a valid data folder name
174  // see ad_connect
175  string wbRGB // window background color, e.g. "(32768,49152,55296)"
176  string cmd
177  sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
178  execute /q/z cmd
179  sprintf cmd, "ad_display_profiles(root:pearl_epics:%s:image)", nickname
180  execute /q/z cmd
181  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
182  execute /q/z cmd
183  sprintf cmd, "add_roi_controls()"
184  execute /q/z cmd
185 end
186 
187 function PearlAnglescanTracker(epicsname, wbRGB)
188  string epicsname // base name of the detector, e.g. X03DA-SCIENTA:
189  // image1: and cam1: are appended by the function
190  // see ast_setup
191  string wbRGB // window background color, e.g. "(32768,49152,55296)"
192  string cmd
193  sprintf cmd, "ast_setup()"
194  execute /q/z cmd
195  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
196  execute /q/z cmd
197 end
variable PearlLiveDisplay(string epicsname, string nickname, string wbRGB)
Definition: pearl-menu.ipf:168
-
variable DisplayGizmoSlicer()
Definition: pearl-menu.ipf:149
+Go to the documentation of this file.
1 #pragma rtGlobals=1 // Use modern global access method.
2 #pragma ModuleName = PearlMenu
3 #pragma version = 1.02
4 
5 // main menu for PEARL data acquisition and analysis packages
6 
7 // $Id$
8 // author: matthias.muntwiler@psi.ch
9 // Copyright (c) 2013-14 Paul Scherrer Institut
10 
11 // Licensed under the Apache License, Version 2.0 (the "License");
12 // you may not use this file except in compliance with the License.
13 // You may obtain a copy of the License at
14 // http://www.apache.org/licenses/LICENSE-2.0
15 
16 menu "PEARL"
17 
18  submenu "Data Files"
19  PearlMenuEnableFunc("pearl_data_explorer") + "Data Explorer", /Q, pearl_data_explorer()
20  help = {"Data explorer panel with file import and preview", "Requires ARPES package and HDF5 XOP"}
21  PearlMenuEnableFunc("ad_load_dialog") + "AD HDF5", /Q, ad_load_dialog("")
22  help = {"Import area detector HDF5 data file", "Requires ARPES package and HDF5 XOP"}
23  end
24 
25  submenu "On-the-Fly Data"
26  PearlMenuEnableFunc("otf_rename_folders") + "Shorten OTF Folder Names", /Q, otf_rename_folders("010")
27  help = {"Renames otf_xxxxxx_yyyyyy_zzzz data folders to otf_yyyyyy (removing date and suffix)", "Requires Optics package"}
28  PearlMenuEnableFunc("otf_gather_batch") + "Gather OTF Batch", /Q, otf_gather_batch("current_ch1", "photonenergy", "otf_batch")
29  help = {"Copies data from all otf_* folders into otf_batch folder", "Requires Optics package"}
30  PearlMenuEnableFunc("PearlOpticsPreviewPanel") + "OTF Preview", /Q, PearlOpticsPreviewPanel()
31  help = {"Opens a preview panel for OTF data in otf_* folders", "Requires Optics package"}
32  end
33 
34  submenu "Scienta Analyser"
35  PearlMenuEnableFunc("ad_display_profiles") + "Scienta Live View", /Q, PearlLiveDisplay("X03DA-SCIENTA:", "EA", "(65280,54528,48896)")
36  help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
37  PearlMenuEnableFunc("ast_setup") + "Angle Scan Tracker", /Q, PearlAnglescanTracker("X03DA-SCIENTA:", "(65280,54528,48896)")
38  help = {"Preview of acquired angle scan data and current detection angles.", "Requires ARPES package and EPICS XOP"}
39  PearlMenuEnableFunc("sample_tracker") + "Sample Tracker", /Q, PearlSampleTracker(1)
40  help = {"Live tracking and adjustment of sample position.", "Requires ARPES package and EPICS XOP"}
41  end
42 
43  submenu "Cameras"
44  PearlMenuEnableFunc("ad_display_profiles") + "Exit Slit Camera", /Q, PearlLiveDisplay("X03DA-OP-PS1:", "OP", "(65280,54528,48896)")
45  help = {"Display preview panel with latest image from Scienta", "Requires ARPES package and EPICS XOP"}
46  PearlMenuEnableFunc("ad_display_profiles") + "Manipulator Camera", /Q, PearlCameraDisplay("X03DA-ES-PS1:", "ES", "(32767,32767,32767)")
47  help = {"Display live panel of the exit slit camera", "Requires ARPES package and EPICS XOP"}
48  end
49 
50  submenu "Display"
51  PearlMenuEnableFunc("ad_display_profiles") + "2D Profiles", /Q, Display2dProfiles()
52  help = {"Profiles display of 2D data", "Requires ARPES package"}
53  PearlMenuEnableFunc("ad_display_brick") + "3D Slicer", /Q, Display3dSlicer()
54  help = {"Slice and profiles display of 3D data", "Requires ARPES package"}
55  PearlMenuEnableFunc("ad_display_brick") + "3D Gizmo", /Q, DisplayGizmoSlicer()
56  help = {"Gizmo display of 3D data", "Requires ARPES package"}
57  end
58 
59  submenu "Process"
60  PearlMenuEnableFunc("asp_show_panel") + "XPD scans", /Q, asp_show_panel()
61  help = {"Data processing of two-pi angle scans", "Requires ARPES package"}
62  end
63 
64  submenu "Services"
65  PearlMenuEnableFunc("pearl_elog") + "Open ELOG Panel", /Q, pearl_elog("")
66  help = {"Open an ELOG panel to send entries to an ELOG logbook"}
67  end
68 
69  submenu "Sample Preparation"
70  PearlMenuEnableFunc("ramp_generator") + "Annealing Ramp", /Q, ramp_generator()
71  help = {"Sample annealing ramp generator"}
72  end
73 
74  submenu "Packages"
75  "Load ARPES Package", /Q, LoadPearlArpes()
76  help = {"Data processing and analysis for ARPES experiments"}
77  "Load Preparation Package", /Q, LoadPearlPreparation()
78  help = {"Process control for sample preparation"}
79  "Load Optics Package", /Q, LoadPearlOptics()
80  help = {"Data processing and analysis for beamline commissioning"}
81  end
82 end
83 
89 function /s PearlMenuEnableFunc(funcname)
90  string funcname
91  if (exists(funcname) >= 3)
92  return ""
93  else
94  return "("
95  endif
96 end
97 
98 function LoadPearlOptics()
99  execute /p/q/z "INSERTINCLUDE \"pearl-optics\""
100  execute /p/q/z "COMPILEPROCEDURES "
101  execute /p/q/z "BuildMenu \"PEARL\""
102 end
103 
104 function LoadPearlArpes()
105  execute /p/q/z "INSERTINCLUDE \"pearl-arpes\""
106  execute /p/q/z "COMPILEPROCEDURES "
107  execute /p/q/z "BuildMenu \"PEARL\""
108 end
109 
111  execute /p/q/z "INSERTINCLUDE \"pearl-preparation\""
112  execute /p/q/z "COMPILEPROCEDURES "
113  execute /p/q/z "BuildMenu \"PEARL\""
114 end
115 
117  dfref dfBefore = GetDataFolderDFR()
118  Execute /q/z "CreateBrowser prompt=\"Select 2D wave\", showWaves=1, showVars=0, showStrs=0"
119  dfref dfAfter = GetDataFolderDFR()
120  SetDataFolder dfBefore
121 
122  SVAR list = S_BrowserList
123  NVAR flag = V_Flag
124 
125  if ((flag != 0) && (ItemsInList(list) >= 1))
126  string brickname = StringFromList(0, list)
127  string cmd
128  sprintf cmd, "ad_display_profiles(%s)", brickname
129  execute /q/z cmd
130  endif
131 end
132 
133 function Display3dSlicer()
134  dfref dfBefore = GetDataFolderDFR()
135  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
136  dfref dfAfter = GetDataFolderDFR()
137  SetDataFolder dfBefore
138 
139  SVAR list = S_BrowserList
140  NVAR flag = V_Flag
141 
142  if ((flag != 0) && (ItemsInList(list) >= 1))
143  string brickname = StringFromList(0, list)
144  string cmd
145  sprintf cmd, "ad_display_slice(%s)", brickname
146  execute /q/z cmd
147  sprintf cmd, "ad_brick_slicer(%s)", brickname
148  execute /q/z cmd
149  endif
150 end
151 
153  dfref dfBefore = GetDataFolderDFR()
154  Execute /q/z "CreateBrowser prompt=\"Select 3D wave\", showWaves=1, showVars=0, showStrs=0"
155  dfref dfAfter = GetDataFolderDFR()
156  SetDataFolder dfBefore
157 
158  SVAR list = S_BrowserList
159  NVAR flag = V_Flag
160 
161  if ((flag != 0) && (ItemsInList(list) >= 1))
162  string brickname = StringFromList(0, list)
163  string cmd
164  sprintf cmd, "ad_display_brick(%s)", brickname
165  execute /q/z cmd
166  sprintf cmd, "ad_brick_slicer(%s)", brickname
167  execute /q/z cmd
168  endif
169 end
170 
185 function PearlLiveDisplay(epicsname, nickname, wbRGB)
186  string epicsname
187  string nickname
188  string wbRGB
189 
190  string cmd
191  sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
192  execute /q/z cmd
193  sprintf cmd, "ad_display_profiles(root:pearl_epics:%s:image)", nickname
194  execute /q/z cmd
195  //sprintf cmd, "ad_add_overlay(root:pearl_epics:%s:image)", nickname
196  //execute /q/z cmd
197  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
198  execute /q/z cmd
199  sprintf cmd, "add_roi_controls()"
200  execute /q/z cmd
201 end
202 
218 function PearlCameraDisplay(epicsname, nickname, wbRGB)
219  string epicsname
220  string nickname
221  string wbRGB
222 
223  string cmd
224  sprintf cmd, "ad_connect(\"%s\", \"%s\")", epicsname, nickname
225  execute /q/z cmd
226  sprintf cmd, "display; appendimage root:pearl_epics:%s:image", nickname
227  execute /q/z cmd
228  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
229  execute /q/z cmd
230  cmd = "ModifyGraph height={Plan,1,left,bottom}"
231  execute /q/z cmd
232 end
233 
242 function PearlAnglescanTracker(epicsname, wbRGB)
243  string epicsname
244  string wbRGB
245 
246  string cmd
247  sprintf cmd, "ast_setup()"
248  execute /q/z cmd
249  sprintf cmd, "ModifyGraph wbRGB=%s", wbRGB
250  execute /q/z cmd
251 end
252 
261 function PearlSampleTracker(action)
262  variable action
263  string cmd
264  sprintf cmd, "sample_tracker(%u)", action
265  execute /q/z cmd
266 end
267 
variable PearlLiveDisplay(string epicsname, string nickname, string wbRGB)
area detector live display
Definition: pearl-menu.ipf:185
+
variable DisplayGizmoSlicer()
Definition: pearl-menu.ipf:152
variable ad_load_dialog(string APathName)
load area detector data files selected in a file dialog window
-
variable ad_brick_slicer(wave data)
open a slicer panel for 3D data.
+
variable ad_brick_slicer(wave data)
open a slicer panel for 3D data.
variable ast_setup()
set up data structures, display graph, and try to connect to analyser.
-
variable LoadPearlPreparation()
Definition: pearl-menu.ipf:107
-
variable PearlAnglescanTracker(string epicsname, string wbRGB)
Definition: pearl-menu.ipf:187
-
variable LoadPearlArpes()
Definition: pearl-menu.ipf:101
-
variable LoadPearlOptics()
Definition: pearl-menu.ipf:94
-
variable Display3dSlicer()
Definition: pearl-menu.ipf:130
+
variable LoadPearlPreparation()
Definition: pearl-menu.ipf:110
+
variable PearlAnglescanTracker(string epicsname, string wbRGB)
display the angle scan tracker window
Definition: pearl-menu.ipf:242
+
variable LoadPearlArpes()
Definition: pearl-menu.ipf:104
+
variable LoadPearlOptics()
Definition: pearl-menu.ipf:98
+
variable PearlSampleTracker(variable action)
display the sample tracker window
Definition: pearl-menu.ipf:261
+
variable PearlCameraDisplay(string epicsname, string nickname, string wbRGB)
area detector surveillance camera display
Definition: pearl-menu.ipf:218
+
variable Display3dSlicer()
Definition: pearl-menu.ipf:133
variable otf_gather_batch(string ywavematch, string xwavematch, string destfolder)
-
variable asp_show_panel()
create the angle scan processing panel
+
variable asp_show_panel()
create the angle scan processing panel
variable otf_rename_folders(string pattern, variable unique_index=defaultValue, string new_suffix=defaultValue, string match_str=defaultValue)
string ad_display_profiles(wave image, string filter=defaultValue)
open a new profiles graph window.
variable pearl_data_explorer()
-
string PearlMenuEnableFunc(string funcname)
Definition: pearl-menu.ipf:82
-
string ad_display_slice(wave data)
display three-dimensional data by 2D slice.
+
string PearlMenuEnableFunc(string funcname)
check whether a function name exists
Definition: pearl-menu.ipf:89
+
string ad_display_slice(wave data)
display three-dimensional data by 2D slice.
variable pearl_elog(string logbook)
main function to initialize ELOG and to open an ELOG panel.
Definition: pearl-elog.ipf:97
-
string ad_display_brick(wave data)
open a new "gizmo" window with three-dimensional data.
-
variable Display2dProfiles()
Definition: pearl-menu.ipf:113
+
string ad_display_brick(wave data)
open a new "gizmo" window with three-dimensional data.
+
variable Display2dProfiles()
Definition: pearl-menu.ipf:116
@@ -368,7 +391,7 @@ Licensed under the Apache License, Version 2.0 (the "License");

prompt for the gauss4_reduction parameters

-

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

+

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

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

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

+

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

@@ -439,7 +462,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 463 of file pearl-scienta-preprocess.ipf.

+

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

@@ -491,7 +514,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
free wave containing references of the two result waves. the first wave is the integral minus linear background. the second wave is the Poisson one-sigma error.
-

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

+

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

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

apply the gauss4_reduction function to a single image

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

-

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

+

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

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

Definition at line 10 of file pearl-vector-operations.ipf.

+

rotate a 2D cartesian vector and returns its x component.

+
Parameters
+ + + + +
xxx coordinate.
yyy coordinate.
anglerotation angle in degrees.
+
+
+
Returns
x coordinate of the rotated vector.
+ +

Definition at line 45 of file pearl-vector-operations.ipf.

@@ -199,7 +243,18 @@ Functions
-

Definition at line 18 of file pearl-vector-operations.ipf.

+

rotate a 2D cartesian vector and returns its y component.

+
Parameters
+ + + + +
xxx coordinate.
yyy coordinate.
anglerotation angle in degrees.
+
+
+
Returns
y coordinate of the rotated vector.
+ +

Definition at line 60 of file pearl-vector-operations.ipf.

@@ -229,7 +284,18 @@ Functions
-

Definition at line 83 of file pearl-vector-operations.ipf.

+

rotate a wave of 3-vectors about the x axis.

+

this function rotates multiple vectors.

+
Parameters
+ + + +
[in,out]inoutwave with dimensions (M, N), M >= 3 (x, y, z), N >= 1. the result will be in same wave. only the first three rows of dimension 0 are used, extra rows are left unchanged.
[in]anglerotation angle in degrees.
+
+
+
Returns
none
+ +

Definition at line 175 of file pearl-vector-operations.ipf.

@@ -259,7 +325,18 @@ Functions
-

Definition at line 101 of file pearl-vector-operations.ipf.

+

rotates a wave of 3-vectors about the y axis

+

this function rotates multiple vectors.

+
Parameters
+ + + +
[in,out]inoutwave with dimensions (M, N), M >= 3 (x, y, z), N >= 1. the result will be in same wave. only the first three rows of dimension 0 are used, extra rows are left unchanged.
[in]anglerotation angle in degrees.
+
+
+
Returns
none
+ +

Definition at line 203 of file pearl-vector-operations.ipf.

@@ -289,7 +366,18 @@ Functions
-

Definition at line 119 of file pearl-vector-operations.ipf.

+

rotates a wave of 3-vectors about the z axis

+

this function rotates multiple vectors.

+
Parameters
+ + + +
[in,out]inoutwave with dimensions (M, N), M >= 3 (x, y, z), N >= 1. the result will be in same wave. only the first three rows of dimension 0 are used, extra rows are left unchanged.
[in]anglerotation angle in degrees.
+
+
+
Returns
none
+ +

Definition at line 231 of file pearl-vector-operations.ipf.

@@ -319,7 +407,18 @@ Functions
-

Definition at line 35 of file pearl-vector-operations.ipf.

+

calculate a matrix representing a 3-vector rotation around the x axis.

+

the function calculates the matrix elements of a rotation about the x axis.

+
Parameters
+ + + +
[in,out]matrix3x3 wave to receive the rotation matrix elements. the function calculates only the 2x2 block of the rotation. the other elements must be initialized by the caller, e.g. set to the identity matrix.
[in]anglerotation angle in degrees.
+
+
+
Returns
rotation matrix. this is the same wave instance as the matrix input.
+ +

Definition at line 92 of file pearl-vector-operations.ipf.

@@ -349,7 +448,18 @@ Functions
-

Definition at line 51 of file pearl-vector-operations.ipf.

+

calculate a matrix representing a 3-vector rotation around the y axis

+

the function calculates the matrix elements of a rotation about the y axis.

+
Parameters
+ + + +
[in,out]matrix3x3 wave to receive the rotation matrix elements. the function calculates only the 2x2 block of the rotation. the other elements must be initialized by the caller, e.g. set to the identity matrix.
[in]anglerotation angle in degrees.
+
+
+
Returns
rotation matrix. this is the same wave instance as the matrix input.
+ +

Definition at line 120 of file pearl-vector-operations.ipf.

@@ -379,7 +489,18 @@ Functions
-

Definition at line 67 of file pearl-vector-operations.ipf.

+

calculate a matrix representing a 3-vector rotation around the z axis

+

the function calculates the matrix elements of a rotation about the z axis.

+
Parameters
+ + + +
[in,out]matrix3x3 wave to receive the rotation matrix elements. the function calculates only the 2x2 block of the rotation. the other elements must be initialized by the caller, e.g. set to the identity matrix.
[in]anglerotation angle in degrees.
+
+
+
Returns
rotation matrix. this is the same wave instance as the matrix input.
+ +

Definition at line 148 of file pearl-vector-operations.ipf.

@@ -389,7 +510,7 @@ Functions
-Go to the documentation of this file.
1 #pragma rtGlobals=3
2 #pragma version = 2.0
3 #pragma IgorVersion = 6.1
4 #pragma ModuleName = PearlVectorOperations
5 
6 // author: matthias.muntwiler@psi.ch
7 // Copyright (c) 2011-13 Paul Scherrer Institut
8 // $Id$
9 
10 function rotate2d_x(xx, yy, angle)
11  // rotates a 2D cartesian vector and returns its x component
12  variable xx, yy
13  variable angle // rotation angle in degrees
14 
15  return xx * cos(angle * pi / 180) - yy * sin(angle * pi / 180)
16 end
17 
18 function rotate2d_y(xx, yy, angle)
19  // rotates a 2D cartesian vector and returns its y component
20  variable xx, yy
21  variable angle // rotation angle in degrees
22 
23  return xx * sin(angle * pi / 180) + yy * cos(angle * pi / 180)
24 end
25 
27  // creates a matrix which represents a 3-vector rotation
28  // the matrix is initialized as identity
29 
30  make /n=(3,3)/free matrix
31  matrix = p == q // identity
32  return matrix
33 end
34 
35 function /wave set_rotation_x(matrix, angle)
36  // calculates a matrix representing a 3-vector rotation around the x axis
37  wave matrix // rotation matrix
38  variable angle // rotation angle in degrees
39 
40  variable si = sin(angle * pi / 180)
41  variable co = cos(angle * pi / 180)
42 
43  matrix[1][1] = co
44  matrix[2][2] = co
45  matrix[2][1] = si
46  matrix[1][2] = -si
47 
48  return matrix
49 end
50 
51 function /wave set_rotation_y(matrix, angle)
52  // calculates a matrix representing a 3-vector rotation around the y axis
53  wave matrix // rotation matrix
54  variable angle // rotation angle in degrees
55 
56  variable si = sin(angle * pi / 180)
57  variable co = cos(angle * pi / 180)
58 
59  matrix[0][0] = co
60  matrix[2][2] = co
61  matrix[0][2] = si
62  matrix[2][0] = -si
63 
64  return matrix
65 end
66 
67 function /wave set_rotation_z(matrix, angle)
68  // calculates a matrix representing a 3-vector rotation around the z axis
69  wave matrix // rotation matrix
70  variable angle // rotation angle in degrees
71 
72  variable si = sin(angle * pi / 180)
73  variable co = cos(angle * pi / 180)
74 
75  matrix[0][0] = co
76  matrix[1][1] = co
77  matrix[1][0] = si
78  matrix[0][1] = -si
79 
80  return matrix
81 end
82 
83 function rotate_x_wave(inout, angle)
84  // rotates a wave of 3-vectors about the x axis
85  wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
86  // result will be in same wave
87  variable angle // rotation angle in degrees
88 
89  wave m_rotation_x = create_rotation_matrix_free()
90  make /n=3/d/free w_temp_rotate_x
91  variable ivec, nvec
92  nvec = max(DimSize(inout, 1), 1)
93  for (ivec = 0; ivec < nvec; ivec += 1)
94  set_rotation_x(m_rotation_x, angle)
95  w_temp_rotate_x = inout[p][ivec]
96  matrixop /free w_temp_rotate_x_result = m_rotation_x x w_temp_rotate_x
97  inout[][ivec] = w_temp_rotate_x_result[p]
98  endfor
99 end
100 
101 function rotate_y_wave(inout, angle)
102  // rotates a wave of 3-vectors about the y axis
103  wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
104  // result will be in same wave
105  variable angle // rotation angle in degrees
106 
107  wave m_rotation_y = create_rotation_matrix_free()
108  make /n=3/d/free w_temp_rotate_y
109  variable ivec, nvec
110  nvec = max(DimSize(inout, 1), 1)
111  for (ivec = 0; ivec < nvec; ivec += 1)
112  set_rotation_y(m_rotation_y, angle)
113  w_temp_rotate_y = inout[p][ivec]
114  matrixop /free w_temp_rotate_y_result = m_rotation_y x w_temp_rotate_y
115  inout[][ivec] = w_temp_rotate_y_result[p]
116  endfor
117 end
118 
119 function rotate_z_wave(inout, angle)
120  // rotates a wave of 3-vectors about the z axis
121  wave inout // wave with dimensions (3, N), N >= 1, (x, y, z)
122  // result will be in same wave
123  variable angle // rotation angle in degrees
124 
125  wave m_rotation_z = create_rotation_matrix_free()
126  make /n=3/d/free w_temp_rotate_z
127  variable ivec, nvec
128  nvec = max(DimSize(inout, 1), 1)
129  for (ivec = 0; ivec < nvec; ivec += 1)
130  set_rotation_z(m_rotation_z, angle)
131  w_temp_rotate_z = inout[p][ivec]
132  matrixop /free w_temp_rotate_z_result = m_rotation_z x w_temp_rotate_z
133  inout[][ivec] = w_temp_rotate_z_result[p]
134  endfor
135 end
wave set_rotation_x(wave matrix, variable angle)
-
variable rotate_x_wave(wave inout, variable angle)
-
variable rotate2d_x(variable xx, variable yy, variable angle)
-
wave set_rotation_z(wave matrix, variable angle)
-
variable rotate_y_wave(wave inout, variable angle)
-
variable rotate2d_y(variable xx, variable yy, variable angle)
-
variable rotate_z_wave(wave inout, variable angle)
-
wave create_rotation_matrix_free()
-
wave set_rotation_y(wave matrix, variable angle)
+Go to the documentation of this file.
1 #pragma rtGlobals=3
2 #pragma version = 2.1
3 #pragma IgorVersion = 6.1
4 #pragma ModuleName = PearlVectorOperations
5 
6 // copyright (c) 2011-17 Paul Scherrer Institut
7 //
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
11 // http:///www.apache.org/licenses/LICENSE-2.0
12 //
13 // Please acknowledge the use of this code.
14 
30 
35 
36 
45 function rotate2d_x(xx, yy, angle)
46  variable xx, yy
47  variable angle
48 
49  return xx * cos(angle * pi / 180) - yy * sin(angle * pi / 180)
50 end
51 
60 function rotate2d_y(xx, yy, angle)
61  variable xx, yy
62  variable angle
63 
64  return xx * sin(angle * pi / 180) + yy * cos(angle * pi / 180)
65 end
66 
74  make /n=(3,3)/free matrix
75  matrix = p == q // identity
76  return matrix
77 end
78 
92 function /wave set_rotation_x(matrix, angle)
93  wave matrix
94  variable angle
95 
96  variable si = sin(angle * pi / 180)
97  variable co = cos(angle * pi / 180)
98 
99  matrix[1][1] = co
100  matrix[2][2] = co
101  matrix[2][1] = si
102  matrix[1][2] = -si
103 
104  return matrix
105 end
106 
120 function /wave set_rotation_y(matrix, angle)
121  wave matrix
122  variable angle
123 
124  variable si = sin(angle * pi / 180)
125  variable co = cos(angle * pi / 180)
126 
127  matrix[0][0] = co
128  matrix[2][2] = co
129  matrix[0][2] = si
130  matrix[2][0] = -si
131 
132  return matrix
133 end
134 
148 function /wave set_rotation_z(matrix, angle)
149  wave matrix
150  variable angle
151 
152  variable si = sin(angle * pi / 180)
153  variable co = cos(angle * pi / 180)
154 
155  matrix[0][0] = co
156  matrix[1][1] = co
157  matrix[1][0] = si
158  matrix[0][1] = -si
159 
160  return matrix
161 end
162 
175 function rotate_x_wave(inout, angle)
176  wave inout
177  variable angle
178 
179  wave m_rotation_x = create_rotation_matrix_free()
180  make /n=3/d/free w_temp_rotate_x
181  variable ivec, nvec
182  nvec = max(DimSize(inout, 1), 1)
183  for (ivec = 0; ivec < nvec; ivec += 1)
184  set_rotation_x(m_rotation_x, angle)
185  w_temp_rotate_x = inout[p][ivec]
186  matrixop /free w_temp_rotate_x_result = m_rotation_x x w_temp_rotate_x
187  inout[0,2][ivec] = w_temp_rotate_x_result[p]
188  endfor
189 end
190 
203 function rotate_y_wave(inout, angle)
204  wave inout
205  variable angle
206 
207  wave m_rotation_y = create_rotation_matrix_free()
208  make /n=3/d/free w_temp_rotate_y
209  variable ivec, nvec
210  nvec = max(DimSize(inout, 1), 1)
211  for (ivec = 0; ivec < nvec; ivec += 1)
212  set_rotation_y(m_rotation_y, angle)
213  w_temp_rotate_y = inout[p][ivec]
214  matrixop /free w_temp_rotate_y_result = m_rotation_y x w_temp_rotate_y
215  inout[0,2][ivec] = w_temp_rotate_y_result[p]
216  endfor
217 end
218 
231 function rotate_z_wave(inout, angle)
232  wave inout
233  variable angle
234 
235  wave m_rotation_z = create_rotation_matrix_free()
236  make /n=3/d/free w_temp_rotate_z
237  variable ivec, nvec
238  nvec = max(DimSize(inout, 1), 1)
239  for (ivec = 0; ivec < nvec; ivec += 1)
240  set_rotation_z(m_rotation_z, angle)
241  w_temp_rotate_z = inout[p][ivec]
242  matrixop /free w_temp_rotate_z_result = m_rotation_z x w_temp_rotate_z
243  inout[0,2][ivec] = w_temp_rotate_z_result[p]
244  endfor
245 end
wave set_rotation_x(wave matrix, variable angle)
calculate a matrix representing a 3-vector rotation around the x axis.
+
variable rotate_x_wave(wave inout, variable angle)
rotate a wave of 3-vectors about the x axis.
+
variable rotate2d_x(variable xx, variable yy, variable angle)
rotate a 2D cartesian vector and returns its x component.
+
wave set_rotation_z(wave matrix, variable angle)
calculate a matrix representing a 3-vector rotation around the z axis
+
variable rotate_y_wave(wave inout, variable angle)
rotates a wave of 3-vectors about the y axis
+
variable rotate2d_y(variable xx, variable yy, variable angle)
rotate a 2D cartesian vector and returns its y component.
+
variable rotate_z_wave(wave inout, variable angle)
rotates a wave of 3-vectors about the z axis
+
wave create_rotation_matrix_free()
create a free matrix wave which represents the 3-vector identity.
+
wave set_rotation_y(wave matrix, variable angle)
calculate a matrix representing a 3-vector rotation around the y axis