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