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