def wavelength_loop(cube, head, wavels, out_cube, newsize, outspax): '''Function to take input datacube and process it iteratively through each wavelength channel as follows: - Generate PSF array for given channel - Add effect of ADR to channel - Convolve cube channel with PSF - Frebin up to chosen output spaxel scale Inputs: cube: Datacube head: Datacube header wavels: Wavelength array out_cube: Empty output cube newsize: tuple containing (x_newsize, y_newsize) array sizes outspax: output spaxels (x, y) (mas, mas) Output: cube: Processed cube head: Updated header ''' nspec = wp.NIRSpec() nspec.pupilopd = None print 'OPD = ', nspec.pupilopd oversamp = 1000. / float(outspax[0]) for l in xrange(len(wavels)): #Print percentage bar update_progress(n.round(l / float(len(wavels)), 2)) #Create PSF channel psf = nspec.calcPSF(outfile=None, source=None, filter=None, nlambda=None, monochromatic=wavels[l] * 1.E-6, oversample=oversamp, fov_arcsec=5, rebin=False) psf = psf[0].data #Convolve cube channel with PSF channel channel = psf_convolve(cube[l, :, :], psf) #Frebin datacube up to output spaxel scale newsize = (int(newsize[0]), int(newsize[1])) channel *= (head['CDELT1'] * head['CDELT2'] * 1.E-6) channel = frebin(channel, (newsize[0], newsize[1]), total=True) channel /= (outspax[0] * outspax[1] * 1.E-6) #Add channel to output cube out_cube[l, :, :] = channel return out_cube, head
def sky_background(wavels, delta_lambda, dit): '''Function that generates a sky background curve combining sky continuum, sky thermal emission and sky emission lines. Inputs: wavels: array of wavelengths for datacube delta_lambda: resolution element [um] dit: exposure time [s]. This determins how the sky emission line amplitudes vary through the exposure. Outputs: sky_bg_curve: array of total sky background [units of photons/s/m^2/um/arcsec^2] for each wavelength value in wavels ''' #Load up all datafile using n.genfromtxt(...) #sky_em = n.genfromtxt(bgpath+'ASM_background/radiance_resolution_0.15_angstroms_MICRONS.txt') sky_em = n.genfromtxt( os.path.join( bgpath, 'ASM_background/radiance_resolution_0.15_angstroms_MICRONS.txt')) #Cut down data to relevent region. se_start_arg = n.where(sky_em[:, 0] < wavels[0])[0][-1] se_end_arg = n.where(sky_em[:, 0] > wavels[-1])[0][0] sky_em_slice = sky_em[se_start_arg:se_end_arg + 1, :] if type(delta_lambda) == n.ndarray: #Low resolution mode. Use low_res_mode function to generate sky emission spectrum sky_em_spec = low_res_spec(sky_em, delta_lambda, False) binned_sky_em = sky_em_spec[:, 1].copy() else: #Convolve sky transmission array with Gaussian LSF of #FWHM = sqrt(new_resolution**2-old_resolution**2) #to fold in spectrum for each spectral pixel. input_disp = sky_em[1, 0] - sky_em[0, 0] sigma = n.sqrt(delta_lambda**2 - input_disp**2) / (2. * n.sqrt(2. * n.log(2.))) conv_sky_em = gauss_convolve(sky_em_slice, sigma, lambda_space='Linear') ###new 30-05-14 conv_sky_em_ph = conv_sky_em[:, 1] * input_disp #convert to units of photons/s/m^2/arcsec^2 binned_sky_em_ph = frebin( conv_sky_em_ph.reshape(len(conv_sky_em_ph), 1), (1, len(wavels)), True) #Total photons conserved binned_sky_em = binned_sky_em_ph / float( wavels[1] - wavels[0]) #reconvert back to photons/s/m^2/um/arcsec^2 binned_sky_em.shape = (len(wavels), 1, 1) return binned_sky_em
def pp_wavelength_channel(chann, head, wave, l, newsize, outspax): '''Function to take input datacube and process it iteratively through each wavelength channel as follows: - Generate PSF array for given channel - Add effect of ADR to channel - Convolve cube channel with PSF - Frebin up to chosen output spaxel scale Inputs: chann: cube channel head: Datacube header wave: wavelength [um] l: iteration no. out_cube: Empty output cube newsize: tuple containing (x_newsize, y_newsize) array sizes outspax: tuple containing (x, y) output spaxel scales Output: cube: Processed cube head: Updated header inspax: Input spaxel scale (mas, mas) outspax: Output spaxel scale (mas, mas) ''' nspec = wp.NIRSpec() nspec.pupilopd = None #print 'OPD = ', nspec.pupilopd oversamp = 1000. / float(outspax[0]) #Create PSF channel #print 'Wavelength = ', wave*1.E-6, 'm' psf = nspec.calcPSF(outfile=None, source=None, filter=None, nlambda=None, monochromatic=wave * 1.E-6, oversample=oversamp, fov_arcsec=5, rebin=False) psf = psf[0].data #Convolve cube channel with PSF channel chann = psf_convolve(chann, psf) #Frebin datacube up to output spaxel scale newsize = (int(newsize[0]), int(newsize[1])) chann *= (head['CDELT1'] * head['CDELT2'] * 1.E-6) chann = frebin(chann, (newsize[0], newsize[1]), total=True) chann /= (outspax[0] * outspax[1] * 1.E-6) return chann, l
def wavelength_loop(cube, head, wavels, out_cube, newsize, outspax): '''Function to take input datacube and process it iteratively through each wavelength channel as follows: - Generate PSF array for given channel - Add effect of ADR to channel - Convolve cube channel with PSF - Frebin up to chosen output spaxel scale Inputs: cube: Datacube head: Datacube header wavels: Wavelength array out_cube: Empty output cube newsize: tuple containing (x_newsize, y_newsize) array sizes outspax: output spaxels (x, y) (mas, mas) Output: cube: Processed cube head: Updated header ''' nspec = wp.NIRSpec() nspec.pupilopd = None print 'OPD = ', nspec.pupilopd oversamp = 1000./float(outspax[0]) for l in xrange(len(wavels)): #Print percentage bar update_progress(n.round(l/float(len(wavels)),2)) #Create PSF channel psf = nspec.calcPSF(outfile=None, source=None, filter=None, nlambda=None, monochromatic=wavels[l]*1.E-6, oversample=oversamp, fov_arcsec=5, rebin=False) psf = psf[0].data #Convolve cube channel with PSF channel channel = psf_convolve(cube[l,:,:], psf) #Frebin datacube up to output spaxel scale newsize = (int(newsize[0]), int(newsize[1])) channel *= (head['CDELT1']*head['CDELT2']*1.E-6) channel = frebin(channel, (newsize[0],newsize[1]), total=True) channel /= (outspax[0]*outspax[1]*1.E-6) #Add channel to output cube out_cube[l,:,:] = channel return out_cube, head
def pp_wavelength_channel(chann, head, wave, l, newsize, outspax): '''Function to take input datacube and process it iteratively through each wavelength channel as follows: - Generate PSF array for given channel - Add effect of ADR to channel - Convolve cube channel with PSF - Frebin up to chosen output spaxel scale Inputs: chann: cube channel head: Datacube header wave: wavelength [um] l: iteration no. out_cube: Empty output cube newsize: tuple containing (x_newsize, y_newsize) array sizes outspax: tuple containing (x, y) output spaxel scales Output: cube: Processed cube head: Updated header inspax: Input spaxel scale (mas, mas) outspax: Output spaxel scale (mas, mas) ''' nspec = wp.NIRSpec() nspec.pupilopd = None #print 'OPD = ', nspec.pupilopd oversamp = 1000./float(outspax[0]) #Create PSF channel #print 'Wavelength = ', wave*1.E-6, 'm' psf = nspec.calcPSF(outfile=None, source=None, filter=None, nlambda=None, monochromatic=wave*1.E-6, oversample=oversamp, fov_arcsec=5, rebin=False) psf = psf[0].data #Convolve cube channel with PSF channel chann = psf_convolve(chann, psf) #Frebin datacube up to output spaxel scale newsize = (int(newsize[0]), int(newsize[1])) chann *= (head['CDELT1']*head['CDELT2']*1.E-6) chann = frebin(chann, (newsize[0],newsize[1]), total=True) chann /= (outspax[0]*outspax[1]*1.E-6) return chann, l
def my_convolution(chann, head, newsize, outspax, psf, instpsf): #Convolve cube channel with PSF channel chann = psf_convolve(chann, psf) #Convolve cube channel with instrument PSF chann = psf_convolve(chann, instpsf) #Frebin datacube up to output spaxel scale newsize = (int(newsize[0]), int(newsize[1])) #chann *= (head['CDELT1']*head['CDELT2']*1.E-6) chann = frebin(chann, (newsize[0],newsize[1]), total=True) #chann /= (outspax[0]*outspax[1]*1.E-6) return chann
def sky_background(wavels, delta_lambda, dit): '''Function that generates a sky background curve combining sky continuum, sky thermal emission and sky emission lines. Inputs: wavels: array of wavelengths for datacube delta_lambda: resolution element [um] dit: exposure time [s]. This determins how the sky emission line amplitudes vary through the exposure. Outputs: sky_bg_curve: array of total sky background [units of photons/s/m^2/um/arcsec^2] for each wavelength value in wavels ''' #Load up all datafile using n.genfromtxt(...) #sky_em = n.genfromtxt(bgpath+'ASM_background/radiance_resolution_0.15_angstroms_MICRONS.txt') sky_em = n.genfromtxt(os.path.join(bgpath,'ASM_background/radiance_resolution_0.15_angstroms_MICRONS.txt')) #Cut down data to relevent region. se_start_arg = n.where(sky_em[:,0] < wavels[0])[0][-1] se_end_arg = n.where(sky_em[:,0] > wavels[-1])[0][0] sky_em_slice = sky_em[se_start_arg:se_end_arg+1,:] if type(delta_lambda) == n.ndarray: #Low resolution mode. Use low_res_mode function to generate sky emission spectrum sky_em_spec = low_res_spec(sky_em, delta_lambda, False) binned_sky_em = sky_em_spec[:,1].copy() else: #Convolve sky transmission array with Gaussian LSF of #FWHM = sqrt(new_resolution**2-old_resolution**2) #to fold in spectrum for each spectral pixel. input_disp = sky_em[1,0] - sky_em[0,0] sigma = n.sqrt(delta_lambda**2-input_disp**2)/(2.*n.sqrt(2.*n.log(2.))) conv_sky_em = gauss_convolve(sky_em_slice, sigma, lambda_space='Linear') ###new 30-05-14 conv_sky_em_ph = conv_sky_em[:,1]*input_disp #convert to units of photons/s/m^2/arcsec^2 binned_sky_em_ph = frebin(conv_sky_em_ph.reshape(len(conv_sky_em_ph),1), (1,len(wavels)), True) #Total photons conserved binned_sky_em = binned_sky_em_ph/float(wavels[1]-wavels[0]) #reconvert back to photons/s/m^2/um/arcsec^2 binned_sky_em.shape = (len(wavels),1,1) return binned_sky_em
def wavelength_loop(cube, head, wavels, out_cube, AO, psfvars, adrvals, newsize, outspax, adr_switch='ON'): '''Function to take input datacube and process it iteratively through each wavelength channel as follows: - Generate PSF array for given channel - Add effect of ADR to channel - Convolve cube channel with PSF - Frebin up to chosen output spaxel scale Inputs: cube: Datacube head: Datacube header wavels: Wavelength array out_cube: Empty output cube AO: AO mode [LTAO, SCAO, Gaussian] psdvars: list containing [psfparams, psfspax, psfsize, [D,eps], res_jitter, seeing, user_psf, user_psflams] adrvals: array of ADR values newsize: tuple containing (x_newsize, y_newsize) array sizes outspax: tuple containing (x, y) output spaxel scales adr_switch: ON or OFF. Turns ADR effect on or off. Output: cube: Processed cube head: Updated header inspax: Input spaxel scale (mas, mas) outspax: Output spaxel scale (mas, mas) ''' for l in xrange(len(wavels)): #Print percentage bar update_progress(n.round(l / float(len(wavels)), 2)) #Create PSF channel #If user PSF and 2D image upsf = psfvars[-2] upsflams = psfvars[-1] if type(upsf) != str and type(upsflams) == str: psf = upsf #If User PSF and 3D cube elif type(upsf) != str and type(upsflams) != str: #Interpolate PSF cube interp = interp1d(upsflams, upsf, axis=0) psf = interp(wavels[l]) elif AO == 'LTAO' or AO == 'SCAO' or AO == 'GLAO': psf = create_psf_channel(psfvars[0], l, psfvars[1], (head['CDELT1'], head['CDELT2']), psfvars[2], psfvars[3], psfvars[4]) elif AO == 'Gaussian': psf = create_Gausspsf_channel(wavels[l], psfvars[5], psfvars[3], psfvars[4], psfvars[2], Nyquist=False, psfspax=psfvars[1], output_spax=(head['CDELT1'], head['CDELT2'])) else: print 'AO = ', AO raise ValueError('AO choice error!') #Create instrument PSF array instpsf = create_instpsf(psfvars[2], psfvars[1], outspax, (head['CDELT1'], head['CDELT2'])) #Add ADR effect to channel if adr_switch == 'ON': cube[l, :, :] = add_ADR(cube[l, :, :], head, adrvals[l], 'spline3') #Convolve cube channel with PSF channel channel = psf_convolve(cube[l, :, :], psf) #Convolve cube channel with instrument PSF channel = psf_convolve(channel, instpsf) #Frebin datacube up to output spaxel scale newsize = (int(newsize[0]), int(newsize[1])) channel *= (head['CDELT1'] * head['CDELT2'] * 1.E-6) channel = frebin(channel, (newsize[0], newsize[1]), total=True) channel /= (outspax[0] * outspax[1] * 1.E-6) #Correct ADR effect if adr_switch == 'ON': adrhead = head.copy() adrhead['CDELT1'] = outspax[0] adrhead['CDELT2'] = outspax[1] channel = add_ADR(channel, adrhead, -1. * adrvals[l], 'spline3') #Add channel to output cube out_cube[l, :, :] = channel return out_cube, head
def pp_wavelength_channel(chann, head, wave, l, AO, psfvars, adrval, newsize, outspax, adr_switch): '''Function to take input datacube and process it iteratively through each wavelength channel as follows: - Generate PSF array for given channel - Add effect of ADR to channel - Convolve cube channel with PSF - Frebin up to chosen output spaxel scale Inputs: chann: cube channel head: Datacube header wave: wavelength [um] l: iteration no. out_cube: Empty output cube AO: AO mode [LTAO, SCAO, Gaussian] psfvars: list containing [psfparams, psfspax, psfsize, [D,eps], res_jitter, seeing, user_psf, user_psflams] adrval: ADR value newsize: tuple containing (x_newsize, y_newsize) array sizes outspax: tuple containing (x, y) output spaxel scales adr_switch: On or OFF. Turns ADR effect on or off Output: cube: Processed cube head: Updated header inspax: Input spaxel scale (mas, mas) outspax: Output spaxel scale (mas, mas) ''' #Create PSF channel #If user PSF and 2D image upsf = psfvars[-2] upsflams = psfvars[-1] if type(upsf) != str and type(upsflams) == str: psf = upsf #If User PSF and 3D cube elif type(upsf) != str and type(upsflams) != str: #Interpolate PSF cube interp = interp1d(upsflams, upsf, axis=0) psf = interp(wave) elif AO == 'LTAO' or AO == 'SCAO' or AO == 'GLAO': psf = create_psf_channel(psfvars[0], l, psfvars[1], (head['CDELT1'], head['CDELT2']), psfvars[2], psfvars[3], psfvars[4]) elif AO == 'Gaussian': psf = create_Gausspsf_channel(wave, psfvars[5], psfvars[3], psfvars[4], psfvars[2], False, psfvars[1], (head['CDELT1'], head['CDELT2'])) else: print 'AO = ', AO raise ValueError('AO choice or user_PSF error!') #Create instrument PSF array instpsf = create_instpsf(psfvars[2], psfvars[1], outspax, (head['CDELT1'], head['CDELT2'])) #Add ADR effect to channel if adr_switch == 'ON': chann = add_ADR(chann, head, adrval, 'spline3') #Convolve cube channel with PSF channel chann = psf_convolve(chann, psf) #Convolve cube channel with instrument PSF chann = psf_convolve(chann, instpsf) #Frebin datacube up to output spaxel scale newsize = (int(newsize[0]), int(newsize[1])) chann *= (head['CDELT1'] * head['CDELT2'] * 1.E-6) chann = frebin(chann, (newsize[0], newsize[1]), total=True) chann /= (outspax[0] * outspax[1] * 1.E-6) #"Correct" ADR effect if adr_switch == 'ON': adrhead = head.copy() adrhead['CDELT1'] = outspax[0] adrhead['CDELT2'] = outspax[1] chann = add_ADR(chann, adrhead, -1. * adrval, 'spline3') return chann, l
def spectral_res(datacube, head, grating, wavels, gratings, 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 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 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] bandws[2]: output R ''' print 'Spectral resolution and wavelength range.' print 'Chosen grating: ', grating bandws = gratings[grating] 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.*bandws[2]) lamb_per_pix = new_res/2. elif bandws != None and spec_nyquist==False: new_res = (bandws[0]+bandws[1])/(2.*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 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, bandws[2]
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
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 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