;+
;PROCEDURE: THM_SST_REMOVE_SUNPULSE
;Purpose:
;  Routine to perform a variety of calibrations on full distribution sst data.  
;  These can remove sun contamination and on-board masking. They can also scale 
;  the data to account for the loss of solid angle from the inability of the sst
;  to measure directly along the probe geometric Z axis and the inability to measure
;  directly along the probe geometric xy plane.(ie X=0,Y=0,Z = n or X=n,Y=m,Z=0,  are SST 'blind spots')  
;  THM_REMOVE_SUNPULSE routine should not generally be called directly.
;  Keywords to it will be passed down from higher level routines such as, thm_part_moments,
;  thm_part_moments2, thm_part_dist,thm_part_getspec, thm_sst_psif, and thm_sst_psef
;
;  Arguments:
;           dat:  the dat structure used in thm_part_dist, etc...
;
;  Keywords:
;  
;  method_clean: Simplified sun cleaning methods:
;                   Allowed options are:
;                   'manual': To use this option you need to specify the contaminated bins using the sun_bins keyword.  Specified bins are removed and interpolated over phi.
;                  
;                   'automatic': This method attempts to find contaminated bins using a statistical outlier test(modified z-score)
;                    then fills the bins by interpolation over phi.
;
;  sun_bins: method_clean manual removal bin selection.  Must be either a 64 element or a 16x64 element 0-1 array.  Bins set to 1 will be used, bins set to 0
;                  will be removed and filled.  
;                  The 64 element input is the same format as the output from edit3dbins, it removes and fills all energies at a particular angle of measure.
;                  The 16x64 element input allows the user to remove some bins at some of the 16 energies but to keep others.                                 
; 
;  
;  all_angle_median:  set this option to replace the angular distribution with the median
;                     of the data calculated over the all angles(thetas & phis) for each energy.
;                     This will generally eliminate contamination in some of the moments, but will make 
;                     analysis of angular plots impossible. It will also eliminate the velocity
;                     moment.
;  scale_sphere:  set this option to increase the value of all counts by 16%.  This accounts
;                 for the loss of phase space mentioned above.
;
;  method_sunpulse_clean:  set this to a string:  Either 'median' or 'spin_fit' or 'z_score_mod'
;              'median':  This will remove all points that are greater 
;                than 2.0 standard deviations from the median.By default they will be filled by a 
;                linear interpolation across the phi angle by default. 
;              'spin_fit':  This will remove all points that are greater
;                than 2.0 standard deviations from a spin fit across phi angle.  The equation used to
;                fit is A+B*sin(phi)+C*cos(phi). By default these points will be filled by a linear
;                interpolation across the phi angle. The fitting is done using the svdfit routine
;                from the idl distribution.
;              'z_score_mod': This will remove all points that have a modified z-score(calculated across phi) greater than 3.5 
;                The modified z-score is a normalized outlier detection test defined as follows:  
;                #1 X_Bar = median(X+1)
;                #2 Sigma = MAD = Median Absolute Deviation = median(abs(X-X_Bar))
;                #3 Z_Score_Mod = .6745*(X - X_Bar)/Sigma
;                This test can often get excellent results because it is insensitive to variation in standard deviation
;                and skew in the distributions.  
;
;  limit_sunpulse_clean: set this equal to a floating point number that will override the default of 2.0 standard
;             deviation tolerance or 3.5 z_score_tolerance, used by the sunpulse cleaning methods by default.
;             This keyword will only have an effect if the method_sunpulse_clean keyword is set.
;
;  fillin_method: Set this keyword to a string that specifies the method used to fill the points that are
;             removed via the method_sunpulse_clean or the mask_remove keywords, and bins removed when enoise_remove_method='fill'.
;             'interpolation': this routine will interpolate across the phi angle.  This is the 
;               default behavior. Interpolation is done using the interp_gap routine.
;             'spin_fit': this routine will perform a spin fit to the data after the points
;               have been removed using the equation A+B*sin(phi)+C*cos(phi).  It will then generate
;               expected values for each removed phi using the equation of fit.   The fitting is done using
;               the svdfit routine from the idl distribution.  Note that if 'spin_fit' is selected for
;               the clean method and the fill method, this routine will perform two spin fits.
;             'blank' : Just removes the data but doesn't fill with anything
;
;
;  mask_remove: Set this keyword to the proportion of values that must be 0 at all energies to determine that a mask is present.
;             Generally .99 or 1.0 is a good value.  The mask is a set of points that are set to 0 on-board the spacecraft. 
;             By default they will be filled by linear interpolation across phi.  NOTE: This argument is not actually accepted by
;             this routine, it is only documented here.  If you provide this argument to thm_part_moments, 
;             thm_part_moments2, or thm_part_getspec, those routines will appropriately set the value for the
;             mask_tot keyword to this routine.
;
; enoise_bins:  A 0-1 array that indicates which bins should be used to calculate electronic noise.  A 0 indicates that the
;               bin should be used for electronic noise calculations.  This is basically the output from the bins argument of edit3dbins.
;               It should have dimensions 16x4. NOTE: This argument is not actually accepted by
;               this routine, it is only documented here.  If you provide this argument to thm_part_moments, 
;               thm_part_moments2, or thm_part_getspec, those routines will appropriately set the value for the
;               enoise_tot keyword to this routine.
;
; enoise_bgnd_time:  This should be either a 2 element array or a 2xN element array(where n is the number of elements in enoise_bins).  
;                The arguments represents the start and end times over which the electronic background will be calculated for each
;                bin.  If you pass a 2 element array the same start and end times can be used for each bin.  If you pass a 2xN element
;                array, then the Ith bin in enoise_bins will use the time enoise_bgnd_time[0,I] as the start time and enoise_bgnd_time[1,I] as
;                the end time for the calculation of the background for that bin.  If this keyword is not set then electronic noise will not 
;                be subtracted.NOTE: This argument is not actually accepted by
;                this routine, it is only documented here.  If you provide this argument to thm_part_moments, 
;                thm_part_moments2, or thm_part_getspec, those routines will appropriately set the value for the
;                enoise_tot keyword to this routine.
;
; 
;
; enoise_remove_method(default: 'fit_median') set the keyword to a string specifying the method you want to use to calculate the electronic noise that will be subtracted 
;                This function combines values across time.  The allowable options are:
;                'min':  Use the minimum value in the time interval for each bin/energy combination.
;                
;                'average': Use the average value in the time interval for each bin/energy combination.
;                
;                'median': Use the median value in the time interval for each bin/energy combination.
;                
;                'fit_average': Fill in selected bins with a value that is interpolated across phi,  then use
;                     the average of these values across the time interval for each bin/energy combination.
;                     
;                'fit_median' : Fill in selected bins with a value that is interpolated across phi,  then use
;                     the mean of these values across the time interval for each bin/energy combination.
;                     
;                'fill': Fill in selected bins across phi, do not perform any subtraction.  This will
;                provide the cleanest looking plot, but the signal in that bin will be entirely removed.
;                 
;             
;                  NOTE: This argument is not actually accepted by
;                     this routine, it is only documented here.  If you provide this argument to thm_part_moments, 
;                     thm_part_moments2, or thm_part_getspec, those routines will appropriately set the value for the
;                     enoise_tot keyword to this routine.
;                     
;  enoise_remove_fit_method(default:'interpolation'):  Set this keyword to control the method used in 'fit_average' & 'fit_median' to
;                    fit across phi. 
;                    Options are: 
;                    'interpolation'
;                    'spin_fit' 
;                    By default, missing bins are interpolated across phi.  Setting
;                    enoise_remove_fit_method='spin_fit' will instead try to fill by fitting to a curve of the form A+B*sin(phi)+C*cos(phi).
; 
;  mask_tot:  The user should never manually set this keyword.  thm_part_moments,thm_part_moments2, & thm_part_getspec
;             will properly set this keyword, if the mask_remove keyword is set when they are called.
;
;  enoise_tot: The user should never manually set this keyword. thm_part_moments,thm_part_moments2, & thm_part_getspec
;             will properly set this keyword, if enoise keywords are set when called.
;

;
;
;
;
; Examples:  
; 
;            thm_part_moments,probe='a',inst='ps?f',method_clean='automatic'
;            
;            sun_bins=dblarr(64)+1
;            sun_bins[[30,39,40,46,55,56,61,62]] = 0 ;these are the bin numbers that will be removed 
;            thm_part_moments,probe='a',inst='ps?f',sun_method='manual',sun_bins=sun_bins
; 
;            thm_part_moments,probe='a',instrum=['ps?f'],mag_suffix='_peif_magf',scpot_suffix='_peif_sc_pot',moments='*', $
;              ,fillin_method='spin_fit',method_sunpulse_clean='spin_fit',limit_sunpulse_clean=1.8, $
;              trange=['2008-05-19','2008-05-20'],tplotsuffix='_fit_mask_fit'
;   
;            thm_part_getspec, probe='a', trange=['2007-03-23','2007-03-23'],theta=[0,45], data_type='ps?f', angle='phi', $
;              erange=[50000,100000], /mask_remove,method_sunpulse_clean='median',limit_sunpulse_clean=1.5, $
;              suffix='_fit_mask_med_t2'  
;          
;            edit3dbins,thm_sst_psef(probe='a', time_double('2008-03-01'),method_sunpulse_clean='spin_fit', $
;              limit_sunpulse_clean=1.2),ebins=4,sum_ebins=1
;
;
;SEE ALSO:
;  thm_part_moments.pro, thm_part_moments2.pro, thm_part_getspec.pro
;  thm_part_dist.pro, thm_sst_psif.pro, thm_sst_psef.pro,thm_crib_sst_contamination.pro
;  thm_sst_find_masking.pro, thm_sst_erange_bin_val.pro
;
; $LastChangedBy: pcruce $
; $LastChangedDate: 2012-08-10 09:42:49 -0700 (Fri, 10 Aug 2012) $
; $LastChangedRevision: 10800 $
; $URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/tags/spedas_4_1/projects/themis/spacecraft/particles/SST/thm_sst_remove_sunpulse.pro $
;-

;Moving to separate file
;;HELPER function
;;take the dat component of a structure and splits it into an array
;;ordered in terms of theta =  energy*angle->energy*theta*phi
;;dimensions 16*64->16*4*16,  phi is guaranteed to be contiguous but
;;not necessarily ascending(some phi may be out of phase by 180 degrees)
;;returns indices to perform this transformation
;function dat2angsplit,dat
;
;  compile_opt idl2,hidden
;  
;  index = indgen(16,64)
;  t_sort = bsort(dat.theta[0,*])
;  index = index[*,t_sort]
;  return,transpose(reform(index,16,16,4),[0,2,1]) ; this magic properly reforms and orders the dimensions  
;
;end

;HELPER function
;function to use in svd fitting for sunpulse correction
function svd_func,x,m

  compile_opt idl2,hidden

  return,[[1.0],[sin(x*!DTOR)],[cos(x*!DTOR)]]

end

;HELPER function
;performs filling using an svd fit
function do_spin_fill,dat,ref,phi

  compile_opt idl2,hidden

  dat2 = dat

  good = where(finite(dat2))
  bad = ssl_set_complement(good,indgen(n_elements(dat)))
  
  if good[0] ne -1 && bad[0] ne -1 then begin

    idx = where(dat2[good] ne 0)
    
    if idx[0] eq -1 then begin  ;if the system of equations is not-invertible because it is all zeros then add a constant offset
      dat2[good] += 1
    endif
      
    except_val = !EXCEPT  ;svdfit annoyingly reports a floating point error EVERY TIME IT OCCURS if you don't disable them entirely
    !EXCEPT = 0  
    result = svdfit(phi[good],dat2[good],a=[1,1,1],function_name='svd_func',status=stat) ;fit the data
    !EXCEPT = except_val
                     
    if stat eq 0 then begin
    ; replace values with fit points
      dat2[bad] = result[0] + result[1]*sin(phi[bad]*!DTOR)+result[2]*cos(phi[bad]*!DTOR)         
    endif else begin
      dat2[bad] = ref[bad] ;replace values with ref values to ensure there are no NaNs in the output
    endelse
      
    
    if idx[0] eq -1 then begin ;remove a constant offset if one was added
      dat2 -= 1
    endif
  endif
  
  idx = where(~finite(dat2))
  
  return,dat2

end

;fills nan's using the nearest neighbor method
;function fill_nn,x,y

;  idx = where(finite(y))

;  y_nan = y[idx]
;  x_nan = x[idx]
  
;  int = interpol(findgen(n_elements(idx)),x_nan,x)
;  return,y_nan[round(int)]

;end

function thm_sst_remove_sunpulse,dat, $
  all_angle_median=all_angle_median, $
  scale_sphere=scale_sphere, $
  method_sunpulse_clean=method_sunpulse_clean, $
  limit_sunpulse_clean=limit_sunpulse_clean, $
  fillin_method=fillin_method, $
  mask_tot=mask_tot, $
  enoise_tot=enoise_tot, $
  badbins2mask=badbins2mask,$
  method_clean=method_clean,$ ;simplified logic for sun contamination removal
  sun_bins=sun_bins,$
  no_sun=no_sun, $
  err_msg=err_msg, msg_suppress=msg_suppress

  compile_opt idl2

  ;prevents double calculation during recursive calls
  if keyword_set(no_sun) then return,dat

  if keyword_set(method_clean) then begin
    
    ;if not set, automatic and manual contamination methods will use interpolation by default
    if ~keyword_set(fillin_method) && ~is_string(fillin_method) then begin
      fillin_method = 'interpolation'
    endif
    
    if strlowcase(method_clean) eq 'automatic' then begin
      method_sunpulse_clean = 0 ;prevent interaction between multiple methods of contamination removal
    endif else if (method_clean) eq 'manual' then begin
      if undefined(sun_bins) then begin
        err_msg = 'Warning: Sun contamination removal set to manual but sun bins is not set'
        if ~keyword_set(msg_suppress) then dprint, dlevel=1, err_msg
        return,dat
      endif else begin
        dim = dimen(sun_bins)
        enoise_tot = dblarr(16,64)
        if n_elements(dim) eq 1 then begin
          idx = where(sun_bins eq 0,c)
          if c gt 0 then begin
            enoise_tot[*,idx] = replicate(!VALUES.D_NAN,16,c)
          endif else begin
            err_msg = 'Warning: No sun contamination bins selected, but sun contamination removal is turned on'
            if ~keyword_set(msg_suppress) then dprint, dlevel=1, err_msg
          endelse
        endif else if n_elements(dim) eq 2 then begin ;select sun contaminated bins by angle and energy
          idx = where(sun_bins eq 0,c) 
          if c gt 0 then begin
            enoise_tot[idx] = !VALUES.D_NAN
          endif else begin
            err_msg = 'Warning: No sun contamination bins selected, but sun contamination removal is turned on 
            if ~keyword_set(msg_suppress) then dprint, dlevel=1, err_msg
          endelse
        endif
      endelse
    endif
  endif

  ;************************************
  ;This code sets some defaults & validates inputs
  ;***********************************
  if keyword_set(limit_sunpulse_clean) && is_num(limit_sunpulse_clean,/real) then begin
    deviation = limit_sunpulse_clean
    z_score_val = limit_sunpulse_clean
  endif else begin
    deviation = 2.0
    z_score_val = 3.5
  endelse

  if keyword_set(method_sunpulse_clean) && is_string(method_sunpulse_clean) then begin
    if strmatch(strlowcase(method_sunpulse_clean),'median') then begin
      median = deviation
    endif else if strmatch(strlowcase(method_sunpulse_clean),'spin_fit') then begin
      spin_fit = deviation
    endif else if strmatch(strlowcase(method_sunpulse_clean),'z_score_mod') then begin   
      zvar_mod = z_score_val
    endif else begin
      err_msg = 'method_sunpulse_clean unrecognized, probable typo in input: ' + method_sunpulse_clean
      if ~keyword_set(msg_suppress) then dprint, dlevel=1, err_msg
      return, dat
    endelse
  endif
  
  if keyword_set(fillin_method) && is_string(fillin_method) then begin
    if strmatch(strlowcase(fillin_method),'spin_fit') then begin
      spin_fill = 1
    endif else if strmatch(strlowcase(fillin_method),'blank') then begin
      blank_fill = 1
    endif else if ~strmatch(strlowcase(fillin_method),'interpolation') then begin
      msg = 'fillin_method unrecognized, probable typo in input: ' + fillin_method
      err_msg = keyword_set(err_msg) ? [err_msg,msg]:msg
      if ~keyword_set(msg_suppress) then dprint, dlevel=1, msg
    endif
  endif 

  dat_out = dat ;don't mutate the original

  ;**********************************************
  ;This code substracts the electronic noise
  ;*********************************************
  if keyword_set(enoise_tot) && enoise_tot[0] ne -1 then begin
  
    dat_out.data -= enoise_tot
    
;Start removal here, to verify averages of enoise subtraction
;    idx = where(dat_out.data lt 0,c)
;    
;    if c gt 0 then begin
;      dat_out.data[idx] = 0
;    endif 
;Stop removal here
  
  endif

  ;****************************************************
  ;median keyword: kluge to remove sunpulse corruption
  ;This is an old option that sets all angles to the median over angle
  ;Better methods are now available
  ;****************************************************
  if keyword_set(all_angle_median) && ndimen(dat_out.data) eq 2 then begin
    dim_med = dimen(dat_out.data)
    val_med = rebin(median(dat_out.data,dimen=2),dim_med)
    dat_out.data = val_med
  endif 

  ;*****************************************************
  ;This code removes the masking, using the value passed
  ;via mask_tot
  ;*****************************************************
  if keyword_set(mask_tot) && mask_tot[0] ne -1 && ndimen(dat_out.data) eq 2 then begin
  
    mask_ang_idx = thm_sst_dat2angsplit(dat_out) ; get indices to convert 16*64->16*4*16
    mask_dat = dat_out.data[mask_ang_idx] ; get data from main stucture
    mask_phi = dat_out.phi[mask_ang_idx]
    mask_tots = mask_tot[mask_ang_idx]
      
    mask_phi[*,[0,2],0:7] -= 360  ; make phi's monotonic      
   
    idx = where(mask_tots eq 0)
   
    if idx[0] ne -1 then begin
    
      for i=0, n_elements(idx)-1 do begin
      
        en_idx = idx[i] mod 16     ; calculate dimensional indices from linear index
        th_idx = (idx[i] / 16) mod 4
        ph_idx = (idx[i] / 64)
        
        mask_dat[en_idx,th_idx,ph_idx] = !VALUES.F_NAN
      
      endfor
    
    endif
    
    mask_inv_ang_idx = bsort(mask_ang_idx)     ;calculate indices to reverse transformation
    dat_out.data = mask_dat[mask_inv_ang_idx]    ;store result
      
  endif 

  ;****************************************************************
  ;outliers keyword: remove sunpulse contamination by replacing the top n
  ;angles in the array with an svd fit
  ;This code removes the sun contamination using a certain distance from a central value
  ;Several different methods are available
  ;****************************************************************
  if (keyword_set(median) || keyword_set(spin_fit) || keyword_set(zvar_mod)) && ndimen(dat_out.data) eq 2 then begin

    rem_ang_idx = thm_sst_dat2angsplit(dat_out) ; get indices to convert 16*64->16*4*16
    rem_dat = dat_out.data[rem_ang_idx]
    rem_phi = dat_out.phi[rem_ang_idx]

    rem_phi[*,[0,2],0:7] -= 360  ; make phi's monotonic (sometimes they range from 180-360 degrees then 0-180, this makes them go from -180,180   

    for j=0L,16-1 do begin ; loop over energy
      for k=0L,4-1 do begin ; loop over theta
                            
        rem_var = reform(rem_dat[j,k,*]) ;store this loop's row of values
        rem_var_phi = reform(rem_phi[j,k,*]) ;store this loop's row of phis
          
        if keyword_set(median) then begin  
          rem_med = median(rem_var) ;calculate statistics
          rem_dev = sqrt(total((rem_var-rem_med)^2,/nan)/16)
          ;rem_min = rem_med-remove_std*rem_dev
          rem_min = 0
          rem_max = rem_med+median*rem_dev
          rem_good = where(rem_var ge rem_min and rem_var le rem_max) ;identify good values
          rem_bad = ssl_set_complement(rem_good,indgen(16))
          
          if rem_bad[0] ne -1 then begin
            rem_dat[j,k,rem_bad] = !VALUES.F_NAN ;store result    
          endif

        
        endif else if keyword_set(spin_fit) then begin
        
          idx = where(finite(rem_var))
        
          except_val = !EXCEPT  ;svdfit annoyingly reports a floating point error EVERY TIME IT OCCURS if you don't disable them entirely
         !EXCEPT = 0  
          result = svdfit(rem_var_phi[idx],rem_var[idx],a=[1,1,1],function_name='svd_func',status=rem_s) ;fit the data
         !EXCEPT = except_val
          
          if rem_s eq 0 then begin
            
            yfit = result[0] + result[1]*sin(rem_var_phi*!DTOR)+result[2]*cos(rem_var_phi*!DTOR)    
            ydev = stddev(yfit,/nan)
            ymin = 0
            ymax = yfit+spin_fit*ydev        
            ygood = where(rem_var ge ymin and rem_var le ymax) ;identify good values
            ybad = ssl_set_complement(ygood,indgen(16))
            
            if ybad[0] ne -1 && ygood[0] ne -1 then begin
              
              rem_dat[j,k,ybad] = !VALUES.F_NAN ;store result
              
            endif
          endif
        endif else if keyword_set(zvar_mod) then begin
        
          zvar_med = median(rem_var+1) ;calculate statistics
          zvar_mad = median(abs(rem_var - zvar_med))
          zvar_var = .6745*(rem_var - zvar_med)/zvar_mad
          
          zvar_good = where(zvar_var le zvar_mod)
          zvar_bad = ssl_set_complement(zvar_good,indgen(16))
        
          if zvar_bad[0] ne -1 then begin
            rem_dat[j,k,zvar_bad] = !VALUES.F_NAN ;store result    
          endif
        
        endif
         
      endfor
    endfor
    
     ;replace data
    rem_inv_ang_idx = bsort(rem_ang_idx)
    dat_out.data = rem_dat[rem_inv_ang_idx]           
      
  endif
  
  ;**************************************************
  ;perform fill, this is done in a separate step so that it can be done simulataneously for all modifications
  ;This code fills via interpolation of svd_fit
  ;**************************************************
  
  idx = where(~finite(dat_out.data))
  
  if idx[0] ne -1L then begin
  
    if ~keyword_set(blank_fill) || keyword_set(spin_fill) then begin
      fill_ang_idx = thm_sst_dat2angsplit(dat_out) ; get indices to convert 16*64->16*4*16
      fill_dat = dat_out.data[fill_ang_idx]
      fill_dat_ref = dat.data[fill_ang_idx] ; used as a reference to leave data unchanged if filling does not work
      fill_phi = dat_out.phi[fill_ang_idx]
      fill_bins = dat_out.bins[fill_ang_idx]
  
      fill_phi[*,[0,2],0:7] -= 360  ; make phi's monotonic (sometimes they range from 180-360 degrees then 0-180, this makes them go from -180,180   
  
      for j=0L,16-1 do begin ; loop over energy
        for k=0L,4-1 do begin ; loop over theta
                              
          fill_var = reform(fill_dat[j,k,*]) ;store this loop's row of values
          fill_var_ref = reform(fill_dat_ref[j,k,*])
          fill_var_phi = reform(fill_phi[j,k,*]) ;store this loop's row of phis          
                  
          triple_fill_var = [fill_var,fill_var,fill_var]  ;triple the data points to ensure that the fit wraps around the phi rotation
          triple_fill_ref = [fill_var_ref,fill_var_ref,fill_var_ref]
          triple_fill_phi = [fill_var_phi-360,fill_var_phi,fill_var_phi+360]
                  
          if keyword_set(spin_fill) then begin
            triple_fill_var = do_spin_fill(triple_fill_var,triple_fill_ref,triple_fill_phi)    
        ;    dprint,'Spin Fill'      
          endif else begin
            interp_gap,triple_fill_phi,triple_fill_var
        ;    dprint,'Interp Fill'
          endelse
              
          idx = where(~finite(triple_fill_var[16:31]),cnt)
          if cnt ne 0 then begin
            fill_dat[j,k,*] = 0
            fill_bins[j,k,*] = 0 ;if all bins got flagged as contaminated, disable those bins when constructing moments and spectra so that they don't contaminate the data
          endif else begin     
            fill_dat[j,k,*] = triple_fill_var[16:31] ;store result (only the center element of the triple)
          endelse
        endfor
      endfor    
      
      ;idx = where(~finite(fill_dat),cnt)
      
  ;    if cnt ne 0 then stop
      
        ;replace data
      fill_inv_ang_idx = bsort(fill_ang_idx)
      dat_out.data = fill_dat[fill_inv_ang_idx]
      dat_out.bins = fill_bins[fill_ang_idx]        
    endif else begin
     ; dprint,'Blank Fill'
      dat_out.bins[idx] = 0 ;if data blanking is set, disable NAN bins
      dat_out.data[idx]= 0 ;since data doesn't tolerate nans
    endelse
  endif
    
  if keyword_set(badbins2mask) then begin
     ;Zero out the bins
     bad_ang = where(badbins2mask eq 0)
     dat_out.bins[*,bad_ang] = 0
     dat_out.data[*,bad_ang] = !VALUES.D_NAN
  endif          
      
  ;*****************************************************************************        
  ;scale the input to account for the region of the sphere that is not covered
  ;This code scales the value for the loss of solid angle, if requested
  ;*****************************************************************************
  if keyword_set(scale_sphere) && ndimen(dat_out.data) eq 2 then begin
    dat_out.data *= 1.16         
  endif
              
  return,dat_out

end