;+ ; ; Name: thm_part_slice2d_geo.pro ; ; Purpose: Helper function for thm_part_slice2d.pro ; Produces slice using each bin's boundaries. ; ; Input: ; data: N element array of data values ; rad: N element array of radial values ; phi: N element array of phi values ; theta: N element array of theta values ; dp: N element array of phi ranges ; dt: N element array of theta ranges ; dr: N element array of velocity ranges ; resolution: Single value (R) giving the number of points in each ; dimension of the slice ; average_angle: Two element array specifying an angle range over which ; averaging will be applied. The angle is measured ; from the slice plane and about the slice's x-axis. ; e.g. [-25,25] will average data within 25 degrees ; of the slice plane about it's x-axis ; ct: Rotation matrix from DSL -> desired coordinates ; rot: Rotation matrix from given coordinates to specific rotation ; (e.g. DSL, GSM -> BV, perp_xy) ; mt: Rotation matrix from specified coords/rotation into ; the slice plane's coordinates ; ; Output: ; xgrid: R element array of x-axis values for the slice ; ygrid: R element array of y-axis values for the slice ; part_slice: RxR element array containing the slice data ; ; Other Keywords: ; msg_obj: Object reference to GUI message bar. If included useful ; console messages will also be output to GUI. ; msg_prefix: String prefix to be printed with progress messages. ; ; Caveats: This routine will slow as the number of bins (N) increases. ; Averaging will significantly lengthen the require time. ; ;- pro thm_part_slice2d_geo, data=data, resolution=resolution, $ rad=r, phi=phi, theta=theta, $ dr=dr, dp=dp, dt=dt, $ ct=ct, rot=rot, mt=mt, $ displacement=displacement, $ average_angle=average_angle, $ ; Data Output part_slice=part_slice, $ xgrid=xgrid, ygrid=ygrid, $ fail=fail, $ ; Info Output msg_obj=msg_obj, msg_prefix=msg_prefix, $ ; Other _extra=_extra compile_opt idl2, hidden ;for progress messages previous_time = systime(/sec) n = float(resolution) rd = 180./!dpi tolerance = 5d-7 ;Initialize slice and coordinates part_slice = dblarr(n,n) ;Create grid of coordinates for entire slice plane vrange = max(abs(r))*[-1,1] xgrid = interpol(vrange + [-1,1]*max(dr), n) ygrid = interpol(vrange + [-1,1]*max(dr), n) u = [ [reform(xgrid # replicate(1.,n), n^2)], $ ;x [reform(replicate(1.,n) # ygrid, n^2)], $ ;y [reform(replicate(displacement,[n,n]), n^2)] ] ;z ;Rotate slice coordinates to desired location. ;The "ct" and "rot" matrices transform INTO the slice plane's coordinates. ;To determine which bins intersect the slice plane the transformtion ;is reversed and the applied to the slice itself to transorm it ;into the data's native coordinates. m = mt if keyword_set(ct) then begin if keyword_set(rot) then m = (ct # rot) # m $ else m = ct # m endif else begin if keyword_set(rot) then m = rot # m endelse u = u # transpose(m) ;Get necesary rotations for averaging. ;The coordinates of the slice plane will be rotated through the ;specified angle range. A separate search will be done at each ;new plane. The number of planes is determined from the desired ;resolution and the width of the average. if keyword_set(average_angle) then begin alpha = minmax(average_angle) ;number of additional slices to average over na = (2 * sqrt(n) * (alpha[1]-alpha[0])/90.) > 2 ;copy slice's x-vector xv = m[*,0] ## replicate(1d,na) ;interpolate across the angle range a = ([dindgen(na-1)/(na-1),1] * (alpha[1]-alpha[0])) + alpha[0] ;constuct quaternion array to get rotation matricies qs = qcompose(xv,a/rd, /free) ;quaternions to rotate about x by a ms = qtom(qs) ;get matricies if n_elements(ms) eq 1 then begin fail = 'Error: Cannot construct rotation matrices for angular averaging.' dprint, dlevel=0, fail return endif ; Testing vectorization... ; ut = u ; for i=0, na-1 do begin ; ut = [ [temporary(ut)], [qrotv2(qs[i,*],u)] ] ; endfor ; ; u = temporary(ut) ; ; ix = lindgen(na)*3 ; iy = ix+1 ; iz = ix+2 ; ; ;Convert transformed slice coordinates to spherical ; pcoords = rd * atan(u[*,iy],u[*,ix]) ;phi ; tcoords = rd * atan(u[*,iz], sqrt(u[*,ix]^2 + u[*,iy]^2)) ;theta ; rcoords = sqrt(u[*,ix]^2 + u[*,iy]^2 + temporary(u[*,iz]^2));r endif else na = 0 ;simplify first loop below ;Loop over slice planes (if averaging over angle) ;A vectorized method was tested and took longer. weight = bytarr(size(part_slice,/dim)) np = n_elements(data) for j=-1, na-1 do begin ; ut = j ge 0 ? qrotv2(qs[j,*],u):u ut = j ge 0 ? reform(ms[j,*,*]) ## u:u ;Convert transformed slice coordinates to spherical pcoords = rd * atan(ut[*,1],ut[*,0]) ;phi tcoords = rd * atan(ut[*,2], sqrt(total(ut[*,0:1]^2,2)) ) ;theta rcoords = sqrt(ut[*,0]^2 + ut[*,1]^2 + ut[*,2]^2);r ;Loop over bins to determine what region each bin covers on the slice plane. for i=0, np-1 do begin if data[i] eq 0 then continue ; Theta-- tlim = [ theta[i]-0.5*dt[i], theta[i]+0.5*dt[i] ] ;account for rounding errors ;this is particularly important for DSL x-y cuts tr = where( abs(tlim - round(tlim)) lt tolerance, ntr) if ntr gt 0 then tlim[tr] = round(tlim[tr]) t = (tcoords gt tlim[0]) and (tcoords le tlim[1]) if total(t) lt 1 then continue ; Phi-- plim = [ phi[i]-0.5*dp[i], phi[i]+0.5*dp[i] ] ; keep limits within [-180,180] over = where(plim gt 180, no) under = where(plim lt -180, nu) if no gt 0 then plim[over] += -360 if nu gt 0 then plim[under] += 360 ;account for rounding errors pr = where( abs(plim - round(plim)) lt tolerance, npr) if npr gt 0 then plim[pr] = round(plim[pr]) ;determine which region ( p0->p1 or p1->p0) the bin spans if plim[0] gt plim[1] then begin p = (pcoords gt plim[0]) or (pcoords le plim[1]) endif else begin p = (pcoords gt plim[0]) and (pcoords le plim[1]) endelse if total(p) lt 1 then continue ; R (velocity/energy)-- s = (rcoords ge r[i]-0.5*dr[i]) and (rcoords lt r[i]+0.5*dr[i]) ; if total(r) lt 1 then continue ; Combine criteria and assign values-- bidx = where( p and t and s, nb) ; bidx = where( total(p,2) and total(t,2) and total(r,2), nb) if nb gt 0 then begin weight[bidx]++ part_slice[bidx] += data[i] endif ;output progress messages every 10 seconds if systime(/sec) - previous_time gt 6 then begin msg = strtrim(long( 100.*((j+1)*np + i)/((na>1)*np) ),2) + '% complete' if keyword_set(msg_prefix) then msg = msg_prefix + msg dprint, dlevel=2, msg if obj_valid(msg_obj) then msg_obj->update, msg previous_time = systime(/sec) endif endfor endfor ; ;testing: ; tools ; a = long(unique(weight)) ; print, '------------' ; for i=0, n_elements(a)-1 do begin ; b = where(weight eq a[i], nb) ; print, strtrim(a[i],2)+': '+strtrim(nb,2)+' ('+strtrim(100.*nb/n_elements(weight),2)+'%)' ; endfor ;Average areas where bins overlapped adj = where(weight eq 0, na) if na gt 0 then weight[adj] = 1b part_slice = part_slice / weight return end