PEARL Procedures  rev-distro-3.0.0-0-gfa24916-dirty
Igor procedures for the analysis of PEARL data
pearl-anglescan-process.ipf
Go to the documentation of this file.
1 #pragma TextEncoding = "UTF-8"
2 #pragma rtGlobals=3 // Use modern global access method and strict wave access.
3 #pragma version = 1.9
4 #pragma IgorVersion = 6.2
5 #pragma ModuleName = PearlAnglescanProcess
6 #include "pearl-vector-operations"
7 #include "pearl-polar-coordinates"
8 #include <New Polar Graphs>
9 
10 // copyright (c) 2013-21 Paul Scherrer Institut
11 //
12 // Licensed under the Apache License, Version 2.0 (the "License");
13 // you may not use this file except in compliance with the License.
14 // You may obtain a copy of the License at
15 // http:///www.apache.org/licenses/LICENSE-2.0
16 //
17 // Please acknowledge the use of this code.
18 
77 
82 
83 
106 function /s strip_append(strip1, strip2)
107  wave strip1
108  wave strip2
109 
110  dfref df1 = GetWavesDataFolderDFR(strip1)
111  dfref df2 = GetWavesDataFolderDFR(strip2)
112  variable ny1 = dimsize(strip1, 1)
113  variable ny2 = dimsize(strip2, 1)
114 
115  concatenate /np=1 {strip2}, strip1
116  string modified = AddListItem(NameOfWave(strip1), "")
117 
118  variable idf = 0
119  do
120  variable iw = 0
121  do
122  wave /z w1 = WaveRefIndexedDFR(df1, iw)
123  if (!WaveExists(w1))
124  break
125  endif
126 
127  wave /z w2 = df2:$(NameOfWave(w1))
128  if (WaveExists(w1) && WaveExists(w2))
129  if ((DimSize(w1, 0) == ny1) && (DimSize(w1, 1) == 0) && (DimSize(w2, 0) == ny2) && (DimSize(w2, 1) == 0))
130  concatenate /np=0 {w2}, w1
131  modified = AddListItem(NameOfWave(w1), modified, "", Inf)
132  endif
133  endif
134  iw += 1
135  while(1)
136 
137  df1 = df1:attr
138  df2 = df2:attr
139  if ((DataFolderRefStatus(df1) != 1) || (DataFolderRefStatus(df2) != 1))
140  break
141  endif
142  idf += 1
143  while(idf < 2)
144 
145  return modified
146 end
147 
170 function strip_delete_frames(strip, qlo, qhi, theta, tilt, phi)
171  wave strip // 2D data, X-axis = analyser angle, Y-axis = arbitrary manipulator scan
172  variable qlo
173  variable qhi
174  wave theta
175  wave tilt
176  wave phi
177 
178  if (qlo > qhi)
179  return -1
180  endif
181 
182  // source indices
183  variable snx = dimsize(strip, 0)
184  variable sny = dimsize(strip, 1)
185  variable sq1lo = 0
186  variable sq1hi = max(qlo-1, 0)
187  variable sq2lo = min(qhi+1, sny - 1)
188  variable sq2hi = dimsize(strip, 1) - 1
189 
190  // dest indices
191  variable dnx = snx
192  variable dny = sny - (sq2lo - sq1hi + 1)
193  variable dq1lo = 0
194  variable dq1hi = sq1hi
195  variable dq2lo = dq1hi + 1
196  variable dq2hi = dny - 1
197  variable q1ofs = sq1lo - dq1lo
198  variable q2ofs = sq2lo - dq2lo
199 
200  duplicate /free strip, strip_copy
201  redimension /n=(dnx,dny) strip
202  strip[][dq1lo,dq1hi] = strip_copy[p][q + q1ofs]
203  strip[][dq2lo,dq2hi] = strip_copy[p][q + q2ofs]
204 
205  duplicate /free theta, theta_copy
206  redimension /n=(dny) theta
207  theta[dq1lo,dq1hi] = theta_copy[p + q1ofs]
208  theta[dq2lo,dq2hi] = theta_copy[p + q2ofs]
209 
210  duplicate /free tilt, tilt_copy
211  redimension /n=(dny) tilt
212  tilt[dq1lo,dq1hi] = tilt_copy[p + q1ofs]
213  tilt[dq2lo,dq2hi] = tilt_copy[p + q2ofs]
214 
215  duplicate /free phi, phi_copy
216  redimension /n=(dny) phi
217  phi[dq1lo,dq1hi] = phi_copy[p + q1ofs]
218  phi[dq2lo,dq2hi] = phi_copy[p + q2ofs]
219 
220  return 0
221 end
222 
252 function normalize_strip_x(strip, [smooth_method, smooth_factor, check])
253  wave strip
254  variable smooth_method
255  variable smooth_factor
256  variable check
257 
258  if (ParamIsDefault(smooth_method))
259  smooth_method = 4
260  endif
261  if (ParamIsDefault(smooth_factor))
262  switch(smooth_method)
263  case 4:
264  smooth_factor = 0.5
265  break
266  default:
267  smooth_factor = 2
268  endswitch
269  endif
270  if (ParamIsDefault(check))
271  check = 0
272  endif
273 
274  // average over all scan positions
275  wave raw_dist = ad_profile_x(strip, -inf, inf, "")
276 
277  // remove nans
278  extract /free /indx raw_dist, clean_index, numtype(raw_dist) == 0
279  duplicate /free raw_dist, dist, dist_x
280  redimension /n=(numpnts(clean_index)) dist, dist_x
281  dist = raw_dist[clean_index[p]]
282  dist_x = pnt2x(raw_dist, clean_index[p])
283  variable div = mean(dist)
284  dist /= div
285 
286  if (check)
287  duplicate /o raw_dist, check_dist
288  check_dist = numtype(raw_dist) == 0 ? interp(x, dist_x, dist) : nan
289  endif
290 
291  // smooth distribution function
292  switch(smooth_method)
293  case 1:
294  Smooth /B /E=3 smooth_factor, dist
295  break
296  case 2:
297  Smooth /E=3 smooth_factor, dist
298  break
299  case 3:
300  make /n=1 /d /free fit_params
301  fit_scienta_ang_transm(raw_dist, fit_params)
302  duplicate /free raw_dist, dist, dist_x
303  dist_x = x
304  dist = scienta_ang_transm(fit_params, x)
305  break
306  case 4:
307  loess /smth=(smooth_factor) srcWave=dist, factors={dist_x}
308  break
309  endswitch
310 
311  if (check)
312  duplicate /o raw_dist, check_smoo
313  check_smoo = interp(x, dist_x, dist)
314  endif
315 
316  // divide
317  if (check != 2)
318  strip /= interp(x, dist_x, dist)
319  endif
320 end
321 
348 function normalize_strip_phi(strip, theta, phi, [theta_offset, theta_range, check])
349  wave strip
350  wave theta
351  wave phi
352  variable theta_offset
353  variable theta_range
354  variable check
355 
356  if (ParamIsDefault(check))
357  check = 0
358  endif
359  if (ParamIsDefault(theta_offset))
360  theta_offset = 0
361  endif
362  if (ParamIsDefault(theta_range))
363  theta_offset = 10
364  endif
365 
366  // average over analyser angles
367  duplicate /free strip, strip_copy
368  MatrixFilter NanZapMedian strip_copy
369  wave dist = ad_profile_y(strip_copy, -inf, inf, "")
370 
371  // smooth distribution function
372  duplicate /free dist, dist_smoo
373  duplicate /free theta, theta_int
374  theta_int = theta - theta_offset
375  duplicate /free phi, phi_int
376  setscale /p x phi_int[0], phi_int[1] - phi_int[0], waveunits(phi, -1), dist, dist_smoo
377 
378  extract /free /indx dist, red_idx, theta_int < theta_range
379  duplicate /free red_idx, red_dist, red_phi
380  red_dist = dist[red_idx]
381  red_phi = phi_int[red_idx]
382 
383  variable wavg = mean(red_dist)
384  make /n=4 /d /free coef
385  coef[0] = {wavg, wavg/100, pi/180, 0}
386  CurveFit /q /h="0010" /g /w=2 sin, kwcWave=coef, red_dist /x=red_phi
387  dist_smoo = coef[0] + coef[1] * sin(coef[2] * phi_int[p] + coef[3])
388 
389  // divide
390  if (check != 2)
391  strip = strip / dist_smoo[q] * coef[0]
392  endif
393 
394  // check
395  if (check)
396  duplicate /o dist, check_dist
397  duplicate /o dist_smoo, check_smoo
398  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
399  endif
400 end
401 
433 function normalize_strip_theta(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
434  wave strip
435  wave theta
436  variable theta_offset
437  variable smooth_method
438  variable smooth_factor
439  variable check
440 
441  if (ParamIsDefault(check))
442  check = 0
443  endif
444  if (ParamIsDefault(theta_offset))
445  theta_offset = 0
446  endif
447  if (ParamIsDefault(smooth_method))
448  smooth_method = 4
449  endif
450  if (ParamIsDefault(smooth_factor))
451  smooth_factor = 0.5
452  endif
453 
454  // average over analyser angles
455  duplicate /free strip, strip_copy
456  MatrixFilter NanZapMedian strip_copy
457  wave dist = ad_profile_y(strip_copy, -inf, inf, "")
458 
459  // smooth distribution function
460  duplicate /free dist, dist_smoo
461  duplicate /free theta, theta_int
462  theta_int = theta - theta_offset
463  setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
464  variable nx = dimsize(strip, 0)
465  variable ix
466 
467  switch(smooth_method)
468  case 1:
469  Smooth /B /E=3 smooth_factor, dist_smoo
470  break
471  case 2:
472  Smooth /E=3 smooth_factor, dist_smoo
473  break
474  case 4:
475  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={theta_int}
476  break
477  case 3:
478  for (ix = 0; ix < nx; ix += 1)
479  dist = strip[ix][p]
480  if (smooth_factor > 1)
481  CurveFit /nthr=0 /q /w=2 poly smooth_factor+1, dist /x=theta_int /d=dist_smoo
482  else
483  CurveFit /nthr=0 /q /w=2 line, dist /x=theta_int /d=dist_smoo
484  endif
485  strip[ix,ix][] /= dist_smoo[q]
486  endfor
487  dist_smoo = 1
488  break
489  endswitch
490 
491  // divide
492  if (check != 2)
493  strip /= dist_smoo[q]
494  endif
495 
496  // check
497  if (check)
498  duplicate /o dist, check_dist
499  duplicate /o dist_smoo, check_smoo
500  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
501  endif
502 end
503 
533 function normalize_strip_thetaphi(strip, theta, phi, [theta_offset, smooth_method, smooth_factor, check])
534  wave strip
535  wave theta
536  wave phi
537  variable theta_offset
538  variable smooth_method
539  variable smooth_factor
540  variable check
541 
542  if (ParamIsDefault(check))
543  check = 0
544  endif
545  if (ParamIsDefault(theta_offset))
546  theta_offset = 0
547  endif
548  if (ParamIsDefault(smooth_method))
549  smooth_method = 4
550  endif
551  if (ParamIsDefault(smooth_factor))
552  smooth_factor = 0.5
553  endif
554 
555  // average over analyser angles
556  duplicate /free strip, strip_copy
557  MatrixFilter NanZapMedian strip_copy
558  wave dist = ad_profile_y(strip_copy, -inf, inf, "")
559 
560  // smooth distribution function
561  duplicate /free dist, dist_smoo
562  duplicate /free theta, theta_int
563  theta_int = theta - theta_offset
564  setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
565  variable nx = dimsize(strip, 0)
566  variable ix
567 
568  switch(smooth_method)
569  case 4:
570  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={theta_int, phi}
571  break
572  default:
573  abort "smooth method not supported"
574  endswitch
575 
576  // divide
577  if (check != 2)
578  strip /= dist_smoo[q]
579  endif
580 
581  // check
582  if (check)
583  duplicate /o dist, check_dist
584  duplicate /o dist_smoo, check_smoo
585  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
586  endif
587 end
588 
594 function normalize_strip_theta_scans(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
595  wave strip
596  wave theta
597  variable theta_offset
598  variable smooth_method
599  variable smooth_factor
600  variable check
601 
602  if (ParamIsDefault(check))
603  check = 0
604  endif
605  if (ParamIsDefault(theta_offset))
606  theta_offset = 0
607  endif
608  if (ParamIsDefault(smooth_method))
609  smooth_method = 4
610  endif
611  if (ParamIsDefault(smooth_factor))
612  smooth_factor = 0.5
613  endif
614 
615  // average over analyser angles
616  duplicate /free strip, strip_copy
617  MatrixFilter NanZapMedian strip_copy
618  wave dist = ad_profile_y(strip_copy, -inf, inf, "")
619 
620  // smooth distribution function
621  duplicate /free dist, dist_smoo
622  duplicate /free theta, theta_int
623  theta_int = theta - theta_offset
624  setscale /p x theta_int[0], theta_int[1] - theta_int[0], waveunits(theta,-1), dist, dist_smoo
625 
626  // analyse scanning scheme
627  duplicate /free theta_int, d1_theta, d2_theta
628  Differentiate /METH=2 theta_int /D=d1_theta
629  Differentiate /METH=2 d1_theta /D=d2_theta
630  d2_theta = abs(d2_theta)
631  make /free w_levels
632  FindLevels /edge=1 /p /q /d=w_levels d2_theta, 0.1
633  if (v_flag != 1)
634  abort "unrecognized scanning scheme"
635  endif
636  w_levels = ceil(w_levels)
637  InsertPoints 0, 1, w_levels
638  w_levels[0] = 0
639  InsertPoints numpnts(w_levels), 1, w_levels
640  w_levels[numpnts(w_levels)-1] = numpnts(theta_int)
641 
642  variable n_scans = numpnts(w_levels) - 1
643  variable i_scan
644  variable p1, p2
645  for (i_scan = 0; i_scan < n_scans; i_scan += 1)
646  p1 = w_levels[i_scan]
647  p2 = w_levels[i_scan+1] - 1
648  duplicate /free /r=[p1, p2] dist, dist_piece, smooth_piece
649  duplicate /free /r=[p1, p2] theta_int, theta_piece
650  switch(smooth_method)
651  case 4:
652  loess /dest=smooth_piece /smth=(smooth_factor) srcWave=dist_piece, factors={theta_piece}
653  break
654  default:
655  abort "smooth method not supported"
656  endswitch
657  dist_smoo[p1, p2] = smooth_piece[p - p1]
658  endfor
659 
660  // divide
661  if (check != 2)
662  strip /= dist_smoo[q]
663  endif
664 
665  // check
666  if (check)
667  duplicate /o dist, check_dist
668  duplicate /o dist_smoo, check_smoo
669  setscale /p x dimoffset(dist,0), dimdelta(dist,0), waveunits(dist,0), check_dist, check_smoo
670  endif
671 end
672 
686 function normalize_strip_2d(strip, theta, [theta_offset, smooth_method, smooth_factor, check])
687  wave strip
688  wave theta
689  variable theta_offset
690  variable smooth_method
691  variable smooth_factor
692  variable check
693 
694  if (ParamIsDefault(check))
695  check = 0
696  endif
697  if (ParamIsDefault(theta_offset))
698  theta_offset = 0
699  endif
700  if (ParamIsDefault(smooth_method))
701  smooth_method = 4
702  endif
703  if (ParamIsDefault(smooth_factor))
704  smooth_factor = 0.5
705  endif
706 
707  variable nx = dimsize(strip, 0)
708  variable ny = dimsize(strip, 1)
709 
710  duplicate /free strip, dist, alpha_int, theta_int
711  MatrixFilter NanZapMedian dist
712  theta_int = theta[q] - theta_offset
713  alpha_int = dimoffset(strip, 0) + p * dimdelta(strip, 0)
714  redimension /n=(nx * ny) dist, alpha_int, theta_int
715 
716  switch(smooth_method)
717  case 4:
718  loess /dest=dist_smoo /smth=(smooth_factor) srcWave=dist, factors={alpha_int, theta_int}
719  redimension /n=(nx, ny) dist_smoo
720  break
721  default:
722  Abort "undefined smooth method"
723  break
724  endswitch
725 
726  // divide
727  if (check != 2)
728  strip /= dist_smoo
729  endif
730 
731  // check
732  if (check)
733  //duplicate /o dist, check_dist
734  duplicate /o dist_smoo, check_smoo
735  endif
736 end
737 
747 function crop_strip(strip, xlo, xhi)
748  wave strip
749  variable xlo
750  variable xhi
751 
752  variable plo = round((xlo - dimoffset(strip, 0)) / dimdelta(strip, 0))
753  variable phi = round((xhi - dimoffset(strip, 0)) / dimdelta(strip, 0))
754  xlo = plo * dimdelta(strip, 0) + dimoffset(strip, 0)
755  xhi = phi * dimdelta(strip, 0) + dimoffset(strip, 0)
756  variable nx = phi - plo + 1
757  variable ny = dimsize(strip, 1)
758 
759  duplicate /free strip, strip_copy
760  redimension /n=(nx,ny) strip
761  strip = strip_copy[p + plo][q]
762  setscale /i x xlo, xhi, waveunits(strip, 0), strip
763 end
764 
779 function crop_strip_theta(strip, theta_lo, theta_hi, theta, tilt, phi)
780  wave strip
781  variable theta_lo
782  variable theta_hi
783  wave theta
784  wave tilt
785  wave phi
786 
787  extract /indx /free theta, idx, (theta >= theta_lo) && (theta <= theta_hi)
788  variable nx = dimsize(strip, 0)
789  variable ny = numpnts(idx)
790 
791  theta[0, ny-1] = theta[idx]
792  tilt[0, ny-1] = tilt[idx]
793  phi[0, ny-1] = phi[idx]
794  redimension /n=(ny) theta, tilt, phi
795 
796  duplicate /free strip, strip_copy
797  redimension /n=(nx,ny) strip
798  strip = strip_copy[p][idx[q]]
799 end
800 
843 function pizza_service(data, nickname, theta_offset, tilt_offset, phi_offset, [npolar, nograph, folding, xpdplot])
844  wave data
845  string nickname
846  variable theta_offset
847  variable tilt_offset
848  variable phi_offset
849  variable npolar
850  variable nograph
851  variable folding
852  variable xpdplot
853 
854  if (ParamIsDefault(npolar))
855  npolar = 91
856  endif
857  if (ParamIsDefault(nograph))
858  nograph = 0
859  endif
860  if (ParamIsDefault(folding))
861  folding = 1
862  endif
863  if (ParamIsDefault(xpdplot))
864  xpdplot = 0
865  endif
866 
867  // sort out data folder structure
868  dfref saveDF = GetDataFolderDFR()
869  dfref dataDF = GetWavesDataFolderDFR(data)
870  setdatafolder dataDF
871  if (DataFolderExists(":attr"))
872  setdatafolder :attr
873  endif
874  dfref attrDF = GetDataFolderDFR()
875 
876  wave /sdfr=attrDF ManipulatorTheta
877  wave /sdfr=attrDF ManipulatorTilt
878  wave /sdfr=attrDF ManipulatorPhi
879 
880  if ((dimsize(ManipulatorTheta, 0) != dimsize(data, 1)) || (dimsize(ManipulatorTilt, 0) != dimsize(data, 1)) || (dimsize(ManipulatorPhi, 0) != dimsize(data, 1)))
881  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."
882  endif
883 
884  duplicate /free ManipulatorTheta, m_theta
885  duplicate /free ManipulatorTilt, m_tilt
886  duplicate /free ManipulatorPhi, m_phi
887 
888  m_theta -= theta_offset
889  m_tilt -= tilt_offset
890  m_phi -= phi_offset
891 
892  pizza_service_2(data, nickname, m_theta, m_tilt, m_phi, npolar=npolar, nograph=nograph, folding=folding, xpdplot=xpdplot)
893 
894  setdatafolder saveDF
895 end
896 
936 function pizza_service_2(data, nickname, m_theta, m_tilt, m_phi, [npolar, nograph, folding, xpdplot])
937  wave data
938  string nickname
939  wave m_theta
940  wave m_tilt
941  wave m_phi
942  variable npolar
943  variable nograph
944  variable folding
945  variable xpdplot
946 
947  if (ParamIsDefault(npolar))
948  npolar = 91
949  endif
950  if (ParamIsDefault(nograph))
951  nograph = 0
952  endif
953  if (ParamIsDefault(folding))
954  folding = 1
955  endif
956  if (ParamIsDefault(xpdplot))
957  xpdplot = 0
958  endif
959 
960  if ((dimsize(m_theta, 0) != dimsize(data, 1)) || (dimsize(m_tilt, 0) != dimsize(data, 1)) || (dimsize(m_phi, 0) != dimsize(data, 1)))
961  Abort "Warning: The dimension size of the manipulator waves does not match the Y dimension of the data wave!"
962  endif
963 
964  string graphname = "graph_" + nickname
965  string outprefix = nickname
966 
967  // sort out data folder structure
968  dfref saveDF = GetDataFolderDFR()
969  dfref dataDF = GetWavesDataFolderDFR(data)
970  setdatafolder dataDF
971 
972  if (xpdplot)
973  setdatafolder root:
974  outprefix = nickname
975  else
976  setdatafolder dataDF
977  newdatafolder /s/o $nickname
978  outprefix = ""
979  endif
980  dfref destDF = GetDataFolderDFR()
981 
982  // performance monitoring
983  variable timerRefNum
984  variable /g pol_perf_secs
985  timerRefNum = startMSTimer
986 
987  duplicate /free m_tilt, corr_tilt
988  duplicate /free m_phi, corr_phi
989  corr_tilt = -m_tilt // checked 140702
990  corr_phi = m_phi // checked 140702
991 
992  make /n=1/d/free d_polar, d_azi
993 
994  convert_angles_ttpd2polar(m_theta, corr_tilt, corr_phi, data, d_polar, d_azi)
995  d_azi += 180 // changed 151030 (v1.6)
996  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
997  variable ifold
998  for (ifold = 0; ifold < folding; ifold += 1)
999  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
1000  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
1001  d_azi += 360 / folding
1002  endfor
1003 
1004  // normalize folding
1005  if (strlen(outprefix))
1006  string s_prefix = outprefix + "_"
1007  string s_int = s_prefix + "i"
1008  else
1009  s_prefix = ""
1010  s_int = "values"
1011  endif
1012  if (folding > 1)
1013  wave values = $s_int
1014  values /= folding
1015  endif
1016 
1017  if (!nograph)
1018  display_hemi_scan(outprefix, graphname = graphname)
1019  endif
1020 
1021  if (timerRefNum >= 0)
1022  pol_perf_secs = stopMSTimer(timerRefNum) / 1e6
1023  endif
1024 
1025  setdatafolder saveDF
1026 end
1027 
1053 function show_analyser_line(theta, tilt, phi, theta_offset, tilt_offset, phi_offset, [npolar, nograph, xpdplot])
1054  variable theta
1055  variable tilt
1056  variable phi
1057  variable theta_offset
1058  variable tilt_offset
1059  variable phi_offset
1060  variable npolar
1061  variable nograph
1062  variable xpdplot
1063 
1064  string nickname = "analyser"
1065 
1066  if (ParamIsDefault(npolar))
1067  npolar = 91
1068  endif
1069  if (ParamIsDefault(nograph))
1070  nograph = 0
1071  endif
1072  if (ParamIsDefault(xpdplot))
1073  xpdplot = 0
1074  endif
1075  string graphname = "graph_" + nickname
1076  string outprefix = nickname
1077 
1078  // sort out data folder structure
1079  dfref saveDF = GetDataFolderDFR()
1080  dfref dataDF = saveDF
1081  if (xpdplot)
1082  setdatafolder root:
1083  outprefix = nickname
1084  else
1085  setdatafolder dataDF
1086  newdatafolder /s/o $nickname
1087  outprefix = ""
1088  endif
1089  dfref destDF = GetDataFolderDFR()
1090 
1091  make /n=1 /free m_theta
1092  make /n=1 /free m_tilt
1093  make /n=1 /free m_phi
1094  m_theta = theta - theta_offset
1095  m_tilt = tilt - tilt_offset
1096  m_tilt *= -1 // checked 140702
1097  m_phi = phi - phi_offset
1098  //m_phi *= -1 // checked 140702
1099 
1100  make /n=60 /free data
1101  setscale /i x -30, 30, data
1102  data = x
1103  make /n=1/d/free d_polar, d_azi
1104 
1105  convert_angles_ttpa2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
1106  d_azi += 180 // changed 151030 (v1.6)
1107  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
1108  make_hemi_grid(npolar, outprefix, xpdplot=xpdplot)
1109  hemi_add_anglescan(outprefix, data, d_polar, d_azi)
1110 
1111  if (!nograph)
1112  display_hemi_scan(outprefix, graphname = graphname)
1113  endif
1114 
1115  setdatafolder saveDF
1116 end
1117 
1122 
1123 function convert_angles_ttpd2polar(theta, tilt, phi, data, polar, azi)
1124  wave theta, tilt, phi // see convert_angles_ttpa2polar
1125  wave data // in, 1D or 2D
1126  // X-scale must be set to analyser angle scale
1127  wave polar, azi // see convert_angles_ttpa2polar
1128 
1129  make /n=(dimsize(data, 0)) /d /free ana
1130  setscale /p x dimoffset(data, 0), dimdelta(data, 0), waveunits(data, 0), ana
1131  ana = x
1132  convert_angles_ttpa2polar(theta, tilt, phi, ana, polar, azi)
1133 end
1134 
1162 function convert_angles_ttpa2polar(theta, tilt, phi, analyser, polar, azi)
1163  wave theta
1164  wave tilt
1165  wave phi
1166  wave analyser
1167  wave polar, azi
1168 
1169  variable nn = numpnts(theta)
1170  variable na = numpnts(analyser)
1171  redimension /n=(na, nn) polar, azi
1172 
1173  variable radius = 1 // don't need to specify - everything is scalable
1174 
1175  // step 1: calculate cartesian detection vectors at normal emission
1176  // this is simply a polar-cartesian mapping, independent of the manipulator
1177  // phi=0 is in the polar rotation plane
1178  make /n=(3,na) /d /free w_orig_polar, w_orig_cart, w_rot_cart, w_rot_polar
1179  w_orig_polar[0][] = radius
1180  w_orig_polar[1][] = analyser[q]
1181  w_orig_polar[2][] = 0
1182  polar2cart_wave(w_orig_polar, w_orig_cart)
1183  // if the angle-dispersive axis was horizontal, we'd need to rotate the detector
1184  //rotate_z_wave(w_orig_cart, 90)
1185 
1186  variable ii
1187  for (ii = 0; ii < nn; ii += 1)
1188  // step 2: rotate the detection vectors according to the manipulator angles
1189  // the order of rotations is important because we rotate about fixed axes
1190  // y-axis = tilt rotation axis
1191  // x-axis = polar rotation axis
1192  // z-axis = normal emission = azimuthal rotation axis
1193  w_rot_cart = w_orig_cart
1194  rotate_y_wave(w_rot_cart, -tilt[ii])
1195  rotate_x_wave(w_rot_cart, -theta[ii])
1196  rotate_z_wave(w_rot_cart, -phi[ii] - 90)
1197  // map the vectors back to the sample coordinate system
1198  cart2polar_wave(w_rot_cart, w_rot_polar)
1199  // copy to output
1200  polar[][ii] = w_rot_polar[1][p]
1201  azi[][ii] = w_rot_polar[2][p]
1202  endfor
1203 end
1204 
1205 static function line_average(source, dest)
1206  // is this function used?
1207  wave source
1208  wave dest
1209 
1210  variable ii
1211  variable nn = dimsize(source, 1)
1212  make /n=(dimsize(source, 0))/d/free line
1213  for (ii = 0; ii < nn; ii += 1)
1214  line = source[p][ii]
1215  wavestats /q line
1216  dest[][ii] = line[p] / v_max
1217  endfor
1218 end
1219 
1223 static function calc_nth(Theta_st, Theta_in, th, Phi_ran, Phi_ref, Holomode)
1224  Variable Theta_st, Theta_in, th, Phi_ran, Phi_ref
1225  String Holomode
1226  Variable The_step
1227  Variable deg2rad=0.01745329
1228 
1229  if ( cmpstr(Holomode, "Stereographic") == 0)
1230  The_step =trunc( Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st )
1231  if(th==90)
1232  The_step =trunc( Phi_ran*sin(th*pi/180)*Phi_ref/Theta_st )
1233  endif
1234  else
1235  if (cmpstr(Holomode, "Parallel") == 0)
1236  The_step=trunc( Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st )
1237  else
1238  if ( cmpstr(Holomode, "h") == 0)
1239  The_step=trunc( th/Theta_in*Phi_ran/Theta_st )
1240  else
1241  //altro
1242  endif
1243  endif
1244  endif
1245 
1246  return(The_step)
1247 end
1248 
1252 static function calc_phi_step(Theta_in, th, Theta_st, Phi_ran, Phi_ref, Holomode)
1253  Variable Theta_in, th, Theta_st, Phi_ran, Phi_ref
1254  String Holomode
1255 
1256  Variable Phi_st
1257  Variable deg2rad=0.01745329
1258 
1259  if ( cmpstr(Holomode, "Stereographic") == 0 )
1260  if ((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
1261  Phi_st=0.0
1262  else
1263  Phi_st=Phi_ran/(trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st))
1264  endif
1265  if(th==90)
1266  Phi_st=2.0
1267  endif
1268  endif
1269 
1270  if ( cmpstr(Holomode, "Parallel") == 0 )
1271  if((th < 0.5) || (trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st) == 0))
1272  Phi_st=0.0
1273  else
1274  Phi_st=Phi_ran/(trunc(Phi_ran*tan(th*deg2rad)*Phi_ref/Theta_st))
1275  endif
1276  endif
1277 
1278  if ( cmpstr(Holomode, "h") == 0 )
1279  if((th < 0.5) || (trunc(Phi_ran*sin(th*deg2rad)*Phi_ref/Theta_st) == 0))
1280  Phi_st=0.0
1281  else
1282  Phi_st=Phi_ran/trunc(th/Theta_in*Phi_ran/Theta_st)
1283  endif
1284  endif
1285 
1286  if (Phi_st==0)
1287  Phi_st=360
1288  endif
1289 
1290  return(Phi_st)
1291 end
1292 
1296 static function Calc_The_step(th, Theta_st, Holomode)
1297  String Holomode
1298  Variable th, Theta_st
1299 
1300  Variable deg2rad=0.01745329, dt_loc,The_step
1301 
1302  if ( (cmpstr(Holomode, "Stereographic")) ==0 )
1303  The_step=Theta_st
1304  endif
1305 
1306  if ( (cmpstr(Holomode, "h")) ==0 )
1307  The_step=Theta_st
1308  endif
1309 
1310  if ( cmpstr(Holomode, "Parallel") == 0 )
1311  if(th < 89.5)
1312  dt_loc = Theta_st/cos(th*deg2rad)
1313  if(dt_loc > 10)
1314  dt_loc=10
1315  endif
1316  The_step=dt_loc
1317  else
1318  The_step=10
1319  endif
1320  endif
1321  return(The_step)
1322 end
1323 
1327 static function CalcN_Theta(HoloMode,Theta_in,Theta_ran,Theta_st)
1328  String HoloMode
1329  Variable Theta_in,Theta_ran,Theta_st
1330  Variable n_theta, aux, aux1,ii
1331 
1332  aux = Theta_in
1333  aux1= Theta_in - Theta_ran
1334  ii = 0
1335  do
1336  aux = aux - Calc_The_step(aux, Theta_st, HoloMode)
1337  if(aux<=Theta_in-Theta_ran)
1338  aux=Theta_in-Theta_ran
1339  endif
1340  ii = ii+1
1341  while((aux>aux1)%&(Theta_in-aux<=Theta_ran)) //
1342  n_theta=ii+1
1343  Return(n_theta)
1344 end
1345 
1365 function make_hemi_grid(npol, nickname, [xpdplot])
1366  variable npol
1367  string nickname
1368  variable xpdplot
1369 
1370  if (ParamIsDefault(xpdplot))
1371  xpdplot = 0
1372  endif
1373 
1374  string HoloMode = "h"
1375  variable Theta_in = 90
1376  variable Theta_ran = 90
1377  variable Theta_st = 90 / (npol - 1)
1378  variable Phi_ran = 360
1379  variable Phi_ref = 1
1380  variable Phi_in = 0
1381 
1382  variable n_theta = CalcN_Theta(HoloMode, Theta_in, Theta_ran, Theta_st)
1383 
1384  // wave names
1385  if (strlen(nickname))
1386  string s_prefix = nickname + "_"
1387  string s_int = s_prefix + "i" // Intensity wave (counts/sec)
1388  else
1389  s_prefix = ""
1390  s_int = "values" // "i" is not a valid wave name
1391  endif
1392  string s_polar = s_prefix + "pol" // thetas for each int-point of the holo
1393  string s_azim = s_prefix + "az" // phis for each int-point of the holo
1394 
1395  string s_index = s_prefix + "index" // starting index for each theta
1396  string s_theta = s_prefix + "th" // theta values
1397  string s_dphi = s_prefix + "dphi" // delta phis at each theta
1398  string s_nphis = s_prefix + "nphis" // number of phis at each theta
1399 
1400  string s_HoloData = s_prefix + "data" // All holo exp.- parameter information
1401  string s_HoloInfo = s_prefix + "info"
1402 
1403  // the following two waves are used by the pearl-anglescan procedures but not by XPDplot
1404  string s_tot = s_prefix + "tot" // accumulated counts at each point
1405  string s_weight = s_prefix + "wt" // total accumulation time at each point (arb. units)
1406 
1407  make /O/D/n=(n_theta) $s_index /wave=index
1408  make /O/D/n=(n_theta) $s_theta /wave=theta
1409  make /O/D/n=(n_theta) $s_dphi /wave=dphi
1410  make /O/D/n=(n_theta) $s_nphis /wave=nphis
1411 
1412  //---------- calculate phi-step-size for this theta:
1413  variable aux = Calc_The_step(Theta_in, Theta_st, HoloMode)
1414  dphi[0] = calc_phi_step(Theta_in, Theta_in, aux, Phi_ran, Phi_ref, HoloMode)
1415  Theta[0] = Theta_in
1416  nphis[0] = calc_nth(aux, Theta_in, Theta_in, Phi_ran, Phi_ref, HoloMode)
1417  Index[0] = nphis[0]
1418 
1419  //---------- calculate number of phis, phi-step, and starting-index for each theta:
1420  variable ii = 1
1421  do
1422  Theta[ii] = Theta[ii-1] - aux
1423  if(Theta[ii] <= Theta_in-Theta_ran)
1424  Theta[ii] = Theta_in-Theta_ran
1425  endif
1426  aux = Calc_The_step(Theta[ii], Theta_st, HoloMode)
1427  dphi[ii] = calc_phi_step(Theta_in, Theta[ii], aux, Phi_ran, Phi_ref, HoloMode)
1428  nphis[ii] = calc_nth(aux, Theta_in, Theta[ii], Phi_ran, Phi_ref, HoloMode)
1429  Index[ii] = Index[ii-1] + nphis[ii]
1430  ii=ii+1
1431  while(ii < n_theta)
1432 
1433  if (Index[n_theta-1]==Index[n_theta-2])
1434  Index[n_theta-1]=Index[n_theta-2]+1
1435  nphis[n_theta-1]=1
1436  endif
1437 
1438  variable NumPoints = sum(nphis, 0, numpnts(nphis))
1439 
1440  //---------- calculate theta and phi for each data point:
1441  make /O/D/N=(NumPoints) $s_polar /wave=polar, $s_azim /wave=azim
1442  note azim, "version=1.6"
1443 
1444  ii = 0
1445  variable StartIndex = 0
1446  variable EndIndex
1447  do
1448  EndIndex=Index[ii]
1449  Polar[StartIndex, EndIndex-1]=Theta[ii]
1450  Azim[StartIndex, EndIndex-1]= mod(Phi_ran+(x-StartIndex)*dphi[ii]+Phi_in,Phi_ran)
1451  ii = ii + 1
1452  StartIndex = EndIndex
1453  while(ii < n_theta)
1454 
1455  duplicate /o azim, $s_int /wave=values
1456  duplicate /o azim, $s_tot /wave=totals
1457  duplicate /o azim, $s_weight /wave=weights
1458  values = nan
1459  totals = 0
1460  weights = 0
1461 
1462  // XPDplot metadata
1463  if (xpdplot)
1464  string s_FileName = ""
1465  string s_Comment = "created by pearl-anglescan-process.ipf"
1466  string s_HoloMode = "Stereographic"
1467  variable /g gb_SpectraFile = 0
1468 
1469  Make/O/D/n=22 $s_HoloData /wave=HoloData
1470  HoloData[0] = NaN // v_StartKE
1471  HoloData[1] = NaN // v_StoppKE
1472  HoloData[6] = NumPoints
1473  HoloData[7] = Theta_in
1474  HoloData[8] = Theta_ran
1475  HoloData[9] = Theta_st
1476  HoloData[11] = Phi_in
1477  HoloData[12] = Phi_ran
1478  HoloData[13] = Theta_st
1479  HoloData[15] = Phi_ref
1480  HoloData[16] = Phi_ran
1481  HoloData[17] = 0 // v_HoloBit (stereographic)
1482 
1483  Make/O/T/n=22 $s_HoloInfo /wave=HoloInfo
1484  HoloInfo[0] = s_FileName
1485  HoloInfo[1] = s_Comment
1486  HoloInfo[10] = s_HoloMode
1487  HoloInfo[11] = "" // s_MeasuringMode
1488 
1489  // notebook for XPDplot
1490  if (WinType(NickName) == 5)
1491  Notebook $NickName selection={startOfFile, endOfFile}
1492  Notebook $NickName text=""
1493  else
1494  NewNotebook /F=0 /K=1 /N=$NickName /W=(5,40,341,260)
1495  Notebook $NickName defaultTab=140
1496  Notebook $NickName statusWidth=300
1497  Notebook $NickName backRGB=(56797,56797,56797)
1498  Notebook $NickName pageMargins={80,80,80,80}
1499  Notebook $NickName fSize=10
1500  Notebook $NickName fStyle=0,textRGB=(65535,0,26214)
1501  Notebook $NickName textRGB=(65535,0,26214)
1502  endif
1503  Notebook $NickName text = "File:\t" + s_FileName + "\r"
1504  Notebook $NickName text = "*** " + s_Comment + " ***\r\r"
1505  Notebook $NickName text = "Angle-Mode:\t" + s_HoloMode + "\r"
1506  Notebook $NickName text = "XPDplot Nickname:\t" + NickName + "\r"
1507  endif
1508 end
1509 
1516 function /s get_hemi_nickname(w)
1517  wave w
1518 
1519  string prefix = get_hemi_prefix(w)
1520  string wname = nameofwave(w)
1521  string nickname
1522 
1523  if (strlen(prefix))
1524  nickname = prefix
1525  else
1526  string s_wave_df = GetWavesDataFolder(w, 1)
1527  dfref parent_df = $(s_wave_df + "::")
1528  nickname = GetDataFolder(0, parent_df)
1529  endif
1530 
1531  return nickname
1532 end
1533 
1541 function /s get_hemi_prefix(w)
1542  wave w
1543 
1544  string wname = nameofwave(w)
1545  string prefix
1546  if (ItemsInList(wname, "_") >= 2)
1547  prefix = StringFromList(0, wname, "_")
1548  else
1549  prefix = ""
1550  endif
1551 
1552  return prefix
1553 end
1554 
1572 function /df find_hemi_data(nickname, prefix, intwave)
1573  string nickname
1574  string &prefix
1575  string &intwave
1576 
1577  dfref datadf
1578  prefix = ""
1579  intwave = "values"
1580  if (strlen(nickname))
1581  if (DataFolderExists(nickname))
1582  datadf = $nickname
1583  else
1584  datadf = getdatafolderdfr()
1585  prefix = nickname + "_"
1586  intwave = prefix + "i"
1587  if (exists(intwave) != 1)
1588  datadf = root:
1589  endif
1590  endif
1591  else
1592  datadf = getdatafolderdfr()
1593  prefix = ""
1594  intwave = "values"
1595  endif
1596  return datadf
1597 end
1598 
1606 function clear_hemi_grid(nickname)
1607  string nickname
1608 
1609  dfref datadf
1610  string s_prefix
1611  string s_int
1612  datadf = find_hemi_data(nickname, s_prefix, s_int)
1613 
1614  string s_totals = s_prefix + "tot"
1615  string s_weights = s_prefix + "wt"
1616 
1617  wave /sdfr=datadf /z w_values = $s_int
1618  wave /sdfr=datadf /z w_totals = $s_totals
1619  wave /sdfr=datadf /z w_weights = $s_weights
1620 
1621  if (waveexists(w_totals))
1622  w_totals = 0
1623  endif
1624  if (waveexists(w_weights))
1625  w_weights = 0
1626  endif
1627  if (waveexists(w_values))
1628  w_values = nan
1629  endif
1630 end
1631 
1653 function duplicate_hemi_scan(source_nickname, dest_folder, dest_nickname, [xpdplot])
1654  string source_nickname
1655  dfref dest_folder
1656  string dest_nickname
1657  variable xpdplot
1658 
1659  if (ParamIsDefault(xpdplot))
1660  xpdplot = 0
1661  endif
1662 
1663  dfref savedf = getdatafolderdfr()
1664 
1665  // source data
1666  string s_prefix = ""
1667  string s_int = "values"
1668  dfref source_df = find_hemi_data(source_nickname, s_prefix, s_int)
1669  string s_polar = s_prefix + "pol"
1670  string s_azim = s_prefix + "az"
1671  string s_theta = s_prefix + "th"
1672  string s_tot = s_prefix + "tot"
1673  string s_weight = s_prefix + "wt"
1674  string s_matrix = s_prefix + "matrix"
1675 
1676  wave /sdfr=source_df theta1 = $s_theta
1677  wave /sdfr=source_df polar1 = $s_polar
1678  wave /sdfr=source_df azim1 = $s_azim
1679  wave /sdfr=source_df tot1 = $s_tot
1680  wave /sdfr=source_df weight1 = $s_weight
1681  wave /sdfr=source_df values1 = $s_int
1682  wave /sdfr=source_df /z matrix1 = $s_matrix
1683 
1684  variable npol = numpnts(theta1)
1685 
1686  setdatafolder dest_folder
1687  make_hemi_grid(npol, dest_nickname, xpdplot=xpdplot)
1688 
1689  // dest data
1690  dfref dest_df = find_hemi_data(dest_nickname, s_prefix, s_int)
1691  s_polar = s_prefix + "pol"
1692  s_azim = s_prefix + "az"
1693  s_theta = s_prefix + "th"
1694  s_tot = s_prefix + "tot"
1695  s_weight = s_prefix + "wt"
1696  s_matrix = s_prefix + "matrix"
1697 
1698  wave /sdfr=dest_df theta2 = $s_theta
1699  wave /sdfr=dest_df polar2 = $s_polar
1700  wave /sdfr=dest_df azim2 = $s_azim
1701  wave /sdfr=dest_df tot2 = $s_tot
1702  wave /sdfr=dest_df weight2 = $s_weight
1703  wave /sdfr=dest_df values2 = $s_int
1704 
1705  tot2 = tot1
1706  weight2 = weight1
1707  values2 = values1
1708  if (waveexists(matrix1))
1709  setdatafolder dest_df
1710  duplicate /o matrix1, $s_matrix
1711  endif
1712 
1713  if (!(NumberByKey("version", note(azim1), "=", "\r") >= 1.6))
1714  azim2 += 180 // changed 151030 (v1.6)
1715  azim2 = azim2 >= 360 ? azim2 - 360 : azim2
1716  endif
1717 
1718  setdatafolder saveDF
1719 end
1720 
1728 function rotate_hemi_scan(nickname, angle)
1729  string nickname
1730  variable angle
1731 
1732  dfref savedf = getdatafolderdfr()
1733 
1734  string s_prefix = ""
1735  string s_int = "values"
1736  dfref df = find_hemi_data(nickname, s_prefix, s_int)
1737 
1738  string s_polar = s_prefix + "pol"
1739  string s_azim = s_prefix + "az"
1740  string s_tot = s_prefix + "tot"
1741  string s_weight = s_prefix + "wt"
1742 
1743  wave /sdfr=df polar = $s_polar
1744  wave /sdfr=df azim = $s_azim
1745  wave /sdfr=df tot = $s_tot
1746  wave /sdfr=df weight = $s_weight
1747  wave /sdfr=df values = $s_int
1748 
1749  azim += angle
1750  azim = azim < 0 ? azim + 360 : azim
1751  azim = azim >= 360 ? azim - 360 : azim
1752 
1753  duplicate /free polar, neg_polar
1754  neg_polar = -polar
1755  sort {neg_polar, azim}, polar, azim, tot, weight, values
1756 
1757  setdatafolder saveDF
1758 end
1759 
1776 function /s prepare_hemi_scan_display(nickname, [projection])
1777  string nickname
1778  variable projection
1779 
1780  dfref savedf = getdatafolderdfr()
1781 
1782  if (ParamIsDefault(projection))
1783  projection = 1
1784  endif
1785 
1786  // hemi grid waves
1787  string s_prefix = ""
1788  string s_int = "values"
1789  dfref df = find_hemi_data(nickname, s_prefix, s_int)
1790 
1791  string s_polar = s_prefix + "pol"
1792  string s_azim = s_prefix + "az"
1793 
1794  wave /sdfr=df /z values = $s_int
1795  wave /sdfr=df /z azim = $s_azim
1796  wave /sdfr=df /z polar = $s_polar
1797 
1798  setdatafolder df
1799  string s_ster_rad = s_prefix + "ster_rad"
1800  duplicate /o polar, $s_ster_rad /wave=ster_rad
1801  ster_rad = calc_graph_radius(polar, projection=projection)
1802 
1803  string s_ster_x = s_prefix + "ster_x"
1804  string s_ster_y = s_prefix + "ster_y"
1805  duplicate /o azim, $s_ster_x /wave=ster_x, $s_ster_y /wave=ster_y
1806  ster_x = ster_rad * cos(azim * pi / 180)
1807  ster_y = ster_rad * sin(azim * pi / 180)
1808 
1809  setdatafolder savedf
1810 end
1811 
1858 function /s display_hemi_scan(nickname, [projection, graphtype, do_ticks, do_grids, graphname])
1859  string nickname
1860  variable projection
1861  variable graphtype
1862  variable do_ticks
1863  variable do_grids
1864  string graphname
1865 
1866  dfref savedf = getdatafolderdfr()
1867 
1868  if (ParamIsDefault(projection))
1869  projection = 1
1870  endif
1871  if (ParamIsDefault(graphtype))
1872  graphtype = 1
1873  endif
1874  if (ParamIsDefault(do_ticks))
1875  do_ticks = 3
1876  endif
1877  if (ParamIsDefault(do_grids))
1878  do_grids = 3
1879  endif
1880  if (ParamIsDefault(graphname))
1881  if (strlen(nickname) > 0)
1882  graphname = nickname
1883  else
1884  graphname = GetDataFolder(0)
1885  endif
1886  endif
1887 
1888  prepare_hemi_scan_display(nickname, projection=projection)
1889 
1890  // hemi grid waves
1891  string s_prefix = ""
1892  string s_int = "values"
1893  dfref df = find_hemi_data(nickname, s_prefix, s_int)
1894 
1895  string s_polar = s_prefix + "pol"
1896  string s_azim = s_prefix + "az"
1897  string s_matrix = s_prefix + "matrix"
1898  string s_ster_rad = s_prefix + "ster_rad"
1899 
1900  wave /sdfr=df /z values = $s_int
1901  wave /sdfr=df /z azim = $s_azim
1902  wave /sdfr=df /z polar = $s_polar
1903  wave /sdfr=df /z ster_rad = $s_ster_rad
1904  wave /sdfr=df /z matrix = $s_matrix
1905 
1906  setdatafolder df
1907  variable azim_offset = 0
1908  if (!(NumberByKey("version", note(azim), "=", "\r") >= 1.6))
1909  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!"
1910  azim_offset = 180 // changed 151030 (v1.6)
1911  endif
1912 
1913  string s_trace
1914  DoWindow $graphname
1915  if (v_flag)
1916  if (str2num(GetUserData(graphname, "", "graphtype")) == graphtype)
1917  // graph exists and will update automatically - do not recreate
1918  graphtype = 0
1919  else
1920  // graph exists - but needs recreating
1921  killwindow $graphname
1922  endif
1923  endif
1924 
1925  switch(graphtype)
1926  case 1:
1927  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1928 
1929  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1930  ModifyGraph /W=$graphname mode($s_trace)=2, lsize($s_trace)=2
1931  ModifyGraph /W=$graphname zColor($s_trace)={values,*,*,BlueGreenOrange,0}
1932 
1933  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 trace=polarY0
1934  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1935  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1936 
1937  SetWindow $graphname, userdata(projection)=num2str(projection)
1938  SetWindow $graphname, userdata(graphtype)=num2str(graphtype)
1939  draw_hemi_axes(graphname, do_grids=do_grids)
1940  break
1941  case 3:
1942  graphname = display_polar_graph(graphname, angle_offset=azim_offset, do_ticks=do_ticks)
1943 
1944  s_trace = WMPolarAppendTrace(graphname, ster_rad, azim, 360)
1945  ModifyGraph /W=$graphname mode($s_trace)=0, lsize($s_trace)=0
1946  AppendImage /L=VertCrossing /B=HorizCrossing matrix
1947 
1948  ColorScale /W=$graphname /C /N=text0 /E=2 /F=0 /B=1 /A=RB /X=0.00 /Y=0.00 image=$s_matrix
1949  ColorScale /W=$graphname /C /N=text0 side=2, width=5, heightPct=40, frame=0.50, lblMargin=0
1950  ColorScale /W=$graphname /C /N=text0 nticks=2, minor=1, tickLen=4.00, tickThick=0.50
1951 
1952  SetWindow $graphname, userdata(projection)=num2str(projection)
1953  SetWindow $graphname, userdata(graphtype)=num2str(graphtype)
1954  draw_hemi_axes(graphname, do_grids=do_grids)
1955  break
1956  endswitch
1957 
1958  setdatafolder savedf
1959  return graphname
1960 end
1961 
2003 static function /s display_polar_graph(graphname, [angle_offset, do_ticks])
2004 
2005  string graphname
2006  variable angle_offset
2007  variable do_ticks
2008 
2009  dfref savedf = GetDataFolderDFR()
2010 
2011  if (ParamIsDefault(angle_offset))
2012  angle_offset = 0
2013  endif
2014  if (ParamIsDefault(do_ticks))
2015  do_ticks = 3
2016  endif
2017 
2018  if ((strlen(graphname) == 0) || (wintype(graphname) == 0))
2019  Display /k=1 /W=(10,45,360,345)
2020  DoWindow /C $graphname
2021  graphname = WMNewPolarGraph("", graphname)
2022  WMPolarGraphSetVar(graphname, "zeroAngleWhere", angle_offset)
2023 
2024  WMPolarGraphSetVar(graphname, "angleAxisThick", 0.5)
2025  WMPolarGraphSetStr(graphname, "doMajorAngleTicks", "manual")
2026  WMPolarGraphSetVar(graphname, "majorAngleInc", 30) // major ticks in 30 deg steps
2027  WMPolarGraphSetVar(graphname, "minorAngleTicks", 2) // minor ticks in 10 deg steps
2028  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
2029  WMPolarGraphSetVar(graphname, "doAngleTickLabelSubRange", 1)
2030  WMPolarGraphSetVar(graphname, "angleTickLabelRangeStart", 0)
2031  WMPolarGraphSetVar(graphname, "angleTickLabelRangeExtent", 90)
2032  WMPolarGraphSetStr(graphname, "angleTickLabelNotation", "%g°")
2033 
2034  WMPolarGraphSetVar(graphname, "doPolarGrids", 0)
2035  WMPolarGraphSetVar(graphname, "doRadiusTickLabels", 0)
2036  WMPolarGraphSetStr(graphname, "radiusAxesWhere", " Off") // note the leading spaces, cf. WMPolarAnglesForRadiusAxes
2037  WMPolarGraphSetStr(graphname, "radiusTicksLocation", "Off")
2038 
2039  WMPolarGraphSetVar(graphname, "majorTickLength", 2)
2040  WMPolarGraphSetVar(graphname, "majorTickThick", 0.5)
2041  WMPolarGraphSetVar(graphname, "minorTickLength", 1)
2042  WMPolarGraphSetVar(graphname, "minorTickThick", 0.5)
2043  WMPolarGraphSetVar(graphname, "tickLabelOpaque", 0)
2044  WMPolarGraphSetVar(graphname, "tickLabelFontSize", 7)
2045 
2046  // changes
2047  if (do_ticks & 1)
2048  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Outside")
2049  else
2050  WMPolarGraphSetStr(graphname, "angleTicksLocation", "Off")
2051  endif
2052  if (do_ticks & 2)
2053  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 1)
2054  else
2055  WMPolarGraphSetVar(graphname, "doMinorAngleTicks", 0)
2056  endif
2057 
2058  DoWindow /T $graphname, graphname
2059 
2060  // cursor info in angles
2061  string graphdf = "root:packages:WMPolarGraphs:" + graphname
2062  setdatafolder graphdf
2063  // current theta, phi coordinates are stored in global variables in the package folder of the graph
2064  variable /g csrA_theta
2065  variable /g csrA_phi
2066  variable /g csrB_theta
2067  variable /g csrB_phi
2068  // the text box is hidden initially. it shows up and hides with the cursor info box.
2069  string tb
2070  tb = "\\{"
2071  tb = tb + "\"A = (%.1f, %.1f)\","
2072  tb = tb + graphdf + ":csrA_theta,"
2073  tb = tb + graphdf + ":csrA_phi"
2074  tb = tb + "}"
2075  TextBox /W=$graphname /A=LT /B=1 /E=2 /F=0 /N=tb_angles /X=1 /Y=1 /V=0 tb
2076  tb = "\\{"
2077  tb = tb + "\"B = (%.1f, %.1f)\","
2078  tb = tb + graphdf + ":csrB_theta,"
2079  tb = tb + graphdf + ":csrB_phi"
2080  tb = tb + "}"
2081  AppendText /W=$graphname /N=tb_angles tb
2082  // updates are triggered by a window hook
2083  SetWindow $graphname, hook(polar_graph_hook)=PearlAnglescanProcess#polar_graph_hook
2084  else
2085  // graph window exists
2086  DoWindow /F $graphname
2087  endif
2088 
2089  setdatafolder savedf
2090  return graphname
2091 end
2092 
2118 static function /s draw_hemi_axes(graphname, [do_grids])
2119  string graphname
2120  variable do_grids
2121 
2122  if (ParamIsDefault(do_grids))
2123  do_grids = 3
2124  endif
2125 
2126  dfref savedf = GetDataFolderDFR()
2127 
2128  string sproj = GetUserData(graphname, "", "projection")
2129  variable projection = str2num("0" + sproj)
2130 
2131  SetDrawLayer /W=$graphname ProgFront
2132 
2133  // polar axis
2134  SetDrawEnv /W=$graphname xcoord=HorizCrossing, ycoord=VertCrossing
2135  SetDrawEnv /W=$graphname linethick= 0.5
2136  SetDrawEnv /W=$graphname dash=2
2137  SetDrawEnv /W=$graphname fillpat=0
2138  SetDrawEnv /W=$graphname fname="default", fsize=7
2139  SetDrawEnv /W=$graphname textxjust=1, textyjust=1
2140  //SetDrawEnv /W=$graphname linefgc=(65535,65535,65535)
2141  SetDrawEnv /W=$graphname save
2142 
2143  if (do_grids & 1)
2144  DrawLine /W=$graphname 0, -2, 0, 2
2145  DrawLine /W=$graphname -2, 0, 2, 0
2146  endif
2147 
2148  variable radi
2149  if (do_grids & 2)
2150  radi = calc_graph_radius(0.5, projection=projection)
2151  DrawOval /W=$graphname -radi, radi, radi, -radi
2152  radi = calc_graph_radius(30, projection=projection)
2153  DrawOval /W=$graphname -radi, radi, radi, -radi
2154  radi = calc_graph_radius(60, projection=projection)
2155  DrawOval /W=$graphname -radi, radi, radi, -radi
2156 
2157  SetDrawEnv /W=$graphname textxjust= 1,textyjust= 2
2158  SetDrawEnv /W=$graphname save
2159  radi = calc_graph_radius(30, projection=projection)
2160  DrawText /W=$graphname radi, -0.1, "30°"
2161  radi = calc_graph_radius(60, projection=projection)
2162  DrawText /W=$graphname radi, -0.1, "60°"
2163  endif
2164 
2165  setdatafolder savedf
2166 end
2167 
2190 function draw_diffraction_cone(graphname, groupname, theta_axis, theta_inner, phi)
2191  string graphname
2192  string groupname
2193 
2194  variable theta_axis
2195  variable theta_inner
2196  variable phi
2197 
2198  variable r_axis = calc_graph_radius(theta_axis)
2199  variable r_inner = calc_graph_radius(theta_inner)
2200  variable r_outer = calc_graph_radius(2 * theta_axis - theta_inner)
2201 
2202  SetDrawEnv push
2203  SetDrawLayer UserFront
2204  DrawAction getgroup=$groupname, delete
2205  SetDrawEnv gstart, gname=$groupname
2206  variable xc, yc, xr, yr
2207 
2208  // cone periphery
2209  variable r_center = (r_outer + r_inner) / 2
2210  variable r_radius = (r_outer - r_inner) / 2
2211  xc = r_center * cos(phi * pi / 180)
2212  yc = r_center * sin(phi * pi / 180)
2213  xr = r_radius
2214  yr = r_radius
2215  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
2216  SetDrawEnv dash=11, fillpat=0
2217  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
2218 
2219  // cone axis
2220  xc = r_axis * cos(phi * pi / 180)
2221  yc = r_axis * sin(phi * pi / 180)
2222  r_radius = calc_graph_radius(2)
2223  xr = r_radius
2224  yr = r_radius
2225  SetDrawEnv xcoord=HorizCrossing, ycoord=VertCrossing
2226  SetDrawEnv fillfgc=(0,0,0)
2227  DrawOval xc - xr, yc - yr, xc + xr, yc + yr
2228 
2229  SetDrawEnv gstop
2230  SetDrawEnv pop
2231 end
2232 
2254 function /s display_scanlines(nickname, alpha_lo, alpha_hi, m_theta, m_tilt, m_phi, [folding, projection])
2255  string nickname
2256  variable alpha_lo
2257  variable alpha_hi
2258  wave m_theta
2259  wave m_tilt
2260  wave m_phi
2261  variable folding
2262  variable projection
2263 
2264  if (ParamIsDefault(folding))
2265  folding = 1
2266  endif
2267  if (ParamIsDefault(projection))
2268  projection = 1
2269  endif
2270 
2271  // sort out data folder structure
2272  dfref saveDF = GetDataFolderDFR()
2273  newdatafolder /s/o $nickname
2274  string graphname = "graph_" + nickname
2275 
2276  duplicate /free m_tilt, loc_m_tilt
2277  loc_m_tilt = -m_tilt
2278 
2279  make /n=1 /d /free d_polar, d_azi
2280  variable n_alpha = round(alpha_hi - alpha_lo) + 1
2281  make /n=(n_alpha) /d /free analyser
2282  setscale /i x alpha_lo, alpha_hi, "°", analyser
2283  analyser = x
2284 
2285  convert_angles_ttpa2polar(m_theta, loc_m_tilt, m_phi, analyser, d_polar, d_azi)
2286  duplicate /free d_polar, d_radius
2287  d_radius = calc_graph_radius(d_polar, projection=projection)
2288  d_azi += 180 // changed 151030 (v1.6)
2289 
2290  graphname = display_polar_graph(graphname)
2291  SetWindow $graphname, userdata(projection)=num2str(projection)
2292 
2293  variable ifold
2294  variable iang
2295  variable nang = numpnts(m_theta)
2296  string s_rad
2297  string s_azi
2298  string s_trace
2299  for (ifold = 0; ifold < folding; ifold += 1)
2300  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
2301  for (iang = 0; iang < nang; iang += 1)
2302  sprintf s_rad, "rad_%d_%d", ifold, iang
2303  duplicate /o analyser, $s_rad
2304  wave w_rad = $s_rad
2305  w_rad = d_radius[p][iang]
2306 
2307  sprintf s_azi, "azi_%d_%d", ifold, iang
2308  duplicate /o analyser, $s_azi
2309  wave w_azi = $s_azi
2310  w_azi = d_azi[p][iang]
2311 
2312  if (numtype(sum(w_rad)) == 0)
2313  s_trace = WMPolarAppendTrace(graphname, w_rad, w_azi, 360)
2314  ModifyGraph /w=$graphname mode($s_trace)=0, lsize($s_trace)=0.5
2315  endif
2316  endfor
2317  d_azi += 360 / folding
2318  endfor
2319 
2320  draw_hemi_axes(graphname)
2321 
2322  setdatafolder saveDF
2323  return graphname
2324 end
2325 
2342 constant kProjDist = 0
2343 constant kProjStereo = 1
2344 constant kProjArea = 2
2345 constant kProjGnom = 3
2346 constant kProjOrtho = 4
2347 
2348 static constant kProjScaleDist = 2
2349 static constant kProjScaleStereo = 2
2350 static constant kProjScaleArea = 2
2351 // scaled so that radius(gnom) = radius(stereo) for polar = 88
2352 static constant kProjScaleGnom = 0.06744519021
2353 static constant kProjScaleOrtho = 2
2354 
2369 threadsafe function calc_graph_radius(polar, [projection])
2370  variable polar
2371  variable projection
2372 
2373  if (ParamIsDefault(projection))
2374  projection = 1
2375  endif
2376 
2377  variable radius
2378  switch(projection)
2379  case kProjStereo: // stereographic
2380  radius = kProjScaleStereo * tan(polar / 2 * pi / 180)
2381  break
2382  case kProjArea: // equal area
2383  radius = kProjScaleArea * sin(polar / 2 * pi / 180)
2384  break
2385  case kProjGnom: // gnomonic
2386  radius = polar < 90 ? kProjScaleGnom * tan(polar * pi / 180) : inf
2387  break
2388  case kProjOrtho: // orthographic
2389  radius = kProjScaleOrtho * sin(polar * pi / 180)
2390  break
2391  default: // equidistant
2392  radius = kProjScaleDist * polar / 90
2393  endswitch
2394 
2395  return radius
2396 end
2397 
2414 threadsafe function calc_graph_polar(x, y, [projection])
2415  variable x
2416  variable y
2417  variable projection
2418 
2419  if (ParamIsDefault(projection))
2420  projection = 1
2421  endif
2422 
2423  variable radius
2424  variable polar
2425 
2426  radius = sqrt(x^2 + y^2)
2427  switch(projection)
2428  case kProjStereo: // stereographic
2429  polar = 2 * atan(radius / kProjScaleStereo) * 180 / pi
2430  break
2431  case kProjArea: // equal area
2432  polar = 2 * asin(radius / kProjScaleArea) * 180 / pi
2433  break
2434  case kProjGnom: // gnomonic
2435  polar = atan(radius / kProjScaleGnom) * 180 / pi
2436  break
2437  case kProjOrtho: // orthographic
2438  polar = asin(radius / kProjScaleOrtho) * 180 / pi
2439  break
2440  default: // equidistant
2441  polar = 90 * radius / kProjScaleDist
2442  endswitch
2443 
2444  return polar
2445 end
2446 
2467 threadsafe function calc_graph_azi(x, y, [projection,zeroAngle])
2468  variable x
2469  variable y
2470  variable projection
2471  variable zeroAngle
2472 
2473  if (ParamIsDefault(projection))
2474  projection = 1
2475  endif
2476  if (ParamIsDefault(zeroAngle))
2477  zeroAngle = 0
2478  endif
2479 
2480  variable azi
2481  if (x > 0)
2482  azi = atan(y / x) * 180 / pi
2483  else
2484  azi = atan(y / x) * 180 / pi + 180
2485  endif
2486 
2487  azi += zeroAngle
2488  if (azi < 0)
2489  azi += 360
2490  endif
2491  if (azi >= 360)
2492  azi -= 360
2493  endif
2494  if (numtype(azi) != 0)
2495  azi = 0
2496  endif
2497 
2498  return azi
2499 end
2500 
2512 static function update_polar_info(graphname)
2513  string graphname
2514 
2515  dfref savedf = GetDataFolderDFR()
2516 
2517  string graphdf = "root:packages:WMPolarGraphs:" + graphname
2518  setdatafolder graphdf
2519 
2520  nvar csrA_theta
2521  nvar csrA_phi
2522  nvar csrB_theta
2523  nvar csrB_phi
2524 
2525  string sproj = GetUserData(graphname, "", "projection")
2526  variable projection = str2num("0" + sproj)
2527  nvar zeroAngleWhere
2528 
2529  variable x = hcsr(A, graphname)
2530  variable y = vcsr(A, graphname)
2531  csrA_theta = calc_graph_polar(x, y, projection=projection)
2532  csrA_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2533 
2534  x = hcsr(B, graphname)
2535  y = vcsr(B, graphname)
2536  csrB_theta = calc_graph_polar(x, y, projection=projection)
2537  csrB_phi = calc_graph_azi(x, y, projection=projection, zeroAngle=zeroAngleWhere)
2538 
2539  setdatafolder savedf
2540 end
2541 
2547 static function polar_graph_hook(s)
2548  STRUCT WMWinHookStruct &s
2549 
2550  Variable hookResult = 0
2551 
2552  switch(s.eventCode)
2553  case 7: // cursor moved
2554  update_polar_info(s.winname)
2555  break
2556  case 20: // show info
2557  TextBox /W=$s.winname /N=tb_angles /C /V=1
2558  break
2559  case 21: // hide info
2560  TextBox /W=$s.winname /N=tb_angles /C /V=0
2561  break
2562  endswitch
2563 
2564  return hookResult // 0 if nothing done, else 1
2565 end
2566 
2567 function set_polar_graph_cursor(nickname, cursorname, polar_angle, azim_angle, [graphname])
2568  string nickname
2569  string cursorname
2570  variable polar_angle
2571  variable azim_angle
2572  string graphname
2573 
2574  if (ParamIsDefault(graphname))
2575  if (strlen(nickname) > 0)
2576  graphname = nickname
2577  else
2578  graphname = GetDataFolder(0)
2579  endif
2580  endif
2581 
2582  string s_prefix = ""
2583  string s_int = "values"
2584  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2585 
2586  string s_polar = s_prefix + "pol"
2587  string s_azim = s_prefix + "az"
2588  wave /sdfr=df /z azim = $s_azim
2589  wave /sdfr=df /z polar = $s_polar
2590 
2591  FindLevel /P /Q polar, polar_angle
2592  if (v_flag == 0)
2593  variable polar_level = floor(v_levelx)
2594  FindLevel /P /Q /R=[polar_level] azim, azim_angle
2595  if (v_flag == 0)
2596  variable azim_level = round(v_levelx)
2597  string tracename = "polarY0"
2598  Cursor /W=$graphname /P $cursorname $traceName azim_level
2599  endif
2600  endif
2601 end
2602 
2603 
2637 function hemi_add_anglescan(nickname, values, polar, azi, [weights])
2638  string nickname
2639  wave values
2640  wave polar
2641  wave azi
2642  wave weights
2643 
2644  dfref savedf = GetDataFolderDFR()
2645 
2646  if (ParamIsDefault(weights))
2647  duplicate /free values, weights
2648  weights = 1
2649  endif
2650 
2651  string s_prefix = ""
2652  string s_int = "values"
2653  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2654 
2655  string s_totals = s_prefix + "tot"
2656  string s_weights = s_prefix + "wt"
2657  string s_polar = s_prefix + "pol"
2658  string s_azim = s_prefix + "az"
2659  string s_index = s_prefix + "index"
2660  string s_theta = s_prefix + "th"
2661  string s_dphi = s_prefix + "dphi"
2662  string s_nphis = s_prefix + "nphis"
2663 
2664  wave /sdfr=df w_polar = $s_polar
2665  wave /sdfr=df w_azim = $s_azim
2666  wave /sdfr=df w_values = $s_int
2667  wave /sdfr=df w_totals = $s_totals
2668  wave /sdfr=df w_weights = $s_weights
2669  wave /sdfr=df w_index = $s_index
2670  wave /sdfr=df w_theta = $s_theta
2671  wave /sdfr=df w_dphi = $s_dphi
2672  wave /sdfr=df w_nphis = $s_nphis
2673 
2674  // make internal copies of input, one-dimensional, ordered in theta
2675  duplicate /free values, values_copy
2676  duplicate /free polar, polar_copy
2677  duplicate /free azi, azi_copy
2678  duplicate /free weights, weights_copy
2679  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
2680  redimension /n=(nn) values_copy, polar_copy, azi_copy, weights_copy
2681  sort /r polar_copy, polar_copy, azi_copy, values_copy, weights_copy
2682 
2683  make /n=(numpnts(w_theta)) /free /df dfw
2684  // for debugging: remove the MultiThread keyword and the ThreadSafe keywords of sub-functions
2685  MultiThread dfw = add_anglescan_worker(p, values_copy, weights_copy, polar_copy, azi_copy, w_polar, w_azim, w_theta, w_index, w_dphi, w_nphis)
2686 
2687  variable pp
2688  for (pp = 0; pp < numpnts(dfw); pp += 1)
2689  dfref tdf= dfw[pp]
2690  wave df_totals = tdf:w_totals
2691  wave df_weights = tdf:w_weights
2692  w_totals += df_totals
2693  w_weights += df_weights
2694  endfor
2695  w_values = w_weights > 0 ? w_totals / w_weights : nan
2696 
2697  SetDataFolder savedf
2698 end
2699 
2711 threadsafe static function /df add_anglescan_worker(ith, values, weights, polar, azi, w_polar, w_azim, w_theta, w_index, w_dphi, w_nphis)
2712  variable ith // index into w_theta
2713  wave values // input data: intensity/counts
2714  wave weights // input data: weights/dwell time
2715  wave polar // input data: polar angles
2716  wave azi // input data: azimuthal angles
2717  wave w_polar // hemi grid
2718  wave w_azim // hemi grid
2719  wave w_theta // hemi grid
2720  wave w_index // hemi grid
2721  wave w_dphi // hemi grid
2722  wave w_nphis // hemi grid
2723 
2724  dfref savedf= GetDataFolderDFR()
2725  dfref freedf= NewFreeDataFolder()
2726  SetDataFolder freedf
2727  make /n=(numpnts(w_polar)) /d w_totals, w_weights
2728 
2729  variable pol = w_theta[ith]
2730  variable pol_st = abs(w_theta[1] - w_theta[0])
2731  variable pol1 = pol - pol_st / 2
2732  variable pol2 = pol + pol_st / 2
2733 
2734  extract /free /indx polar, sel, (pol1 < polar) && (polar <= pol2) && (numtype(values) == 0) && (weights > 0)
2735  if (numpnts(sel) > 0)
2736  duplicate /free /r=[0, numpnts(sel)-1] azi, azi_slice
2737  duplicate /free /r=[0, numpnts(sel)-1] values, values_slice
2738  duplicate /free /r=[0, numpnts(sel)-1] weights, weights_slice
2739  azi_slice = azi[sel]
2740  values_slice = values[sel]
2741  weights_slice = weights[sel]
2742  add_aziscan_core(values_slice, weights_slice, pol, azi_slice, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
2743  endif
2744 
2745  SetDataFolder savedf
2746  return freedf
2747 end
2748 
2761 threadsafe static function add_aziscan_core(values, weights, polar, azi, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
2762  wave values // input data: intensity/counts
2763  wave weights // input data: weights/dwell time
2764  variable polar // input data: polar angle
2765  wave azi // input data: angle positions of the azimuthal scan
2766  // acceptable range: >= -360 and < +360
2767  // no specific order required, the function sorts the array in place (!)
2768  wave w_theta // hemi grid
2769  wave w_azim // hemi grid
2770  wave w_index // hemi grid
2771  wave w_dphi // hemi grid
2772  wave w_totals // output data: total counts in hemi grid order
2773  wave w_weights // output data: total weights in hemi grid order
2774 
2775  // destination slice coordinates
2776  variable ipol = BinarySearch(w_theta, polar)
2777  if (ipol < 0)
2778  return -1
2779  endif
2780 
2781  variable d1, d2
2782  if (ipol >= 1)
2783  d1 = w_index[ipol - 1]
2784  else
2785  d1 = 0
2786  endif
2787  d2 = w_index[ipol] - 1
2788  variable nd = d2 - d1 + 1
2789  variable dphi = w_dphi[ipol]
2790  make /n=(nd+1) /free bin_index
2791  setscale /i x w_azim[d1] - dphi/2, w_azim[d2] + dphi/2, "deg", bin_index
2792 
2793  // source slice coordinates
2794  // order the slice from -dphi/2 to 360-dphi/2
2795  azi = azi < 0 ? azi + 360 : azi
2796  azi = azi >= 360 - dphi/2 ? azi - 360 : azi
2797  sort azi, values, weights, azi
2798  setscale /p x 0, 1, "", values, weights, azi
2799 
2800  bin_index = BinarySearch(azi, x) + 1
2801  bin_index = bin_index == -2 ? 0 : bin_index[p]
2802  bin_index = bin_index == -1 ? numpnts(azi) : bin_index[p]
2803  bin_index[nd] = numpnts(azi)
2804 
2805  // loop over destination
2806  variable id
2807  variable v1, v2, w1, w2
2808  for (id = 0; id < nd; id += 1)
2809  if (bin_index[id+1] > bin_index[id])
2810  v1 = w_totals[d1 + id]
2811  w1 = w_weights[d1 + id]
2812  if ((numtype(v1) == 2) || (w1 <= 0))
2813  v1 = 0
2814  w1 = 0
2815  endif
2816  v2 = sum(values, bin_index[id], bin_index[id+1] - 1)
2817  w2 = sum(weights, bin_index[id], bin_index[id+1] - 1)
2818  w_totals[d1 + id] = v1 + v2
2819  w_weights[d1 + id] = w1 + w2
2820  endif
2821  endfor
2822 end
2823 
2844 function hemi_add_aziscan(nickname, values, polar, azi, [weights])
2845  string nickname
2846  wave values
2847  variable polar
2848  wave azi
2849  wave weights
2850 
2851  dfref savedf = GetDataFolderDFR()
2852 
2853  duplicate /free values, values_copy
2854  duplicate /free azi, azi_copy
2855  if (ParamIsDefault(weights))
2856  duplicate /free values, weights_copy
2857  weights_copy = 1
2858  else
2859  duplicate /free weights, weights_copy
2860  endif
2861 
2862  // hemi grid waves
2863  string s_prefix = ""
2864  string s_int = "values"
2865  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2866 
2867  string s_totals = s_prefix + "tot"
2868  string s_weights = s_prefix + "wt"
2869  string s_polar = s_prefix + "pol"
2870  string s_azim = s_prefix + "az"
2871  string s_index = s_prefix + "index"
2872  string s_theta = s_prefix + "th"
2873  string s_dphi = s_prefix + "dphi"
2874  string s_nphis = s_prefix + "nphis"
2875 
2876  wave /sdfr=df w_polar = $s_polar
2877  wave /sdfr=df w_azim = $s_azim
2878  wave /sdfr=df w_values = $s_int
2879  wave /sdfr=df w_totals = $s_totals
2880  wave /sdfr=df w_weights = $s_weights
2881  wave /sdfr=df w_index = $s_index
2882  wave /sdfr=df w_theta = $s_theta
2883  wave /sdfr=df w_dphi = $s_dphi
2884  wave /sdfr=df w_nphis = $s_nphis
2885 
2886  add_aziscan_core(values_copy, weights_copy, polar, azi_copy, w_theta, w_azim, w_index, w_dphi, w_totals, w_weights)
2887 
2888  w_values = w_weights > 0 ? w_totals / w_weights : nan
2889 
2890  SetDataFolder savedf
2891 end
2892 
2920 function interpolate_hemi_scan(nickname, [projection])
2921  string nickname
2922  variable projection
2923 
2924  dfref savedf = GetDataFolderDFR()
2925 
2926  if (ParamIsDefault(projection))
2927  projection = 1
2928  endif
2929 
2930  string s_prefix = ""
2931  string s_int = "values"
2932  dfref df = find_hemi_data(nickname, s_prefix, s_int)
2933  prepare_hemi_scan_display(nickname, projection=projection)
2934 
2935  string s_polar = s_prefix + "pol"
2936  string s_azim = s_prefix + "az"
2937  string s_matrix = s_prefix + "matrix"
2938  string s_ster_rad = s_prefix + "ster_rad"
2939  string s_ster_x = s_prefix + "ster_x"
2940  string s_ster_y = s_prefix + "ster_y"
2941 
2942  wave /sdfr=df /z values = $s_int
2943  wave /sdfr=df /z azim = $s_azim
2944  wave /sdfr=df /z polar = $s_polar
2945  wave /sdfr=df /z ster_rad = $s_ster_rad
2946  wave /sdfr=df /z ster_x = $s_ster_x
2947  wave /sdfr=df /z ster_y = $s_ster_y
2948 
2949  variable min_ster_x = wavemin(ster_x)
2950  variable max_ster_x = wavemax(ster_x)
2951  variable x0 = min_ster_x
2952  variable xn = 181
2953  variable dx = (max_ster_x - min_ster_x) / (xn - 1)
2954  make /n=(numpnts(ster_x), 3) /free triplet
2955  triplet[][0] = ster_x[p]
2956  triplet[][1] = ster_y[p]
2957  triplet[][2] = values[p]
2958 
2959  variable size = 181
2960  setdatafolder df
2961  make /n=(size, size) /d /o $(s_prefix + "matrix") /wave=matrix
2962  make /n=(size, size) /free mnorm
2963  ImageFromXYZ /as {ster_x, ster_y, values}, matrix, mnorm
2964  matrix /= mnorm
2965  matrixfilter NanZapMedian, matrix
2966  matrixfilter gauss, matrix
2967 
2968  duplicate /free values, ster_finite
2969  ster_finite = (numtype(values) == 0) * (ster_x^2 + ster_y^2)
2970  variable ster_max = wavemax(ster_finite)
2971  matrix = (x^2 + y^2) <= ster_max ? matrix : nan
2972 
2973  setdatafolder savedf
2974 end
2975 
2986 function quick_pizza_image(data, nickname, theta_offset, tilt_offset, phi_offset, [npolar, nograph, folding])
2987  wave data // 2D intensity wave, see requirements above
2988  string nickname // nick name for output data
2989  // in default mode, this will be the name of a child folder containing the output
2990  // in XPDplot mode, this will be a prefix of the generated data in the root folder
2991  variable theta_offset // manipulator theta angle corresponding to normal emission
2992  variable tilt_offset // manipulator tilt angle corresponding to normal emission
2993  variable phi_offset // manipulator phi angle corresponding to phi_result = 0
2994  variable npolar // number of polar angles, determines polar and azimuthal step size
2995  // default = 91 (1 degree steps)
2996  variable nograph // 0 (default) = display a new polar graph
2997  // 1 = don't display a new graph (if a graph is existing from a previous call, it will update)
2998  variable folding // rotational averaging, default = 1
2999 
3000  if (ParamIsDefault(npolar))
3001  npolar = 91
3002  endif
3003  if (ParamIsDefault(nograph))
3004  nograph = 0
3005  endif
3006  if (ParamIsDefault(folding))
3007  folding = 1
3008  endif
3009  string graphname = "graph_" + nickname
3010  string s_prefix = ""
3011 
3012  // sort out data folder structure
3013  dfref saveDF = GetDataFolderDFR()
3014  dfref dataDF = GetWavesDataFolderDFR(data)
3015  setdatafolder dataDF
3016  if (DataFolderExists(":attr"))
3017  setdatafolder :attr
3018  endif
3019  dfref attrDF = GetDataFolderDFR()
3020  setdatafolder dataDF
3021  newdatafolder /s/o $nickname
3022  dfref destDF = GetDataFolderDFR()
3023 
3024  // performance monitoring
3025  variable timerRefNum
3026  variable /g xyz_perf_secs
3027  timerRefNum = startMSTimer
3028 
3029  wave /sdfr=attrDF ManipulatorTheta
3030  wave /sdfr=attrDF ManipulatorTilt
3031  wave /sdfr=attrDF ManipulatorPhi
3032  duplicate /free ManipulatorTheta, m_theta
3033  duplicate /free ManipulatorTilt, m_tilt
3034  duplicate /free ManipulatorPhi, m_phi
3035  m_theta -= theta_offset
3036  m_tilt -= tilt_offset
3037  m_tilt *= -1 // checked 140702
3038  m_phi -= phi_offset
3039  //m_phi *= -1 // checked 140702
3040 
3041  make /n=1/d/free d_polar, d_azi
3042  convert_angles_ttpd2polar(m_theta, m_tilt, m_phi, data, d_polar, d_azi)
3043  d_azi += 180 // changed 151030 (v1.6)
3044  d_azi = d_azi >= 360 ? d_azi - 360 : d_azi
3045 
3046  duplicate /free data, values
3047  variable nn = dimsize(values, 0) * max(dimsize(values, 1), 1)
3048  redimension /n=(nn) values, d_polar, d_azi
3049  duplicate /o d_polar, ster_rad, ster_x, ster_y
3050 
3051  variable projection = 1
3052  switch(projection)
3053  case 1: // stereographic
3054  ster_rad = 2 * tan(d_polar / 2 * pi / 180)
3055  break
3056  case 2: // azimuthal
3057  ster_rad = 2 * cos((180 - d_polar) / 2 * pi / 180)
3058  break
3059  endswitch
3060  string s_ster_x = s_prefix + "ster_x"
3061  string s_ster_y = s_prefix + "ster_y"
3062 
3063  nn = 401
3064  make /n=(nn, nn) /d /o matrix
3065  make /n=(nn, nn) /free mnorm
3066  setscale /i x -2, +2, matrix, mnorm
3067  setscale /i y -2, +2, matrix, mnorm
3068  matrix = 0
3069  mnorm = 0
3070 
3071  variable ifold
3072  for (ifold = 0; ifold < folding; ifold += 1)
3073  ster_x = ster_rad * cos(d_azi * pi / 180)
3074  ster_y = ster_rad * sin(d_azi * pi / 180)
3075  ImageFromXYZ {ster_x, ster_y, values}, matrix, mnorm
3076  d_azi = d_azi >= 180 ? d_azi + 360 / folding - 180 : d_azi + 360 / folding
3077  endfor
3078 
3079  matrix /= mnorm
3080  matrixfilter /n=5 NanZapMedian matrix
3081  matrixfilter /n=3 gauss matrix
3082 
3083  if (!nograph)
3084  display /k=1
3085  appendimage matrix
3086  modifygraph width={Plan,1,bottom,left}
3087  endif
3088 
3089  if (timerRefNum >= 0)
3090  xyz_perf_secs = stopMSTimer(timerRefNum) / 1e6
3091  endif
3092 
3093  setdatafolder saveDF
3094 end
3095 
3097 function save_hemi_scan(nickname, pathname, filename)
3098  string nickname
3099  string pathname
3100  string filename
3101 
3102  dfref savedf = getdatafolderdfr()
3103 
3104  // source data
3105  string s_prefix = ""
3106  string s_int = "values"
3107  dfref df = find_hemi_data(nickname, s_prefix, s_int)
3108 
3109  string s_polar = s_prefix + "pol"
3110  string s_azim = s_prefix + "az"
3111  string s_theta = s_prefix + "th"
3112  string s_tot = s_prefix + "tot"
3113  string s_weight = s_prefix + "wt"
3114 
3115  wave /sdfr=df theta1 = $s_theta
3116  wave /sdfr=df polar1 = $s_polar
3117  wave /sdfr=df azim1 = $s_azim
3118  wave /sdfr=df tot1 = $s_tot
3119  wave /sdfr=df weight1 = $s_weight
3120  wave /sdfr=df values1 = $s_int
3121 
3122  save /m="\r\n" /o /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
3123 
3124  setdatafolder saveDF
3125 end
3126 
3130 function load_hemi_scan(nickname, pathname, filename)
3131  string nickname
3132  string pathname
3133  string filename
3134 
3135  dfref savedf = getdatafolderdfr()
3136 
3137  //loadwave /p=$pathname /t theta1, polar1, azim1, tot1, weight1, values1 as filename
3138  //LoadWave /t/p=pearl_explorer_filepath/q filename
3139  //svar waves = s_wavenames
3140  //if (v_flag > 0)
3141  // string /g pearl_explorer_import = "load_itx_file"
3142  //endif
3143 
3144  setdatafolder saveDF
3145 end
3146 
3179 function import_tpi_scan(nickname, theta, phi, intensity, [folding, npolar, nograph, xpdplot])
3180  string nickname
3181  wave theta
3182  wave phi
3183  wave intensity
3184 
3185  variable folding
3186  variable npolar
3187  variable nograph
3188  variable xpdplot
3189 
3190  if (ParamIsDefault(npolar))
3191  npolar = 91
3192  endif
3193  if (ParamIsDefault(nograph))
3194  nograph = 0
3195  endif
3196  if (ParamIsDefault(folding))
3197  folding = 1
3198  endif
3199  if (ParamIsDefault(xpdplot))
3200  xpdplot = 0
3201  endif
3202 
3203  make_hemi_grid(npolar, nickname, xpdplot=xpdplot)
3204 
3205  variable ifold
3206  duplicate /free phi, fold_phi
3207  for (ifold = 0; ifold < folding; ifold += 1)
3208  fold_phi = fold_phi >= 360 ? fold_phi - 360 : fold_phi
3209  hemi_add_anglescan(nickname, intensity, theta, fold_phi)
3210  fold_phi += 360 / folding
3211  endfor
3212 
3213  if (nograph==0)
3214  display_hemi_scan(nickname)
3215  endif
3216 end
3217 
3229 function trim_hemi_scan(nickname, theta_max)
3230  string nickname
3231  variable theta_max
3232 
3233  string s_prefix = ""
3234  string s_int = "values"
3235  dfref df = find_hemi_data(nickname, s_prefix, s_int)
3236 
3237  string s_totals = s_prefix + "tot"
3238  string s_weights = s_prefix + "wt"
3239  string s_polar = s_prefix + "pol"
3240 
3241  wave /sdfr=df w_polar = $s_polar
3242  wave /sdfr=df w_values = $s_int
3243  wave /sdfr=df w_totals = $s_totals
3244  wave /sdfr=df w_weights = $s_weights
3245 
3246  w_values = w_polar <= theta_max ? w_totals / w_weights : nan
3247 end
3248 
3268 function /wave hemi_polar_cut(nickname, azim)
3269  string nickname
3270  variable azim
3271 
3272  dfref savedf = getdatafolderdfr()
3273  string s_prefix = ""
3274  string s_int = "values"
3275  dfref df = find_hemi_data(nickname, s_prefix, s_int)
3276 
3277  string s_totals = s_prefix + "tot"
3278  string s_weights = s_prefix + "wt"
3279  string s_polar = s_prefix + "pol"
3280  string s_azim = s_prefix + "az"
3281  string s_index = s_prefix + "index"
3282  string s_theta = s_prefix + "th"
3283  string s_dphi = s_prefix + "dphi"
3284  string s_nphis = s_prefix + "nphis"
3285  string s_cut
3286  sprintf s_cut, "%s_azi%03u", s_int, round(azim)
3287 
3288  wave /sdfr=df w_polar = $s_polar
3289  wave /sdfr=df w_azim = $s_azim
3290  wave /sdfr=df w_values = $s_int
3291  wave /sdfr=df w_totals = $s_totals
3292  wave /sdfr=df w_weights = $s_weights
3293  wave /sdfr=df w_index = $s_index
3294  wave /sdfr=df w_theta = $s_theta
3295  wave /sdfr=df w_dphi = $s_dphi
3296  wave /sdfr=df w_nphis = $s_nphis
3297 
3298  variable npol = numpnts(w_theta)
3299  variable ipol
3300  variable pol_st = abs(w_theta[1] - w_theta[0])
3301  variable pol
3302  variable pol1, pol2
3303  variable nsel
3304 
3305  setdatafolder df
3306  make /n=(npol) /o $s_cut
3307  wave w_cut = $s_cut
3308  setscale /i x w_theta[0], w_theta[numpnts(w_theta)-1], "deg", w_cut
3309  make /n=1 /free azi_slice
3310  make /n=1 /free values_slice
3311 
3312  for (ipol = 0; ipol < npol; ipol += 1)
3313  pol = w_theta[ipol]
3314  pol1 = pol - pol_st / 2
3315  pol2 = pol + pol_st / 2
3316  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
3317  nsel = numpnts(sel)
3318  if (nsel > 0)
3319  redimension /n=(nsel+2) azi_slice, values_slice
3320  azi_slice[1, nsel] = w_azim[sel[p-1]]
3321  azi_slice[0] = azi_slice[nsel] - 360
3322  azi_slice[nsel+1] = azi_slice[1] + 360
3323  values_slice[1, nsel] = w_values[sel[p-1]]
3324  values_slice[0] = values_slice[nsel]
3325  values_slice[nsel+1] = values_slice[1]
3326  w_cut[ipol] = interp(azim, azi_slice, values_slice)
3327  else
3328  w_cut[ipol] = nan
3329  endif
3330  endfor
3331 
3332  setdatafolder savedf
3333  return w_cut
3334 end
3335 
3354 function /wave hemi_azi_cut(nickname, pol)
3355  string nickname
3356  variable pol
3357 
3358  dfref savedf = getdatafolderdfr()
3359  string s_prefix = ""
3360  string s_int = "values"
3361  dfref df = find_hemi_data(nickname, s_prefix, s_int)
3362 
3363  string s_totals = s_prefix + "tot"
3364  string s_weights = s_prefix + "wt"
3365  string s_polar = s_prefix + "pol"
3366  string s_azim = s_prefix + "az"
3367  string s_index = s_prefix + "index"
3368  string s_theta = s_prefix + "th"
3369  string s_dphi = s_prefix + "dphi"
3370  string s_nphis = s_prefix + "nphis"
3371  string s_cut
3372  sprintf s_cut, "%s_pol%03u", s_int, round(pol)
3373 
3374  wave /sdfr=df w_polar = $s_polar
3375  wave /sdfr=df w_azim = $s_azim
3376  wave /sdfr=df w_values = $s_int
3377  wave /sdfr=df w_totals = $s_totals
3378  wave /sdfr=df w_weights = $s_weights
3379  wave /sdfr=df w_index = $s_index
3380  wave /sdfr=df w_theta = $s_theta
3381  wave /sdfr=df w_dphi = $s_dphi
3382  wave /sdfr=df w_nphis = $s_nphis
3383 
3384  variable pol_st = abs(w_theta[1] - w_theta[0])
3385  variable pol1, pol2
3386  variable nsel
3387 
3388  pol1 = pol - pol_st / 2
3389  pol2 = pol + pol_st / 2
3390  extract /free /indx w_polar, sel, (pol1 < w_polar) && (w_polar <= pol2)
3391  nsel = numpnts(sel)
3392  if (nsel > 0)
3393  setdatafolder df
3394  make /n=(nsel) /o $s_cut
3395  wave w_cut = $s_cut
3396  w_cut = w_values[sel]
3397  setscale /i x w_azim[sel[0]], w_azim[sel[nsel-1]], "°", w_cut
3398  setdatafolder savedf
3399  return w_cut
3400  else
3401  setdatafolder savedf
3402  return $""
3403  endif
3404  setdatafolder savedf
3405 end
3406 
3407 static function check_contrast(values, pcmin, pcmax, vmin, vmax, sym)
3408  wave values
3409  variable pcmin
3410  variable pcmax
3411  variable &vmin
3412  variable &vmax
3413  variable sym
3414 
3415  dfref save_df = GetDataFolderDFR()
3416  dfref dfr = NewFreeDataFolder()
3417  setdatafolder dfr
3418  StatsQuantiles /inan /iw /q /z values
3419  wave /z index = w_quantilesindex
3420  setdatafolder save_df
3421 
3422  if (waveexists(index))
3423  variable imin = round(numpnts(index) * pcmin / 100)
3424  variable imax = round(numpnts(index) * (100 - pcmax) / 100)
3425  vmin = values[index[imin]]
3426  vmax = values[index[imax]]
3427  if (sym)
3428  variable d = vmax - vmin
3429  if ((vmax >= d/4) && (-vmin >= d/4))
3430  vmax = min(abs(vmin), abs(vmax))
3431  vmin = -vmax
3432  endif
3433  endif
3434  else
3435  vmin = wavemin(values)
3436  vmax = wavemax(values)
3437  endif
3438 end
3439 
3463 function set_contrast(pcmin, pcmax, [graphname, colortable, reversecolors, symmetric])
3464  variable pcmin
3465  variable pcmax
3466  string graphname
3467  string colortable
3468  variable reversecolors
3469  variable symmetric
3470 
3471  if (ParamIsDefault(graphname))
3472  graphname = ""
3473  endif
3474  if (ParamIsDefault(colortable))
3475  colortable = ""
3476  endif
3477  if (ParamIsDefault(reversecolors))
3478  reversecolors = 0
3479  endif
3480  if (ParamIsDefault(symmetric))
3481  symmetric = 0
3482  endif
3483 
3484  dfref save_df = GetDataFolderDFR()
3485 
3486  string objname
3487  string info
3488  string wname
3489  string ctab
3490  variable rev
3491  variable n
3492  variable i
3493  variable vmin
3494  variable vmax
3495 
3496  string traces = TraceNameList(graphname, ";", 1+4)
3497  n = ItemsInList(traces, ";")
3498  for (i = 0; i < n; i += 1)
3499  objname = StringFromList(i, traces, ";")
3500  info = TraceInfo(graphname, objname, 0)
3501  if (strlen(info) > 0)
3502  info = StringByKey("RECREATION", info, ":", ";")
3503  info = StringByKey("zColor(x)", info, "=", ";")
3504  if (strlen(info) > 2)
3505  info = info[1,strlen(info)-2]
3506  wname = StringFromList(0, info, ",")
3507  wave w = $wname
3508  ctab = StringFromList(3, info, ",")
3509  rev = str2num("0" + StringFromList(4, info, ","))
3510  if (strlen(colortable) > 0)
3511  ctab = colortable
3512  rev = reversecolors
3513  endif
3514  check_contrast(w, pcmin, pcmax, vmin, vmax, symmetric)
3515  if (vmax > vmin)
3516  ModifyGraph /w=$graphname zColor($objname)={w, vmin, vmax, $ctab, rev}
3517  endif
3518  endif
3519  endif
3520  endfor
3521 
3522  string images = ImageNameList(graphname, ";")
3523  n = ItemsInList(images, ";")
3524  for (i = 0; i < n; i += 1)
3525  objname = StringFromList(i, images, ";")
3526  wave w = ImageNameToWaveRef(graphname, objname)
3527  info = ImageInfo(graphname, objname, 0)
3528  if (strlen(info) > 0)
3529  info = StringByKey("RECREATION", info, ":", ";")
3530  info = StringByKey("ctab", info, "=", ";")
3531  if (strlen(info) > 2)
3532  info = info[1,strlen(info)-2]
3533  ctab = StringFromList(2, info, ",")
3534  rev = str2num("0" + StringFromList(3, info, ","))
3535  if (strlen(colortable) > 0)
3536  ctab = colortable
3537  rev = reversecolors
3538  endif
3539  check_contrast(w, pcmin, pcmax, vmin, vmax, symmetric)
3540  if (vmax > vmin)
3541  ModifyImage /w=$graphname $objname ctab={vmin, vmax, $ctab, rev}
3542  endif
3543  endif
3544  endif
3545  endfor
3546 
3547  setdatafolder save_df
3548 end
3549 
3562 Function AngleToK(inwave)
3563  Wave inwave
3564  String newname = NameofWave(inwave)+"_k"
3565  Duplicate/O inwave, $newname
3566  Wave outwave = $newname
3567  Variable rows,columns,xdelta,xoffset,ydelta,yoffset,kmin,kmax,Emax
3568  // inwave parameters
3569  rows = DimSize(inwave,0)
3570  columns = DimSize(inwave,1)
3571  xdelta = DimDelta(inwave,0)
3572  xoffset = DimOffset(inwave,0)
3573  ydelta = DimDelta(inwave,1)
3574  yoffset = DimOffset(inwave,1)
3575  Emax= xoffset + xdelta*(rows-1)
3576  kmin = 0.5123*sqrt(Emax)*sin(pi/180*(yoffset)) // calculate the k boundaries
3577  kmax = 0.5123*sqrt(Emax)*sin(pi/180*(yoffset+(columns-1)*ydelta))
3578  SetScale/I y kmin,kmax,"Ang^-1", outwave
3579  // scale the y axis
3580  outwave = interp2D(inwave, x, 180/pi*asin(y/ (0.5123*sqrt(x)))) // recalculate to k
3581  outwave = (NumType(outwave)==2) ? 0 : outwave // replace NaNs (optional)
3582 End
crop_strip
variable crop_strip(wave strip, variable xlo, variable xhi)
crop a strip at the sides.
Definition: pearl-anglescan-process.ipf:747
kProjGnom
const variable kProjGnom
Definition: pearl-anglescan-process.ipf:2345
trim_hemi_scan
variable trim_hemi_scan(string nickname, variable theta_max)
trim a hemispherical scan at grazing angle
Definition: pearl-anglescan-process.ipf:3229
hemi_add_anglescan
variable hemi_add_anglescan(string nickname, wave values, wave polar, wave azi, wave weights=defaultValue)
add arbitrary angle scan data to a hemispherical scan grid.
Definition: pearl-anglescan-process.ipf:2637
CalcN_Theta
static variable CalcN_Theta(string HoloMode, variable Theta_in, variable Theta_ran, variable Theta_st)
calculate the number of thetas for a pattern
Definition: pearl-anglescan-process.ipf:1327
import_tpi_scan
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
Definition: pearl-anglescan-process.ipf:3179
pizza_service_2
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
Definition: pearl-anglescan-process.ipf:936
load_hemi_scan
variable load_hemi_scan(string nickname, string pathname, string filename)
load a hemispherical scan from an Igor text file
Definition: pearl-anglescan-process.ipf:3130
normalize_strip_theta
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.
Definition: pearl-anglescan-process.ipf:433
normalize_strip_x
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.
Definition: pearl-anglescan-process.ipf:252
check_contrast
static variable check_contrast(wave values, variable pcmin, variable pcmax, variable *vmin, variable *vmax, variable sym)
Definition: pearl-anglescan-process.ipf:3407
convert_angles_ttpd2polar
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.
Definition: pearl-anglescan-process.ipf:1123
get_hemi_prefix
string get_hemi_prefix(wave w)
finds the prefix given any hemi wave
Definition: pearl-anglescan-process.ipf:1541
make_hemi_grid
variable make_hemi_grid(variable npol, string nickname, variable xpdplot=defaultValue)
create a hemispherical, constant solid angle grid
Definition: pearl-anglescan-process.ipf:1365
clear_hemi_grid
variable clear_hemi_grid(string nickname)
clear a hemispherical scan grid
Definition: pearl-anglescan-process.ipf:1606
rotate_y_wave
variable rotate_y_wave(wave inout, variable angle)
rotates a wave of 3-vectors about the y axis
Definition: pearl-vector-operations.ipf:205
calc_graph_polar
threadsafe variable calc_graph_polar(variable x, variable y, variable projection=defaultValue)
calculate polar angle from Cartesian coordinate
Definition: pearl-anglescan-process.ipf:2414
kProjScaleOrtho
static const variable kProjScaleOrtho
Definition: pearl-anglescan-process.ipf:2353
kProjArea
const variable kProjArea
Definition: pearl-anglescan-process.ipf:2344
get_hemi_nickname
string get_hemi_nickname(wave w)
finds the nick name given any hemi wave
Definition: pearl-anglescan-process.ipf:1516
hemi_azi_cut
wave hemi_azi_cut(string nickname, variable pol)
extract an azimuthal cut from a hemispherical scan
Definition: pearl-anglescan-process.ipf:3354
normalize_strip_2d
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.
Definition: pearl-anglescan-process.ipf:686
line_average
static variable line_average(wave source, wave dest)
Definition: pearl-anglescan-process.ipf:1205
ad_profile_x
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.
Definition: pearl-area-profiles.ipf:481
display_scanlines
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.
Definition: pearl-anglescan-process.ipf:2254
ad_profile_y
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.
Definition: pearl-area-profiles.ipf:543
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.
Definition: pearl-anglescan-process.ipf:594
Calc_The_step
static variable Calc_The_step(variable th, variable Theta_st, string Holomode)
calculate delta-theta for a given theta
Definition: pearl-anglescan-process.ipf:1296
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.
Definition: pearl-anglescan-process.ipf:779
calc_graph_radius
threadsafe variable calc_graph_radius(variable polar, variable projection=defaultValue)
calculate the projected polar angle
Definition: pearl-anglescan-process.ipf:2369
add_anglescan_worker
static threadsafe dfr add_anglescan_worker(variable ith, wave values, wave weights, wave polar, wave azi, wave w_polar, wave w_azim, wave w_theta, wave w_index, wave w_dphi, wave w_nphis)
thread worker for hemi_add_anglescan
Definition: pearl-anglescan-process.ipf:2711
find_hemi_data
dfr find_hemi_data(string nickname, string *prefix, string *intwave)
finds the folder, prefix and name of holo waves given their nick name
Definition: pearl-anglescan-process.ipf:1572
pizza_service
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
Definition: pearl-anglescan-process.ipf:843
draw_diffraction_cone
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.
Definition: pearl-anglescan-process.ipf:2190
interpolate_hemi_scan
variable interpolate_hemi_scan(string nickname, variable projection=defaultValue)
interpolate a hemispherical scan onto a rectangular grid
Definition: pearl-anglescan-process.ipf:2920
kProjScaleDist
static const variable kProjScaleDist
Definition: pearl-anglescan-process.ipf:2348
cart2polar_wave
variable cart2polar_wave(wave in, wave out)
Definition: pearl-polar-coordinates.ipf:37
rotate_hemi_scan
variable rotate_hemi_scan(string nickname, variable angle)
azimuthally rotate a hemispherical scan dataset.
Definition: pearl-anglescan-process.ipf:1728
kProjDist
const variable kProjDist
Definition: pearl-anglescan-process.ipf:2342
display_polar_graph
static string display_polar_graph(string graphname, variable angle_offset=defaultValue, variable do_ticks=defaultValue)
displays an empty polar graph
Definition: pearl-anglescan-process.ipf:2003
quick_pizza_image
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
Definition: pearl-anglescan-process.ipf:2986
set_contrast
variable set_contrast(variable pcmin, variable pcmax, string graphname=defaultValue, string colortable=defaultValue, variable reversecolors=defaultValue, variable symmetric=defaultValue)
set the pseudocolor contrast by percentile.
Definition: pearl-anglescan-process.ipf:3463
calc_nth
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
Definition: pearl-anglescan-process.ipf:1223
hemi_add_aziscan
variable hemi_add_aziscan(string nickname, wave values, variable polar, wave azi, wave weights=defaultValue)
add azimuthal data to a hemispherical scan grid.
Definition: pearl-anglescan-process.ipf:2844
add_aziscan_core
static threadsafe variable add_aziscan_core(wave values, wave weights, variable polar, wave azi, wave w_theta, wave w_azim, wave w_index, wave w_dphi, wave w_totals, wave w_weights)
thread worker for hemi_add_anglescan and hemi_add_aziscan
Definition: pearl-anglescan-process.ipf:2761
convert_angles_ttpa2polar
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.
Definition: pearl-anglescan-process.ipf:1162
kProjScaleGnom
static const variable kProjScaleGnom
Definition: pearl-anglescan-process.ipf:2352
save_hemi_scan
variable save_hemi_scan(string nickname, string pathname, string filename)
save a hemispherical scan to an Igor text file
Definition: pearl-anglescan-process.ipf:3097
PearlAnglescanProcess
processing and holographic mapping of angle scanned XPD data.
rotate_x_wave
variable rotate_x_wave(wave inout, variable angle)
rotate a wave of 3-vectors about the x axis.
Definition: pearl-vector-operations.ipf:176
calc_graph_azi
threadsafe variable calc_graph_azi(variable x, variable y, variable projection=defaultValue, variable zeroAngle=defaultValue)
calculate azimuthal angle from Cartesian coordinate
Definition: pearl-anglescan-process.ipf:2467
kProjStereo
const variable kProjStereo
Definition: pearl-anglescan-process.ipf:2343
normalize_strip_thetaphi
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.
Definition: pearl-anglescan-process.ipf:533
rotate_z_wave
variable rotate_z_wave(wave inout, variable angle)
rotates a wave of 3-vectors about the z axis
Definition: pearl-vector-operations.ipf:234
kProjScaleStereo
static const variable kProjScaleStereo
Definition: pearl-anglescan-process.ipf:2349
kProjScaleArea
static const variable kProjScaleArea
Definition: pearl-anglescan-process.ipf:2350
duplicate_hemi_scan
variable duplicate_hemi_scan(string source_nickname, dfref dest_folder, string dest_nickname, variable xpdplot=defaultValue)
duplicate a hemispherical scan dataset.
Definition: pearl-anglescan-process.ipf:1653
set_polar_graph_cursor
variable set_polar_graph_cursor(string nickname, string cursorname, variable polar_angle, variable azim_angle, string graphname=defaultValue)
Definition: pearl-anglescan-process.ipf:2567
kProjOrtho
const variable kProjOrtho
Definition: pearl-anglescan-process.ipf:2346
normalize_strip_phi
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).
Definition: pearl-anglescan-process.ipf:348
polar2cart_wave
variable polar2cart_wave(wave in, wave out)
Definition: pearl-polar-coordinates.ipf:59
calc_phi_step
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
Definition: pearl-anglescan-process.ipf:1252
polar_graph_hook
static variable polar_graph_hook(WMWinHookStruct *s)
polar graph window hook
Definition: pearl-anglescan-process.ipf:2547
prepare_hemi_scan_display
string prepare_hemi_scan_display(string nickname, variable projection=defaultValue)
create waves for plotting a hemispherical angle scan.
Definition: pearl-anglescan-process.ipf:1776
hemi_polar_cut
wave hemi_polar_cut(string nickname, variable azim)
extract a polar cut from a hemispherical scan.
Definition: pearl-anglescan-process.ipf:3268
version
version
Definition: pearl-anglescan-tracker.ipf:6
show_analyser_line
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
Definition: pearl-anglescan-process.ipf:1053
strip_append
string strip_append(wave strip1, wave strip2)
append an angle scan strip to another one
Definition: pearl-anglescan-process.ipf:106
strip_delete_frames
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.
Definition: pearl-anglescan-process.ipf:170
AngleToK
variable AngleToK(wave inwave)
k-space mapping of 2D angle-energy distribution (scienta image)
Definition: pearl-anglescan-process.ipf:3562
update_polar_info
static variable update_polar_info(string graphname)
update the angles info based on cursors A and B of a given polar graph window
Definition: pearl-anglescan-process.ipf:2512
draw_hemi_axes
static string draw_hemi_axes(string graphname, variable do_grids=defaultValue)
draw polar and azimuthal grids in an existing polar graph.
Definition: pearl-anglescan-process.ipf:2118
display_hemi_scan
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.
Definition: pearl-anglescan-process.ipf:1858