function uly_spect_linrebin, SignalIn, step, WAVERANGE=waverange, $
FLUX_CONSERVE=flux_conserve, $
EXACT=exact, OVERWRITE=overwrite
compile_opt idl2
on_error, 2
if size(SignalIn,/TYPE) ne 8 then message, 'Input spectrum is undefined'
if n_elements(*SignalIn.data) eq 0 then message, 'Input spectrum undefined'
s = size(*SignalIn.data)
npix = (size(*SignalIn.data,/DIM))
if SignalIn.sampling eq 0 then begin
cpout = 0
if (n_elements(step) eq 1) then begin
if SignalIn.step eq step then cpout = 1
endif else if n_elements(step) eq 0 then cpout = 1
if keyword_set(exact) and cpout eq 1 and n_elements(waverange) gt 0 then begin
nshift = (SignalIn.start-waverange[0])/SignalIn.step mod 1d
if abs(nshift) gt 0.001 then cpout = 0
if cpout eq 1 and n_elements(waverange) eq 2 then begin
nshift = (SignalIn.start + (npix[0]-1)*SignalIn.step $
- waverange[0])/SignalIn.step mod 1d
if abs(nshift) gt 0.001 then cpout = 0
endif
endif
if cpout eq 1 then begin
step = SignalIn.step
return, uly_spect_extract(SignalIn, WAVERANGE=waverange, $
OVERWRITE=overwrite)
endif
endif
if SignalIn.sampling eq 0 then begin
indxarr = lindgen(npix[0])
borders = SignalIn.start + [-0.5d,$
(indxarr+0.5d)] * SignalIn.step
bordersLog = alog(borders)
endif else if SignalIn.sampling eq 1 then begin
indxarr = lindgen(npix[0])
bordersLog = SignalIn.start + [-0.5d,$
(indxarr+0.5d)] * SignalIn.step
borders = exp(bordersLog)
endif else if SignalIn.sampling eq 2 then begin
borders = [(*SignalIn.wavelen + shift(*SignalIn.wavelen, 1)) / 2d, 0d]
borders[0] = 2.*(*SignalIn.wavelen)[0] - borders[1]
borders[npix[0]] = 2.*(*SignalIn.wavelen)[npix[0]-1] - borders[npix[0]-1]
bordersLog = alog(borders)
endif else $
message, 'Sampling mode of input is invalid:'+SignalIn.sampling
if n_elements(step) eq 0 then begin
if SignalIn.sampling eq 0 then step = SignalIn.step $
else if SignalIn.sampling eq 2 then begin
if n_elements(waverange) gt 0 then begin
nw = value_locate(*SignalIn.wavelen, waverange)
if nw[0] eq -1 then nw[0] = 0
if n_elements(waverange) eq 1 then nw = [nw[0], npix[0]]
if nw[1] eq -1 then nw[1] = 0
endif else nw = [0d, npix[0]-1]
wr = (*SignalIn.wavelen)[nw]
vsc = alog(wr[1]/wr[0]) / npix[0] * c
endif else begin
if n_elements(waverange) gt 0 then begin
nw = (alog(waverange) - SignalIn.start)/SignalIn.step -0.5d
if n_elements(waverange) gt 1 then $
nw[1] = min([nw[1]+1, npix[0]-0.5]) $
else nw = [nw[0], npix[0]-0.5]
endif else nw = [-0.5d, npix[0]-0.5]
wr = exp(SignalIn.start + nw * SignalIn.step)
step = (wr[1]-wr[0]) / (nw[1] - nw[0])
endelse
endif
linRange = SignalIn.start + [-0.5d,(npix[0]-0.5)] * SignalIn.step
if SignalIn.sampling eq 1 then linRange = exp(linRange) else $
if SignalIn.sampling eq 2 then linRange = [(*SignalIn.wavelen)[0],(*SignalIn.wavelen)[npix-1]]
linRange += [0.5d,-0.5d]*step
if n_elements(waverange) gt 0 then begin
nshift = ceil(max([0d, (linRange[0] - waverange[0]) / step]))
linRange[0] = waverange[0] + step * nshift
if n_elements(waverange) eq 2 then $
linRange[1] = min([waverange[1], linRange[1]])
if linRange[1] lt linRange[0] then begin
message, /INFO, 'waverange is not valid: '+ $
strjoin(strtrim(waverange,2),',')
return, 0
endif
endif
nout = round((linRange[1]-linRange[0]) / step + 1)
linStart = linRange[0]
if SignalIn.sampling lt 2 then begin
if SignalIn.sampling eq 1 then linRange = alog(linRange)
nin = round((linRange[1]-linRange[0]) / SignalIn.step + 1)
endif else nin = n_elements(*SignalIn.wavelen)
dof_factor = nout/double(nin)
if linStart-step/2d gt borders[npix[0]] then begin
message, 'start value is not in the valid range', /INFO
return, 0
endif
NewBorders = linStart + (dindgen(nout+1)-0.5d) * step
dim = size(*SignalIn.data, /DIM)
n_data = n_elements(*SignalIn.data)
n_err = n_elements(*SignalIn.err)
n_dim = size(*SignalIn.data, /N_DIM)
case SignalIn.sampling of
0: flat = step/SignalIn.step
1: begin
flat = step / SignalIn.step / (linStart + dindgen(nout)*step)
if n_dim gt 1 then flat = rebin(flat, [nout, dim[1:*]])
end
else: begin
flat = fltarr(dim[0], /NOZERO)
replicate_inplace, flat, 1B
flat = xrebin(borders, flat, NewBorders, /SPLINF)
if n_dim gt 1 then flat = rebin(flat, [nout, dim[1:*]])
end
endcase
if keyword_set(overwrite) then SignalOut = SignalIn $
else SignalOut = uly_spect_alloc()
SignalIn_type = size(*SignalIn.data, /TYPE)
if keyword_set(flux_conserve) then $
*SignalOut.data = xrebin(borders,*SignalIn.data,NewBorders,/SPLINF) $
else $
*SignalOut.data = xrebin(borders,*SignalIn.data,NewBorders,/SPLINF) / flat
if SignalIn_type lt 5 then *SignalOut.data = float(temporary(*SignalOut.data))
if n_err eq n_data then begin
err = xrebin(borders,*SignalIn.err^2,NewBorders,/SPLINF)
if n_elements(*SignalIn.goodpix) ne 0 then $
minerr = min((*SignalIn.err)[*SignalIn.goodpix])^2 * n_elements(*SignalIn.err) / n_elements(err)$
else $
minerr = min(*SignalIn.err)^2 * n_elements(*SignalIn.err) / n_elements(err)
negative = where(err le minerr, cnt)
if cnt ne 0 then err[negative] = minerr
if keyword_set(flux_conserve) then *SignalOut.err = sqrt(err) $
else *SignalOut.err = sqrt(err) / flat
if dof_factor gt 1 then begin
*SignalOut.err /= sqrt(dof_factor)
endif else if SignalIn.dof_factor gt 1 then begin
d = dof_factor
if d*SignalIn.dof_factor lt 1 then d=1./SignalIn.dof_factor
*SignalOut.err /= sqrt(d)
endif
endif else if n_elements(*SignalIn.err) gt 0 then $
message, 'Error spectrum and data do not have the same number of pixels.'
if n_elements(*SignalIn.goodpix) ne 0 then begin
maskI = replicate(0, npix[0])
maskI[*SignalIn.goodpix] = 1
maskO = xrebin(borders, maskI, NewBorders, /SPLINF) / flat
*SignalOut.goodpix = where(abs(maskO-1) lt 0.1)
endif
SignalOut.title = SignalIn.title
if n_elements(*SignalIn.hdr) ne 0 then *SignalOut.hdr = *SignalIn.hdr
SignalOut.start = linStart
SignalOut.step = step
SignalOut.sampling = 0
SignalOut.dof_factor = max([1d, SignalIn.dof_factor * dof_factor])
sxaddpar, *SignalOut.hdr, 'HISTORY', 'uly_spect_linrebin, step='+strtrim(step,2)
return, SignalOut
end
pro uly_test_spect_rebin
common uly_path, uly_root
if n_elements(uly_root) ne 0 then begin
if file_test(uly_root+'/data/VazMiles_z-0.40t07.94.fits') eq 1 then $
uly_datadir = uly_root+'/data'
endif
if n_elements(uly_datadir) ne 0 then $
filetest = uly_datadir + '/VazMiles_z-0.40t07.94.fits' $
else $
message, 'Could not find the test file'
lmin = [4000.,5905.,6300.]
lmax = [5880.,6260.,6800.]
spectrum = uly_spect_read(filetest, lmin, lmax)
spec_log = uly_spect_logrebin(spectrum, vsc2)
spec_lin = uly_spect_linrebin(spec_log, step)
relat_dif = (*spectrum.data - *spec_lin.data) / *spectrum.data
print, 'n_elem (in) =', n_elements(*spectrum.data), $
' (out) =', n_elements(*spec_lin.data)
print, 'mean (in) =', mean(*spectrum.data), ' (out) =', mean(*spec_lin.data)
print, 'relat resid = ', mean(relat_dif)
if abs(mean(relat_dif)) lt 1d-3 then print, 'Test is sucessful' $
else print, 'Test failed'
end
Part of