;+
;Procedure: thm_part_slice2d
;
;Purpose: Returns a 2-D slice of THEMIS ESA/SST particle distributions.
; This procedure works in conjunction with thm_part_dist_array.pro and
; thm_part_slice2d_plot.pro. See thm_crib_part_slice2d.pro for exaples.
;
; There are three methods for generating slices:
;
; Geomtric:
; Each point on the plot is given the value of the bin it instersects.
; This allows bin boundaries to be drawn at high resolutions.
;
; 2D Interpolation:
; Datapoints within the specified theta or z-axis range are projected onto
; the slice plane and linearly interpolated onto a regular 2D grid.
;
; 3D Interpolation:
; The entire 3-dimensional distribution is linearly interpolated onto a
; regular 3d grid and a slice is extracted from the volume.
;
; Notes: - Interpolation may occur across data gaps or areas with recorded zeroes
; - Higher resolution regridding will severely slow this method
;
;
;
;Calling Sequence:
; thm_part_slice2d, datArr, [datArr2, [datArr3, [datArr4]]], $
; timewin = timewin, slice_time=slice_time, $
; part_slice=part_slice
;
;
;Arguments:
; DATARR[#]: An array of pointers to 3D data structures.
; See thm_part_dist_array.pro for more.
;
;
;Keywords:
;
; SLICE_TIME: Beginning of time window in seconds since Jan. 1, 1970. If
; CENTER_TIME keyword set, then TIME is the center of the time widow
; specified by the TIMEWIN keyword.
; TIMEWIN: Length in seconds over which to compute the slice.
; CENTER_TIME: Flag that, when set, centers the time window around the time
; specified by SLICE_TIME keyword.
; UNITS: A string specifying the units to be used.
; ('counts', 'DF' (default), 'rate', 'crate', 'flux', 'eflux')
; ENERGY: Flag to plot data against energy (in eV) instead of velocity.
; LOG: Flag to apply logarithmic scaling to the radial mesure (i.e. energy/velocity).
; (on by default if /ENERGY is set)
;
; TWO_D_INTERP: Flag to use 2D interpolation method (described above)
; THREE_D_INTERP: Flag to use 3D interpolation method (described above)
;
; COORD: A string designating the coordinate system in which the slice will be
; oriented. Options are 'DSL', 'GSM', 'GSE' and the following magnetic
; field aligned coordinates (field parallel to z axis).
;
; 'xgse': The x axis is the projection of the GSE x-axis
; 'ygsm': The y axis is the projection of the GSM y-axis
; 'zdsl': The y axis is the projection of the DSL z-axis
; 'RGeo': The x is the projection of radial spacecraft position vector (GEI)
; 'mRGeo': The x axis is the projection of the negative radial spacecraft position vector (GEI)
; 'phiGeo': The y axis is the projection of the azimuthal spacecraft position vector (GEI), positive eastward
; 'mphiGeo': The y axis is the projection of the azimuthal spacecraft position vector (GEI), positive westward
; 'phiSM': The y axis is the projection of the azimuthal spacecraft position vector in Solar Magnetic coords
; 'mphiSM': The y axis is the projection of the negative azimuthal spacecraft position vector in Solar Magnetic coords
;
;
; ROTATION: The rotation keyword specifies the orientation of the slice plane
; within the given coordinates (BV and BE will be invariant between
; coordinate systems).
;
; 'BV': The x axis is parallel to B field; the bulk velocity defines the x-y plane
; 'BE': The x axis is parallel to B field; the B x V(bulk) vector defines the x-y plane
; 'xy': (default) The x axis is along the coordinate's x axis and y is along the coordinate's y axis
; 'xz': The x axis is along the coordinate's x axis and y is along the coordinate's z axis
; 'yz': The x axis is along the coordinate's y axis and y is along the coordinate's z axis
; 'xvel': The x axis is along the coordinate's x axis; the x-y plane is defined by the bulk velocity
; 'perp': The x axis is the bulk velocity projected onto the plane normal to the B field; y is B x V(bulk)
; 'perp_xy': The coordinate's x & y axes are projected onto the plane normal to the B field
; 'perp_xz': The coordinate's x & z axes are projected onto the plane normal to the B field
; 'perp_yz': The coordinate's y & z axes are projected onto the plane normal to the B field
;
;
;
; SLICE_X/SLICE_NORM: These keywords respectively specify the slice plane's
; x-axis and normal within the coordinates specified by
; COORD and ROTATION. Both keywords take 3-vectors as input.
;
; If SLICE_X is not specified then the given coordinate's
; x-axis will be used. If SLICE_X is not perpendicular to
; the normal it's projection onto the slice plane will be used.
; An error will be thrown if no projection exists.
;
; If SLICE_NORM is not specified then the given coordinate's
; z-axis will be used (slice along by x-y plane in those
; coordinates).
;
; examples:
; Slice plane perpendicular to DSL z-axis using [3,2,0] as plane's x-axis:
; (this is the same as only using SLICE_X=[3,2,1])
; COORD='dsl' (default), ROTATION='xyz' (default), SLICE_X=[3,2,1]
;
; Slice plane perp. to GSE x-axis, bulk velocity used to define plane's x-axis:
; COORD='gse', ROTATION='xvel', SLICE_NORM=[1,0,0], SLICE_X=[0,1,0]
;
; Slice plane along the B field and radial position vectors, B field used as slice's x-axis:
; COORD='rgeo', SLICE_NORM=[0,1,0], SLICE_X=[0,0,1]
;
; DISPLACEMENT: Value in m/s that specifies how far from the origin the slice
; plane will be cut.
;
; example:
; Slice plane cut at Z_gse = 500
; COORD='gse', ROTATION='xyz' (default), DISPLACEMENT=500.
;
; 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;
; positive in the right handed direction. This will
; average over all data within that range.
; e.g. [-25,25] will average data within 25 degrees
; of the slice plane about it's x-axis
;
; VEL_DATA: Name of tplot variable containing the bulk velocity data.
; This will be used for slice plane alignment and subtraction.
; If not set the bulk velocity will be automatically calculated
; from the distribution (when needed).
; MAG_DATA: Name of tplot variable containing magnetic field data.
; This will be used for slice plane alignment.
; ERANGE: Two element array specifying the energy range to be used.
; COUNT_THRESHOLD: Mask bins that fall below this number of counts after averaging.
; (e.g. COUNT_THRESHOLD=1 masks bins with counts below 1)
; RESOLUTION: Integer specifying the resolution along each dimension of the
; slice (defaults: 2D/3D interpolation: 150, geometric: 500)
; SMOOTH: An odd integer >=3 specifying the width of the smoothing window in #
; of points. Even entries will be incremented, 0 and 1 are ignored.
; Smoothing is performed with a gaussian convolution.
;
; REGRID: (2D/3D Interpolation only)
; A three element array specifying regrid dimensions in phi, theta, and
; energy respectively. If set, all distributions' data will first be
; spherically interpolated to the requested reslotution using the
; nearest neighbor. The resolution in energy will only be interpolated
; to integer multiples of the original resolution (e.g. data with 16
; energies will be interpolated to 32, 48, ...)
;
; THETARANGE: (2D interpolation only)
; Angle range, in degrees [-90,90], used to calculate slice.
; Default = [-20,20]; will override ZDIRRANGE.
; ZDIRRANGE: (2D interpolation only)
; Z-Axis range, in km/s, used to calculate slice.
; Ignored if called with THETARANGE.
;
; MSG_OBJ: Object reference to GUI message bar. If included useful
; console messages will also be output to GUI.
;
;
;Output:
; PART_SLICE: Structure to be passed to thm_part_slice2d_plot.
; {
; data: two dimensional array (NxN) containing the data to be plotted
; xgrid: N dimensional array of x-axis values for plotting
; ygrid: N dimensional array of y-axis values for plotting
; probe: string containing the probe
; dist: string or string array containing the type(s) of distribution used
; mass: assumed particle mass from original distributions
; coord: string describing the coordinate system used for the slice
; rot: string describing the user specified rotation (N/A for 2D interp)
; units: string describing the units
; twin: time window of the slice
; rlog: flag denoting radial log scaling
; ndists: number time samples included in slice
; type: flag denoting slice type (0=geo, 2=2D interp, 3=3D interp)
; zrange: two-element array containing the range of the un-interpolated data
; rrange: two-element array containing the radial range of the data
; trange: two-element array containing the numerical time range
; shift: 3-vector containing any translations made in addition to
; requested rotations (e.g. subtracted bulk velocity)
; bulk: 3-vector containing the bulk velocity in the slice plane's coordinates
; sunvec: 3-vector containing the sun direction in the slice plane's coordinates
; coord_m: Rotation matrix from original data's coordinates (DSL) to
; those specified by the COORD keyword.
; rot_m: Rotation matrix from the the specified coordinates to those
; defined by ROTATION.
; orient_m: Rotation matrix from the coordinates defined by ROTATION to
; the coordinates defined by SLICE_NORM and SLICE_X
; (column matrix of new coord's basis).
; }
;
;
;CAVEATS: Due to IDL software constraints regions containing no data
; are assigned zeros instead of NaNs.
;
;NOTES:
; In general this code makes the following assumptions about the particle data:
; - Look directions, energies, and assumed particle mass may vary between
; modes but not within a mode (this is checked within the code).
; - If assumed mass varies greatly between modes then the mass field in
; the output structure should be ignored. This will prevent 1D slice
; plots from being made with the output
;
;
;
;CREATED BY: A. Flores
; Based on work by Bryan Kerr and Arjun Raj
;
;EXAMPLES: see the crib file: thm_crib_part_slice2d.pro
;-
pro thm_part_slice2d, ptrArray, ptrArray2, ptrArray3, ptrArray4, $
; Time options
timewin=timewin, slice_time=slice_time_in, $
center_time=center_time, $
; Range limits
erange=erange, $
thetarange=thetarange, zdirrange=zdirrange, $
; Orientations
coord=coord_in, rotation=rotation, $
slice_x=slice_x, slice_norm=slice_z, $
displacement=displacement_in, $
; Support Data
mag_data=mag_data, vel_data=vel_data, $
; Type options
type=type, two_d_interp=two_d_interp, $
three_d_interp=three_d_interp, $
; Other options
units=units, resolution=resolution, $
average_angle=average_angle, smooth=smooth, $
count_threshold=count_threshold, $
subtract_counts=subtract_counts, $
subtract_bulk=subtract_bulk, $
regrid=regrid_in, slice_width=slice_width, $
log=log, energy=energy, $
; Output
part_slice=slice_struct, $
; Dummy vars to conserve backwards compatibility
; (should allow oldscripts to be run withouth issue)
xgrid=xgrid, ygrid=ygrid, slice_info=slice_info, $
onecount=onecount, $
; Other
fix_counts=fix_counts, $
msg_obj=msg_obj, fail=fail, $
_extra = _extra
compile_opt idl2
if size(ptrArray,/type) ne 10 then begin
fail = 'Invalid data structure. Input must be valid array of pointers to arrays of '+ $
'ESA or SST distributions with required tags. '+ $
'See thm_part_dist_array.'
dprint, dlevel=1, fail
return
endif
if undefined(slice_time_in) then begin
fail = 'Please specifiy a time at which to compute the slice.'
dprint, dlevel=1, fail
return
endif
if undefined(timewin) then begin
fail = 'Please specifiy a time window for the slice."
dprint, dlevel=1, fail
return
endif
valid_coords = ['dsl','gse','gsm','xgse','ygsm','zdsl','rgeo', $
'mrgeo','phigeo','mphigeo','phism','mphism']
if ~undefined(coord_in) then begin
coord = strlowcase(coord_in)
if ~in_set(coord,valid_coords) then begin
fail = 'Invalid coordinates requested. See thm_crib_part_slice2d for examples.'
dprint, dlevel=1, fail
return
endif
endif
valid_rotations = ['bv', 'be', 'xy', 'xz', 'yz', 'xvel', $
'perp', 'perp_xy', 'perp_xz', 'perp_yz']
if ~undefined(rotation) then begin
if ~in_set(strlowcase(rotation),valid_rotations) then begin
fail = 'Invalid rotation requested. See thm_crib_part_slice2d for examples.'
dprint, dlevel=1, fail
return
endif
endif
d_set = [keyword_set(ptrArray), keyword_set(ptrArray2), $
keyword_set(ptrArray3), keyword_set(ptrArray4)]
fail = ''
; Defaults
;------------------------------------------------------------
slice_time = time_double(slice_time_in[0])
if undefined(coord) then coord='dsl'
if undefined(rotation) then rotation='xy'
if undefined(units) then units = 'df'
if undefined(slice_z) then slice_z = [0,0,1.]
if keyword_set(regrid_in) then regrid = regrid_in
if keyword_set(energy) && undefined(log) then log = 1
if rotation eq 'xyz' then rotation = 'xy'
if rotation eq 'perp_xyz' then rotation = 'perp_xy'
displacement = keyword_set(displacement_in) ? displacement_in:0.
;attempt to get probe, this is a bit messy
probe = keyword_set((*ptrArray[0])[0].spacecraft) ? (*ptrArray[0])[0].spacecraft : $
strmid((*ptrArray[0])[0].project_name, 0, /reverse_offset)
if ~stregex(probe, '[abcde]', /bool, /fold_case) then probe = ''
;Type specific:
if keyword_set(two_d_interp) then type = 2
if keyword_set(three_d_interp) then type = 3
if undefined(type) then type = 0
if type gt 3 then type = 0
if keyword_set(type) && keyword_set(average_angle) then begin
dprint, dlevel=1, 'Angular averaging is only applicable to the geometric method.'+ $
'No averaging will be applied.'
return
endif
; 2d interp
if type eq 2 then begin
if undefined(smooth) then smooth = 7
if undefined(resolution) then resolution = 150
if ~keyword_set(thetarange) and ~keyword_set(zdirrange) then begin
thetarange = [-20.,20]
endif
endif
; 3D interp
if type eq 3 then begin
if undefined(smooth) then smooth = 7
if undefined(resolution) then resolution = 150
endif
; geometric
if ~keyword_set(type) then begin
regrid = 0 ;incompatible with regridding
if undefined(resolution) then resolution = 500
endif
;preserve backward compatability
if ~keyword_set(count_threshold) && keyword_set(onecount) then count_threshold = onecount
msg = 'Processing slice at ' + time_string(slice_time, format=5) +'... '
dprint, dlevel=2, msg
if obj_valid(msg_obj) then msg_obj->update, msg
; Account for multiple data types & mode changes.
; -Each ptrArray[#] input will be a pointer or pointer array.
; -The user may pass in up to 4 of such variables if requesting
; multiple data types (e.g. psif & peif). If the data spans
; a mode change then ptrArray[#] will be an array.
;------------------------------------------------------------
temp=where(d_set,c)
if c eq 1 then begin
ds = [ptrArray]
endif else if c eq 2 then begin
ds = [ptrArray,ptrArray2]
endif else if c eq 3 then begin
ds = [ptrArray,ptrArray2,ptrArray3]
endif else if c eq 4 then begin
ds = [ptrArray,ptrArray2,ptrArray3,ptrArray4]
endif else begin
fail = "Error: This should never happen, please report to the TDAS software team."
dprint,dlevel=0, fail
return
endelse
; Get the slice's time range
;------------------------------------------------------------
; get the boundaries of the time window
if keyword_set(center_time) then begin
trange = [slice_time - timewin/2, $
slice_time + timewin/2 ]
endif else begin
trange = [slice_time, $
slice_time + timewin ]
endelse
; Get support data
;------------------------------------------------------------
; Get mag data
bfield = thm_part_slice2d_getmag(ds, mag_data=mag_data, trange=trange, fail=fail)
if n_elements(bfield) eq 1 then return
; Get bulk velocity (in km/s or eV depending on slice type)
vbulk = thm_part_slice2d_getvel(ds, vel_data=vel_data, trange=trange, energy=energy, fail=fail)
if n_elements(vbulk) eq 1 then return
; Get Sun vector
sunvec = thm_part_slice2d_getsun(ds, trange=trange, fail=fail)
; Extract data from structures
; -apply energy limits
; -average date over time window
; -output r, phi, theta and dr, dphi, dtheta arrays
;------------------------------------------------------------
thm_part_slice2d_getdata, ds, units=units, trange=trange, regrid=regrid, erange=erange, energy=energy, $
data=datapoints, rad=rad, phi=phi, theta=theta, dr=dr, dp=dp, dt=dt, $
fix_counts=fix_counts, fail=fail, _extra=_extra
if keyword_set(fail) then return
; Known causes of an empty data variable should be caught before this.
if ~keyword_set(datapoints) then begin
fail = 'Unknown error extracting data from particle distributions.'
dprint, dlevel=0, fail
return
endif
; Get original data and radial ranges for plotting
; -attempt to ignore small values created from interpolation
; (useful with SST contamination removal on)
idx = where(datapoints gt 0,n)
if n gt 0 then begin
dmoms = moment(alog10(datapoints[idx]),maxmom=2)
min = 10^(dmoms[0] - 2*sqrt(dmoms[1])) ;ignore if < mean - 2*sigma
drange = minmax(datapoints[idx],min_value=min)
endif else begin
drange = [0,0.]
endelse
rrange = [ min( rad - 0.5*dr ), max( rad + 0.5*dr ) ]
; Apply radial log scaling
if keyword_set(log) then begin
thm_part_slice2d_rlog, rad, dr, displacement=displacement
endif
; Convert spherical data to cartesian coordinates for interpolation
if keyword_set(type) then begin
thm_part_slice2d_s2c, rad,theta,phi, xyz
endif
; Get/apply coordinate transformations
; -For geometric mode, transformations will be
; applied inside thm_part_slice2d_geo instead.
;------------------------------------------------------------
; Subtract bulk velocity vector
; -invalid for geometric method
; -incompatible with radial log scaling
if keyword_set(subtract_bulk) and (type ne 0) and ~keyword_set(log) then begin
thm_part_slice2d_subtract, vectors=xyz, vbulk=vbulk, vel_data=vel_data, energy=energy
endif
; Transform to GSM, GSE, or field aligned coordinates
if in_set(coord,['dsl','gse','gsm']) then begin
thm_part_slice2d_cotrans, probe=probe, coord=coord, trange=trange, fail=fail, $
vectors=xyz, bfield=bfield, vbulk=vbulk, sunvec=sunvec, matrix=ct
endif else begin
thm_part_slice2d_fac, probe=probe, coord=coord, trange=trange, mag_data=mag_data, fail=fail, $
vectors=xyz, bfield=bfield, vbulk=vbulk, sunvec=sunvec, matrix=ct
endelse
if keyword_set(fail) then return
; Transform data to the slice plane's coordinates
thm_part_slice2d_rotate, rotation=rotation, fail=fail, $
vectors=xyz, bfield=bfield, vbulk=vbulk, sunvec=sunvec, matrix=rot
if keyword_set(fail) then return
; Apply custom transformation on top of the predefined ones
thm_part_slice2d_orientslice, slice_x=slice_x, slice_z=slice_z, fail=fail, $
vectors=xyz, bfield=bfield, vbulk=vbulk, sunvec=sunvec, matrix=mt
if keyword_set(fail) then return
; Misc.
;------------------------------------------------------------
; Sort transformed vector grid
if keyword_set(xyz) then begin
sorted = sort(xyz[*,0])
xyz = xyz[sorted,*]
datapoints = datapoints[sorted]
endif
; Create slice:
;
; TYPE=0 Geometric Method
; TYPE=1 2D Nearest Neighbor Interpolation (testing only)
; TYPE=2 2D Linear Interpolation
; TYPE=3 3D Linear Interpolation
;------------------------------------------------------------
; Linear 2D interpolation from thm_esa_slice2D
if type eq 2 then begin
dprint, dlevel=4, 'Using 2d linear interpolation'
thm_part_slice2d_2di, datapoints, xyz, resolution, $
thetarange=thetarange, zdirrange=zdirrange, $
part_slice=part_slice, $
xgrid=xgrid, ygrid=ygrid, $
fail=fail
; Linear 3D Interpolation
endif else if type eq 3 then begin
dprint, dlevel=4, 'Using 3d linear interpolation'
thm_part_slice2d_3di, datapoints, xyz, resolution, $
drange=drange, displacement=displacement, $
part_slice=part_slice, $
xgrid=xgrid, ygrid=ygrid, $
fail=fail
; 2D Nearest Neighbor (for testing only)
endif else if type eq 1 then begin
dprint, dlevel=4, 'Using 2d nearest neighbor'
thm_part_slice2d_nn, datapoints, xyz, resolution, slice_orient, $
part_slice=part_slice, $
xgrid=xgrid, ygrid=ygrid, $
slice_width=slice_width, $
shift=keyword_set(subtract_bulk) ? vbulk:0, $
fail=fail
; Geometric Method
endif else begin
dprint, dlevel=4, 'Using geometric method'
thm_part_slice2d_geo, data=datapoints, resolution=resolution, $
rad=rad, phi=phi, theta=theta, dr=dr, dp=dp, dt=dt, $
ct=ct, rot=rot, mt=mt, $
displacement=displacement, average_angle=average_angle, $
msg_obj=msg_obj, msg_prefix=msg, $
part_slice=part_slice, $
xgrid=xgrid, ygrid=ygrid, $
fail=fail
endelse
if keyword_set(fail) then begin
dprint, dlevel=1, fail
return
endif
; Apply smoothing
if keyword_set(smooth) then begin
thm_part_slice2d_smooth, part_slice, smooth
endif
; If this run was used to calculate a flat-count slice then return through the same var
if keyword_set(fix_counts) then begin
fix_counts = part_slice
return
endif
; Apply count threshold/subtraction
; This will create a copy of the slice with all bins set to the specified
; threshold and use it for masking/subtraction.
if keyword_set(count_threshold) or keyword_set(subtract_counts) then begin
fix_counts = keyword_set(subtract_counts) ? subtract_counts:count_threshold
thm_part_slice2d, ptrArray, ptrArray2, ptrArray3, ptrArray4, $
; Use a flat distribution at N counts
fix_counts=fix_counts, $
; Time
timewin=timewin, slice_time=slice_time_in, center_time=center_time, $
; Range
erange=erange, thetarange=thetarange, zdirrange=zdirrange, $
; Orientations
coord=coord_in, rotation=rotation, slice_x=slice_x, slice_norm=slice_z, displacement=displacement_in, $
; Support Data
mag_data=mag_data, vel_data=vel_data, $
; Type
type=type, two_d_interp=two_d_interp, three_d_interp=three_d_interp, $
; Other
units=units, resolution=resolution, average_angle=average_angle, smooth=smooth, $
subtract_bulk=subtract_bulk, regrid=regrid_in, slice_width=slice_width, log=log, energy=energy, $
fail=fail
if ~array_equal(size(/dim,part_slice),size(/dim,fix_counts)) and ~keyword_set(fail) then begin
fail = 'Dimension of reference slice do not match data'
endif
if keyword_set(fail) then begin
fail = 'Error calculating count threshold: ' + fail
dprint, dlevel=1, fail
return
endif
if keyword_set(subtract_counts) then begin
part_slice = (part_slice - fix_counts) > 0
endif
if keyword_set(count_threshold) then begin
btidx = where(part_slice lt fix_counts,nbt)
if nbt gt 0 then begin
part_slice[btidx] = 0
endif
endif
endif
; Pass out slice information for plotting
;------------------------------------------------------------
;loop over dist structures to get name(s), time range, and mass
for i=0, n_elements(ds)-1 do begin
;dist type name
dname = array_concat( ((*ds[i]).data_name)[0], dname )
;time range of particle data
times_ind = thm_part_slice2d_intrange(ds[i], trange, n=ndat)
if ndat gt 0 then begin
trc = [ min((*ds[i])[times_ind].time), $
max((*ds[i])[times_ind].end_time) ]
tr = minmax( array_concat(trc,tr) )
endif
;mass, intra-mode mass differences checked elsewhere
mass_arr = array_concat( ((*ds[i]).mass)[0], mass )
endfor
;don't repeat distribution types in name
dname = strjoin( dname[uniq(dname,sort(dname))],'/')
;warn if masses vary by more than 1% of the median
;this is primarily in case of distributions assuming different species
mass = median(mass_arr)
if max(abs(mass-mass_arr)/mass) gt .01 then begin
dprint, dlevel=4, 'Assumed particle mass varies between distributions by > 1%. '+ $
'Mass omitted from slice metadata.'
mass = !values.f_nan
endif
;adjust radial range
if keyword_set(displacement) then begin
rrange = sqrt( (rrange^2 - displacement^2) > 0. )
endif
slice_struct = { $
; Data
data: temporary(part_slice), $ ;data values
xgrid: xgrid, $ ;x-axis values
ygrid: ygrid, $ ;y-axis values
; Metadata
probe: probe, $ ;probe
dist: dname, $ ;type of distribution (string)
mass: mass, $ ;mass in eV/(km/s)^2, will be NaN if mass varies too much
coord: coord, $ ;coordinates used (string)
rot: rotation, $ ;rotation used (string)
units: units, $ ;units (string)
xyunits: keyword_set(energy) ? 'eV':'km/s', $ ;vector units (string)
twin: timewin, $ ;length of slice in sec
type: type, $ ;integer specifying slice type (0,2,3)
energy: keyword_set(energy), $ ;flag for energy plots
zrange: drange, $ ;data range before interpolation
trange: tr, $ ;total time range of used distributions
rrange: rrange , $ ;instrument velocity/energy range
rlog: keyword_set(log), $ ;flag for radial log plot
; Support Data
shift: keyword_set(subtract_bulk) ? vbulk:0, $ ;for plotting energy limits
bulk: keyword_set(vbulk) ? vbulk:0, $ ;bulk velocity vector
sunvec: keyword_set(sunvec) ? sunvec:0, $ ;sun vector
coord_m: keyword_set(ct) ? ct:-1, $ ;DSL to COORD matrix
rot_m: keyword_set(rot) ? rot:-1, $ ;COORD to ROTATION matrix
orient_m: keyword_set(mt) ? mt:-1 $ ;COORD/ROTATION to slice plane coords matrix
}
msg = 'Finished slice at '+time_string(slice_time, format=5)
dprint, dlevel=2, msg
if obj_valid(msg_obj) then msg_obj->update, msg
; Fill dummy vars if present to preserve backwards compatibility
if arg_present(xgrid) then xgrid = 0
if arg_present(ygrid) then ygrid = 0
if arg_present(slice_info) then slice_info = 0
return
end