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