def low_res_mode(cube, head, wavels): '''Function to convolve spectral dimension of cube for low resolution, R~500 mode of HARMONI, covering wavelength range of 0.8-2.45 um. Because low resolution mode has variable resolution, convolution is performed in pixel space and cube is returned in pixel space. Inputs: cube: datacube head: datacube header wavels: wavelength array [um] Outputs: scaled_cube: rebinned datacube head: updated header file new_wavels: new wavelength array for datacube [um] delta_lambda: New resolution [um] lamb_per_pix: pixel dispersion [um/pixel] outR: output Resolving power ''' # - Load pixel wavelength resolution data # - Calculate pixel wavelength bins according to input cube resolution and resolution data # - cut datacube down in wavelength range if larger than full low res range # - if cube shorter than full low res range, process the full wavelength range of cube # - bin spectrum up in pixel space # - 10x hypersample and convolve with Gaussian LSF in pixel space # - resample back to normal sampling in pixel space # - Return cube in pixel space, along with header, (irregular) wavelength array, (irregular) delta_lambda array, and #(irregular) pixel dispersion array which will be half of each delta_lambda value # - output cube, updated header, new wavels, delta_lambda (NEED TO CHECK HOW TO RETURN THIS AS THIS IS USED BY BACKGROUND FUNCTION), lamb_per_pix #Load data #dat = n.genfromtxt(r500_path+'HARMONI_R500_mode_data.txt', delimiter=',') dat = n.genfromtxt(os.path.join(r500_path, 'HARMONI_R500_mode_data.txt'), delimiter=',') dellam = dat[:, 0] / dat[:, 1] #Ignore spectral dimension if input cube is coarser spectral resolution than output if head['SPECRES'] > dat[:, 2].any(): print 'Input spectral resolution coarser than output.' print 'Ignoring spectral dimension.' return cube, head, wavels, head['SPECRES'], head['CDELT3'] else: convres = n.sqrt(dat[:, 2]**2 - head['SPECRES']**2) outputres = si.interp1d(dat[:, 0], dat[:, 2]) rinterp = si.interp1d(dat[:, 0], convres) #Create new finely sampled wavelength array (0.8-2.46 um) for pixel summation newlam = n.arange(0.8, 2.46, dat[0, 2] / 100.) newres = rinterp(newlam) newrs = newlam / newres rpower = si.interp1d(newlam, newrs) dlam = si.interp1d(newlam, newres) lams = [] dlams = [] lam = newlam[0] dl = dlam(lam) lams.append(lam) dlams.append(dl) try: for i in xrange(2000): lam = nr(lam, lam + dl / 2., rpower(lam + dl / 2.)) lams.append(lam) dlams.append(dlam(lam)) dl = dlam(lam) except ValueError: print 'Pixel wavelength values determined' lams = n.array(lams) dlams = n.array(dlams) #Find relationship between wavelength and pixel no. wavetopix = n.column_stack((range(len(lams)), lams)) wtpinterp = si.interp1d(wavetopix[:, 0], wavetopix[:, 1]) #Nyquist sample pixels (2 pixels per lambda) nyqpix = n.linspace(wavetopix[0, 0], wavetopix[-1, 0], 2 * len(wavetopix[:, 0])) wavetonyqpix = n.column_stack((nyqpix, wtpinterp(nyqpix))) wtnpinterp = si.interp1d(wavetonyqpix[:, 0], wavetonyqpix[:, 1]) #Put datacube flux into photon units if head['FUNITS'] == 'erg/s/cm2/A/arcsec2' or head[ 'FUNITS'] == 'J/s/m2/A/arcsec2': cube *= (head['CDELT3'] * 10000.) else: cube *= head['CDELT3'] #Interpolate datacube onto regular pixel grid (irregular wavelength grid) with 10x hypersampling if wavels[0] < wavetonyqpix[0, 1] and wavels[-1] > wavetonyqpix[ -1, 1]: #cube wavelength range larger than low res mode print 'Cube wavelength range larger than low res mode' start = 0 end = -1 incube_interp = si.interp1d(wavels, cube, axis=0) hpix = n.linspace(wavetonyqpix[0, 0], wavetonyqpix[-1, 0], len(wavetonyqpix) * 10.) elif wavels[0] > wavetonyqpix[0, 1] and wavels[-1] < wavetonyqpix[ -1, 1]: #cube wavelength range inside low res mode print 'Cube wavelength range inside low res mode range' incube_interp = si.interp1d(wavels, cube, axis=0) start = n.where(wavetonyqpix[:, 1] > wavels[0])[0][0] end = n.where(wavetonyqpix[:, 1] > wavels[-1])[0][0] - 1 hpix = n.linspace(wavetonyqpix[start, 0], wavetonyqpix[end, 0], len(wavetonyqpix[start:end, 0]) * 10.) elif wavels[0] > wavetonyqpix[ 0, 1]: #cube short wavelength longer than low res mode shortest wavelength print 'Cube shortest wavelength larger than low res mode' incube_interp = si.interp1d(wavels, cube, axis=0) start = n.where(wavetonyqpix[:, 1] > wavels[0])[0][0] end = -1 hpix = n.linspace(wavetonyqpix[start, 0], wavetonyqpix[-1, 0], len(wavetonyqpix[start:, 0]) * 10.) elif wavels[-1] < wavetonyqpix[ -1, 1]: #cube longest wavelength shorter than low res mode longest wavelength print 'Cube longest wavelength shorter than low res mode' incube_interp = si.interp1d(wavels, cube, axis=0) start = 0 end = n.where(wavetonyqpix[:, 1] > wavels[-1])[0][0] - 1 hpix = n.linspace(wavetonyqpix[0, 0], wavetonyqpix[end, 0], len(wavetonyqpix[:end, 0]) * 10.) else: raise ValueError('Wavelength error!!!') hpixlams = wtnpinterp(hpix) hpixcube = incube_interp(hpixlams) #Convolve with Gaussian of 2 pix FWHM (hypersampled to 20 hpix FWHM) #hgauss = lr_Gauss(2/float(2.*n.sqrt(2.*n.log(2))), 0.1, pix_space=True) hgauss = Gauss(2 / float(2. * n.sqrt(2. * n.log(2))), 0.1) convcube = convolve1d(hpixcube, hgauss[:, 1], axis=0) #Resample back onto normal pixel grid hconvcube_interp = si.interp1d(hpix, convcube, axis=0) convcube = hconvcube_interp(wavetonyqpix[start:end, 0]) #final cube final_cube = convcube #Ensure flux conservation (simplified method) print 'Input cube sum = ', n.sum(hpixcube) * n.diff(hpix)[0] target = n.sum(hpixcube) * n.diff(hpix)[0] current = n.sum(final_cube) * n.diff(wavetonyqpix[start:end, 0])[0] fac = current / target final_cube = n.divide(final_cube, fac) print 'Output cube sum = ', n.sum(final_cube) * n.diff( wavetonyqpix[start:end, 0])[0] #Output wavelength values final_lams = wavetonyqpix[start:end, 1] #Output spectral sampling out_samp = outputres(final_lams) / 2. out_samp.shape = (len(out_samp), 1, 1) #Put datacube flux back into photons/wavelength units if head['FUNITS'] == 'erg/s/cm2/A/arcsec2' or head[ 'FUNITS'] == 'J/s/m2/A/arcsec2': final_cube /= (out_samp * 10000.) else: final_cube /= out_samp #Update header head.update('CTYPE3', 'NL WAVELENGTH', 'Non-linear wavelength') head.update('CRVAL3', final_lams[0]) head.update('NAXIS3', len(final_lams)) del head['CDELT3'] outR = 500 #Return final cube, updated header, new wavelengths, column_stack of (pixel no. & pixel wavelength values), lambda_per_pixel_array return final_cube, head, final_lams, wavetonyqpix[ start:end, :], out_samp, outR
def spectral_res(datacube, head, grating, wavels, gratings, spec_nyquist=True, spec_samp=1., ignoreLSF=False): '''Function that takes input datacube and rebins it to the chosen spectral resolution. It convolves datacube along wavelength axis, interpolates all spaxels along wavelength axis then extracts pixel vales for each datacube wavelength channel. Function combines both spectral resolution choice and datacube chopping in wavelength axis. Option of bypassing spectral processing by setting band=='None' and spec_nyquist=True - this ignores wavelength dimension. Inputs: datacube: object datacube head: header file for object datacube grating: string representing chosen grating. Grating choice sets R and wavelength range wavels: wavelength array for datacube gratings: dictionary of grating parameters (lambda_min, lambda_max, R) spec_nyquist: Boolean - if True, 2 pixels per resolution element. - if False, uses spec_samp value ignoreLSF: Boolean - ignore LSF convolution in spectral dimension Outputs: scaled_cube: rebinned datacube head: updated header file new_wavels: new wavelength array for datacube delta_lambda: New resolution [um] lamb_per_pix: pixel dispersion [um/pixel] resol: output R ''' print 'Spectral resolution and wavelength range.' print 'Chosen grating: ', grating bandws = gratings[grating] z, y, x = datacube.shape if ignoreLSF == True: print 'Ignoring spectral dimension!' return datacube, head, wavels, head['SPECRES'], head['CDELT3'], 0 if bandws == None and spec_nyquist == False: print 'Ignoring spectral dimension!' return datacube, head, wavels, head['SPECRES'], head['CDELT3'], 0 elif bandws != None and spec_nyquist == True: #new_res = (bandws[0]+bandws[1])/(2.*bandws[2]) new_res = bandws[2] lamb_per_pix = new_res / 2. elif bandws != None and spec_nyquist == False: #new_res = (bandws[0]+bandws[1])/(2.*bandws[2]) new_res = bandws[2] lamb_per_pix = spec_samp / 10000. elif bandws == None and spec_nyquist == True: print 'Ignoring spectral dimension!' return datacube, head, wavels, head['SPECRES'], head['CDELT3'], 0 else: print 'Ignoring spectral dimension!' return datacube, head, wavels, head['SPECRES'], head['CDELT3'], 0 print 'Current resolution = %.5f microns' % head['SPECRES'] print 'Current sampling = %.5f microns' % head['CDELT3'] print 'New resolution = %.5f microns' % new_res print 'New sampling = %.5f microns' % lamb_per_pix if head['SPECRES'] >= new_res: print 'WARNING: Input spectral resolution is coarser (or equal) than chosen output!' #Chose whether to convolve with LSF or simply resample. condition = raw_input( 'Do you want to convolve with Gaussian LSF of FWHM' ' given by band and chosen resolving power [y], or not [any other key]?: ' ) if condition == 'y': print 'Convolving with LSF' #Generate Gaussian LSF of FWHM = (bandws[0]+bandws[1])/(2.*R) sig = new_res / (2. * n.sqrt(2. * n.log(2.))) gauss_array = Gauss(sig, head['CDELT3']) #Convolve datacube array with Gaussian along wavelength axis datacube = convolve1d(datacube, gauss_array[:, 1], axis=0) else: print 'Input spectral resolution smaller than chosen output.' print 'Convolving with corresponding LSF.' #Generate Gaussian LSF of FWHM = sqrt(new_resolution**2-head['SPECRES']**2) sig = n.sqrt(new_res**2 - head['SPECRES']**2) / (2. * n.sqrt(2. * n.log(2.))) gauss_array = Gauss(sig, head['CDELT3']) #Convolve datacube array with Gaussian along wavelength axis datacube = convolve1d(datacube, gauss_array[:, 1], axis=0) ## #New wavelength values from chosen photometric band (or ignore) ## if bandws: ## new_wavels = n.arange(bandws[0], bandws[1], lamb_per_pix) ## new_wavels[-1] = bandws[1] ## #Slice datacube down to size of new wavelength array ## start = n.where(wavels < new_wavels[0])[0][-1] ## end = n.where(wavels > new_wavels[-1])[0][0] ## datacube = datacube[start:end+1,:,:] ## elif not bandws: ## new_wavels = n.arange(wavels[0], wavels[-1], lamb_per_pix) ## new_wavels[-1] = wavels[-1] ##### #Interpolate datacube onto regular pixel grid (irregular wavelength grid) with 10x hypersampling if wavels[0] <= bandws[0] and wavels[-1] >= bandws[ 1]: #cube wavelength range larger than grating choice print 'Cube wavelength range larger than grating: chopping down to grating range' new_wavels = n.arange(bandws[0], bandws[1] + lamb_per_pix / 2., lamb_per_pix) new_wavels[-1] = bandws[1] start = n.where(wavels <= new_wavels[0])[0][-1] end = n.where(wavels >= new_wavels[-1])[0][0] #datacube = datacube[start:end+1,:,:] elif wavels[0] > bandws[0] and wavels[-1] < bandws[ 1]: #cube wavelength range inside grating choice print 'Cube wavelength range inside grating range' new_wavels = n.arange(wavels[0], wavels[-1] + lamb_per_pix / 2., lamb_per_pix) new_wavels[-1] = wavels[-1] start = n.where(bandws[0] < wavels)[0][0] end = n.where(bandws[1] > wavels)[0][-1] #datacube = datacube[start:end+1,:,:] elif wavels[0] > bandws[ 0]: #cube short wavelength longer than grating shortest wavelength print 'Cube shortest wavelength larger than grating' new_wavels = n.arange(wavels[0], bandws[1] + lamb_per_pix / 2., lamb_per_pix) new_wavels[-1] = bandws[1] start = n.where(bandws[0] < wavels)[0][0] end = n.where(bandws[1] > wavels)[0][-1] #datacube = datacube[start:end+1,:,:] elif wavels[-1] < bandws[ 1]: #cube longest wavelength shorter than grating longest wavelength print 'Cube longest wavelength shorter than grating' new_wavels = n.arange(bandws[0], wavels[-1] + lamb_per_pix / 2., lamb_per_pix) new_wavels[-1] = wavels[-1] start = n.where(bandws[0] < wavels)[0][0] end = n.where(bandws[1] > wavels)[0][-1] #datacube = datacube[start:end+1,:,:] else: raise ValueError('Specres wavelength error!!!') ##### new_cube = n.zeros((len(new_wavels), y, x), dtype=float) ###New 30-05-14 #Put datacube flux into photon units if head['FUNITS'] == 'erg/s/cm2/A/arcsec2' or head[ 'FUNITS'] == 'J/s/m2/A/arcsec2': datacube *= (head['CDELT3'] * 10000.) else: datacube *= head['CDELT3'] #print 'Datacube sum = ', datacube.sum() #Bin up in spectral dimension to new pixel sampling #Iterate over x-axis and use frebin function on 2D y-z arrays for i in xrange(x): new_cube[:, :, i] = frebin(datacube[start:end + 1, :, i], (y, len(new_wavels)), True) #print 'New cube sum = ', new_cube.sum() #Put datacube flux back into photons/wavelength units if head['FUNITS'] == 'erg/s/cm2/A/arcsec2' or head[ 'FUNITS'] == 'J/s/m2/A/arcsec2': new_cube /= (lamb_per_pix * 10000.) else: new_cube /= lamb_per_pix #Update header head['CRVAL3'] = new_wavels[0] head['CDELT3'] = (new_wavels[1] - new_wavels[0]) head['NAXIS3'] = len(new_wavels) head['SPECRES'] = new_res resol = n.round(new_wavels[len(new_wavels) / 2] / bandws[2], 0) print 'Spectral resolution and wavelength range - done!' #Return new_datacube, new_wavels, updated_header return new_cube, head, new_wavels, new_res, lamb_per_pix, resol
def low_res_spec(spec, wavetopix, transmission_spec=False): '''Function to take input spectrum (e.g. Skycalc transmission or emission spectrum) and return as observed by HARMONI R=500 mode. Inputs: spec: column stacked spectrum (wavelength [um], flux) wavetopix: Column stacked Nyquist sampling pixels and pixel wavelength values for R=500 mode transmission_spec: Boolean. If True, do not multiply then divide by spectral sampling as not required. Outputs: outspec: Output spectrum (wavelength [um], flux) ''' #dat = n.genfromtxt(r500_path+'HARMONI_R500_mode_data.txt', delimiter=',') dat = n.genfromtxt(os.path.join(r500_path, 'HARMONI_R500_mode_data.txt'), delimiter=',') outputres = si.interp1d(dat[:, 0], dat[:, 2]) #Put spectrum flux into photon units (except if transmission spectrum) if not transmission_spec: specflux = spec[:, 1] * (spec[1, 0] - spec[0, 0]) elif transmission_spec: specflux = spec[:, 1] #Find relationship between wavelength and pixel no. wtnpinterp = si.interp1d(wavetopix[:, 0], wavetopix[:, 1]) #Interpolate spectrum onto regular pixel grid (irregular wavelength grid) with 10x hypersampling if spec[0, 0] < wavetopix[0, 1] and spec[-1, 0] > wavetopix[ -1, 1]: #cube wavelength range larger than low res mode inspec_interp = si.interp1d(spec[:, 0], specflux) # start = 0 # end = -1 hpix = n.linspace(wavetopix[0, 0], wavetopix[-1, 0], len(wavetopix) * 10.) elif spec[0, 0] > wavetopix[0, 1] and spec[-1, 0] < wavetopix[ -1, 1]: #cube wavelength range inside low res mode inspec_interp = si.interp1d(spec[:, 0], specflux) start = n.where(wavetopix[:, 1] > spec[0, 0])[0][0] end = n.where(wavetopix[:, 1] > spec[-1, 0])[0][0] hpix = n.linspace(wavetopix[start, 0], wavetopix[end, 0], len(wavetopix[start:end, 0]) * 10.) elif spec[0, 0] > wavetopix[ 0, 1]: #cube short wavelength longer than low res mode shortest wavelength inspec_interp = si.interp1d(spec[:, 0], specflux) start = n.where(wavetopix[:, 1] > spec[0, 0])[0][0] # end = -1 hpix = n.linspace(wavetopix[start, 0], wavetopix[-1, 0], len(wavetopix[start:, 0]) * 10.) elif spec[-1, 0] < wavetopix[ -1, 1]: #cube longest wavelength shorter than low res mode longest wavelength inspec_interp = si.interp1d(spec[:, 0], specflux) # start = 0 end = n.where(wavetopix[:, 1] > spec[-1, 0])[0][0] hpix = n.linspace(wavetopix[0, 0], wavetopix[end, 0], len(wavetopix[:end, 0]) * 10.) else: raise ValueError('Wavelength error!!!') ## inspec_interp = si.interp1d(spec[:,0], specflux) ## hpix = n.linspace(wavetopix[0,0], wavetopix[-1,0], len(wavetopix)*10.) hpixlams = wtnpinterp(hpix) hpixspec = inspec_interp(hpixlams) #Convolve with Gaussian of 2 pix FWHM (hypersampled to 20 hpix FWHM) #hgauss = lr_Gauss(2/float(2.*n.sqrt(2.*n.log(2))), 0.1, pix_space=True) hgauss = Gauss(2 / float(2. * n.sqrt(2. * n.log(2))), 0.1) convspec = convolve1d(hpixspec, hgauss[:, 1]) #Resample back onto normal pixel grid hconvspec_interp = si.interp1d(hpix, convspec) convspec = hconvspec_interp(wavetopix[:, 0]) #final spectrum final_spec = n.column_stack((wavetopix[:, 1], convspec)) #Output sampling out_samp = outputres(wavetopix[:, 1]) / 2. #Ensure flux conservation (simplified method) print 'Input spectrum sum = ', n.sum(hpixspec) * n.diff(hpix)[0] target = n.sum(hpixspec) * n.diff(hpix)[0] current = n.sum(final_spec[:, 1]) * n.diff(wavetopix[:, 0])[0] fac = current / target final_spec[:, 1] = n.divide(final_spec[:, 1], fac) print 'Output cube sum = ', n.sum(final_spec[:, 1]) * n.diff( wavetopix[:, 0])[0] #Put spectrum flux back into photons/wavelength units (except transmission spectrum) if not transmission_spec: final_spec[:, 1] /= out_samp #Return final spectrum return final_spec
def spectral_res(datacube, head, R, band, wavels, spec_nyquist=True, spec_samp=1.): '''Function that takes input datacube and rebins it to the chosen spectral resolution. It convolves datacube along wavelength axis, interpolates all spaxels along wavelength axis then extracts pixel vales for each datacube wavelength channel. Function combines both spectral resolution choice and datacube chopping in wavelength axis. Option of bypassing spectral processing by setting band=='None' and spec_nyquist=True - this ignores wavelength dimension. Inputs: datacube: object datacube head: header file for object datacube R: spectral resolving power band: string representing wavelength band choice. Option of "None" which ignores photometric bands. wavels: wavelength array for datacube spec_nyquist: Boolean - if True, 2 pixels per resolution element. - if False, uses spec_samp value Outputs: scaled_cube: rebinned datacube head: updated header file new_wavels: new wavelength array for datacube delta_lambda: New resolution [um] lamb_per_pix: pixel dispersion [um/pixel] ''' print 'Spectral resolution and wavelength range.' print 'Chosen resolution: ', R print 'Chosen band: ', band bands = { 'V': (.47, .63), 'R': (.63, .79), 'Iz': (.82, 1.03), 'J': (1.08, 1.36), 'H': (1.46, 1.83), 'K': (1.95, 2.45), 'V+R': (.47, .81), 'Iz+J': (.8, 1.36), 'H+K': (1.45, 2.45), 'V-high': (.53, .59), 'R-high': (.61, .68), 'z': (.82, .91), 'J-high': (1.17, 1.29), 'H-high': (1.545, 1.715), 'K-high': (2.09, 2.32), 'None': None } bandws = bands[band] z, y, x = datacube.shape if bandws == None and spec_nyquist == False: print 'Ignoring spectral dimension!' return datacube, head, wavels, head['SPECRES'], head['CDELT3'] elif bandws != None and spec_nyquist == True: new_res = (bandws[0] + bandws[1]) / (2. * R) lamb_per_pix = new_res / 2. elif bandws != None and spec_nyquist == False: new_res = (bandws[0] + bandws[1]) / (2. * R) lamb_per_pix = spec_samp / 10000. elif bandws == None and spec_nyquist == True: #no convolution, just interpolate and read out new wavelengths #when sig=0, gauss returns [1.,1.] so convolution does nothing. # new_res = head['SPECRES'] new_res = (wavels[0] + wavels[-1]) / (2. * R) lamb_per_pix = new_res / 2. else: print 'Ignoring spectral dimension!' return datacube, head, wavels, head['SPECRES'], head['CDELT3'] print 'Current resolution = %.5f microns' % head['SPECRES'] print 'Current sampling = %.5f microns' % head['CDELT3'] print 'New resolution = %.5f microns' % new_res print 'New sampling = %.5f microns' % lamb_per_pix if head['SPECRES'] >= new_res: print 'WARNING: Input spectral resolution is coarser (or equal) than chosen output!' #Chose whether to convolve with LSF or simply resample. condition = raw_input( 'Do you want to convolve with Gaussian LSF of FWHM' ' given by band and chosen resolving power [y], or not [any other key]?: ' ) if condition == 'y': print 'Convolving with LSF' #Generate Gaussian LSF of FWHM = (bandws[0]+bandws[1])/(2.*R) sig = new_res / (2. * n.sqrt(2. * n.log(2.))) gauss_array = Gauss(sig, head['CDELT3']) #Convolve datacube array with Gaussian along wavelength axis datacube = convolve1d(datacube, gauss_array[:, 1], axis=0) else: print 'Input spectral resolution smaller than chosen output.' print 'Convolving with corresponding LSF.' #Generate Gaussian LSF of FWHM = sqrt(new_resolution**2-head['SPECRES']**2) sig = n.sqrt(new_res**2 - head['SPECRES']**2) / (2. * n.sqrt(2. * n.log(2.))) gauss_array = Gauss(sig, head['CDELT3']) #Convolve datacube array with Gaussian along wavelength axis datacube = convolve1d(datacube, gauss_array[:, 1], axis=0) #New wavelength values from chosen photometric band (or ignore) if bandws: new_wavels = n.arange(bandws[0], bandws[1], lamb_per_pix) new_wavels[-1] = bandws[1] #Slice datacube down to size of new wavelength array start = n.where(wavels < new_wavels[0])[0][-1] end = n.where(wavels > new_wavels[-1])[0][0] datacube = datacube[start:end + 1, :, :] elif not bandws: new_wavels = n.arange(wavels[0], wavels[-1], lamb_per_pix) new_wavels[-1] = wavels[-1] new_cube = n.zeros((len(new_wavels), y, x), dtype=float) ###New 30-05-14 #Put datacube flux into photon units if head['FUNITS'] == 'erg/s/cm2/A/arcsec2' or head[ 'FUNITS'] == 'J/s/m2/A/arcsec2': datacube *= (head['CDELT3'] * 10000.) else: datacube *= head['CDELT3'] #print 'Datacube sum = ', datacube.sum() #Bin up in spectral dimension to new pixel sampling #Iterate over x-axis and use frebin function on 2D y-z arrays for i in xrange(x): new_cube[:, :, i] = frebin(datacube[:, :, i], (y, len(new_wavels)), True) #print 'New cube sum = ', new_cube.sum() #Put datacube flux back into photons/wavelength units if head['FUNITS'] == 'erg/s/cm2/A/arcsec2' or head[ 'FUNITS'] == 'J/s/m2/A/arcsec2': new_cube /= (lamb_per_pix * 10000.) else: new_cube /= lamb_per_pix #Update header head.update('CRVAL3', new_wavels[0]) head.update('CDELT3', (new_wavels[1] - new_wavels[0])) head.update('NAXIS3', len(new_wavels)) head.update('SPECRES', new_res) print 'Spectral resolution and wavelength range - done!' #Return new_datacube, new_wavels, updated_header return new_cube, head, new_wavels, new_res, lamb_per_pix