def trim_cube(cube, y1=11, y2=70, x1=6, x2=28, outfile=None): """Trim spatial dimensions of data cube and adjust WCS accordingly. Parameters ---------- cube : DataCube or str Data cube to be trimmed y1, y2, x1, x2 : int Pixels to keep in trimmed cube (1-indexed as might be represented in DS9) outfile : str, optional File name to write to Returns ------- cube : DataCube Trimmed data cube """ if isinstance(cube, str): cube = DataCube(cube) cube.data = cube.data[:, y1 - 1:y2 - 1, x1 - 1:x2 - 1] crpix_old = cube.wcs.wcs.crpix cube.wcs.wcs.crpix[0] = crpix_old[0] - (x1 - 1) cube.wcs.wcs.crpix[1] = crpix_old[1] - (y1 - 1) if outfile is not None: cube.write(outfile) return cube
def subtract_master_sky(scicubes, mastersky, outdir=None, suffix='mskysub.fits'): if type(scicubes) == list: for i, sc in enumerate(scicubes): if not isinstance(sc, DataCube): cube = DataCube(sc) rootfn = sc.split('/')[-1][:-5] cubedatsub = cube.data.transpose() - mastersky cube.data = cubedatsub.transpose() if outdir is not None: cube.write(outdir + rootfn + '_' + suffix) else: if not isinstance(scicubes, DataCube): cube = DataCube(scicubes) rootfn = scicubes.split('/')[-1][:-5] else: cube = scicubes rootfn = '' cubedatsub = cube.data.transpose() - mastersky cube.data = cubedatsub.transpose() if outdir is not None: cube.write(outdir + rootfn + '_' + suffix) return cube
def trim_cube(cube, y1=11, y2=70, x1=6, x2=28, outfile=None): if isinstance(cube, str): cube = DataCube(cube) cube.data = cube.data[:, y1 - 1:y2 - 1, x1 - 1:x2 - 1] crpix_old = cube.wcs.wcs.crpix cube.wcs.wcs.crpix[0] = crpix_old[0] - (x1 - 1) cube.wcs.wcs.crpix[1] = crpix_old[1] - (y1 - 1) if outfile is not None: cube.write(outfile) return cube
def extract_spectrum(cube,pixels,wvslice=None): from linetools.spectra.xspectrum1d import XSpectrum1D if isinstance(cube,str): cube = DataCube(cube) if wvslice is not None: cube = kt.slice_cube(cube,wvslice[0],wvslice[1]) dat = cube.data # Get rid of NaNs dc = dat.copy() nans = np.where(np.isnan(dc)) dc[nans]=0 # Perform the extraction spaxels = [] for i,px in enumerate(pixels): thisspec = dc[:,px[0],px[1]] spaxels.append(thisspec) spaxels=np.array(spaxels) medspec = np.median(spaxels, axis=0) # Get the wavelength array newwavearr = cube.wavelength # Create the spectrum try: spec = XSpectrum1D(wave = newwavearr,flux=medspec) except: import pdb; pdb.set_trace() return spec
def slice_cube(cube, wave1, wave2, outfile=None): """Extract portion of cube extracted in wavelength space. Parameters ---------- cubefile wave1 wave2 outfile Returns ------- """ if isinstance(cube, str): cube = DataCube(cube) dat = cube.data wcs = cube.wcs else: dat = cube.data wcs = cube.wcs newwavearr = cube.wavelength if np.all(newwavearr < 1e-3): newwavearr *= 1e10 tokeep = np.where((newwavearr >= wave1) & (newwavearr <= wave2))[0] wslice = slice(tokeep[0], tokeep[-1] + 1) sl2 = slice(0, np.shape(dat)[1]) sl3 = slice(0, np.shape(dat)[2]) datslice = dat[tokeep, :, :] try: wcsslice = wcs.slice((wslice, sl2, sl3)) except: import pdb pdb.set_trace() newhdulist = wcsslice.to_fits() newhdulist[0].data = datslice if outfile is not None: newhdulist.writeto(outfile, overwrite=True) return DataCube(newhdulist)
def loadRtModel(biconeangle=80, incline=40, extent=30, modeldir='BRP19_conv', suffix='spec_conv1p6_rebinxy_wcstp_convspecrb.fits', filename=None): '''Convolve and rebin a radiative transfer model cube in the spectral direction Parameters ---------- biconeangle : int Opening angle of the biconical outflow: [10,30,45,60,80] incline : int Inclination angle of the disk relative to line of sight: [40,60,80] extent : int Outer extent of outflow (in kpc): [ Returns ------- modelcube : DataCube Radiative transfer model cube ''' if modeldir[-1] != '/': modeldir += '/' if filename is not None: try: modelcube = DataCube('{}{}'.format(modeldir, filename)) return modelcube except: modelcube = DataCube(filename) return modelcube else: raise ValueError('Model datacube file not found') if extent != 30: fname = '{}brp19_biconical{}_rw{}_disk_theta{}_{}'.format( modeldir, biconeangle, extent, incline, suffix) else: fname = '{}brp19_biconical{}_disk_theta{}_{}'.format( modeldir, biconeangle, incline, suffix) modelcube = DataCube(fname) return modelcube
def trim_cube_relpix(cube, cenpix, dx, dy, zeroindex=True, outfile=None, dims='yxz'): """Trim spatial dimensions of data cube relative to some central pixel and adjust WCS accordingly. Parameters ---------- cube : DataCube or str Data cube to be trimmed cenpix : tuple Central pixel indices as (y,x) dx : int Number of pixels to keep in the x-direction dy : int Number of pixels to keep in the y-direction zeroindex : bool, optional If True, cenpix is true index of central pixel but 0-indexed array If False, 1-indexed outfile : str, optional File name to write to Returns ------- cube : DataCube Trimmed data cube """ if isinstance(cube, str): cube = DataCube(cube) if not zeroindex: cenpix[0] -= 1. cenpix[1] -= 1. if dims == 'zyx': cube.data = cube.data[:, cenpix[0][0] - dy + 1:cenpix[0][0] + dy - 1, cenpix[1][0] - dx + 1:cenpix[1][0] + dx - 1] elif dims == 'yxz': cube.data = cube.data[cenpix[0][0] - dy + 1:cenpix[0][0] + dy - 1, cenpix[1][0] - dx + 1:cenpix[1][0] + dx - 1, :] elif dims == 'yx': cube.data = cube.data[cenpix[0][0] - dy + 1:cenpix[0][0] + dy - 1, cenpix[1][0] - dx + 1:cenpix[1][0] + dx - 1] crpix_old = cube.wcs.wcs.crpix cube.wcs.wcs.crpix[0] = crpix_old[0] - (dx - 1) cube.wcs.wcs.crpix[1] = crpix_old[1] - (dy - 1) if outfile is not None: cube.write(outfile) return cube
def extract_spectrum(cube,pixels,wvslice=None,method='median',varcube=None, spatial_scale_xy=None): ## KHRR: if spatial_scale_xy is not None, flux in units of cgs / sq. arcsec are assumed ## This is now only implemented with the 'sum' method from linetools.spectra.xspectrum1d import XSpectrum1D if isinstance(cube,str): cube = DataCube(cube) if wvslice is not None: cube = kt.slice_cube(cube,wvslice[0],wvslice[1]) if varcube is not None: varcube = kt.slice_cube(varcube, wvslice[0], wvslice[1]) ##import pdb; #pdb.set_trace() dat = cube.data # Get rid of NaNs dc = dat.copy() nans = np.where(np.isnan(dc)) dc[nans]=0 # Perform the extraction if method == 'median': if np.shape(np.array(pixels))==(2,): extspec = dc[:,pixels[0],pixels[1]] else: spaxels = [] for i,px in enumerate(pixels): thisspec = dc[:,px[0],px[1]] spaxels.append(thisspec) spaxels=np.array(spaxels) extspec = np.median(spaxels, axis=0) sigspec = -99. * np.ones(np.shape(dc)[0]) elif method == 'mean': if np.shape(np.array(pixels))==(2,): extspec = dc[:,pixels[0],pixels[1]] else: spaxels = [] for i,px in enumerate(pixels): thisspec = dc[:,px[0],px[1]] spaxels.append(thisspec) spaxels=np.array(spaxels) extspec = np.mean(spaxels, axis=0) sigspec = -99. * np.ones(np.shape(dc)[0]) elif method == 'sum': if np.shape(np.array(pixels))==(2,): extspec = dc[:,pixels[0],pixels[1]] else: spaxels = [] for i,px in enumerate(pixels): thisspec = dc[:,px[0],px[1]] spaxels.append(thisspec) spaxels=np.array(spaxels) sigspec = -99. * np.ones(np.shape(dc)[0]) if spatial_scale_xy is None: extspec = np.sum(spaxels, axis=0) else: spxsz = spatial_scale_xy[0] * spatial_scale_xy[1] extspec = spxsz * np.sum(spaxels, axis=0) else: # do the weighted mean vardat = varcube.data vdc = vardat.copy() if np.shape(np.array(pixels))==(2,): extspec = dc[:,pixels[0],pixels[1]] else: spaxels = [] varspaxels = [] for i, px in enumerate(pixels): thisspec = dc[:, px[0], px[1]] thisvar = vdc[:, px[0], px[1]] spaxels.append(thisspec) varspaxels.append(thisvar) spaxels = np.array(spaxels) ivarspaxels = 1./np.array(varspaxels) extspec = np.sum(spaxels*ivarspaxels, axis=0)/np.sum(ivarspaxels,axis=0) sigspec = 1./np.sqrt(np.sum(ivarspaxels,axis=0)) # Get the wavelength array newwavearr = cube.wavelength # Create the spectrum try: spec = XSpectrum1D(wave = newwavearr,flux=extspec,sig=sigspec) except: import pdb; pdb.set_trace() return spec
def rtModel_conv_rb_spec(input, outfil=None, specR=1800., zgal=0.6942, restlam=2796.35, dlam_rb=None, fmt=['lam', 'y', 'x'], return_cube=True): '''Convolve and rebin a radiative transfer model cube in the spectral direction Parameters ---------- input : str or DataCube Input filename or DataCube to convolve/rebin spectrally outfil : str, optional Output filename specR : float, optional Resolving power of spectrum zgal : float, optional Redshift of object restlam : float, optional Reference rest-frame wavelength for calculating kernel sigma dlam_rb : float, optional New wavelength bin size; if None, do not rebin fmt : list, optional Axis order of data cube, must have 'x', 'y', and 'lam' in some order return_cube : bool, optional If True, return DataCube object Returns ------- newwave : array Wavelength vector (same as that of input cube if dlam_rb is None) specconv_cube : 3D array Datacube with convolved spaxels (spatial, spatial, spectral) ''' from linetools.spectra.xspectrum1d import XSpectrum1D dlam_obs = restlam * (1.0 + zgal) / specR dlam_rest = dlam_obs / (1.0 + zgal ) # FWHM of resolution element in Angstroms if isinstance(input, str): ### Assume data format is as the output of ### KR's read_spec_output.read_fullfits_conv_rebin() hdu = fits.open(input) data_pad = hdu[0].data # Original data, just padded cubedat = hdu[1].data # Spatially convolved data wave = hdu[2].data # Wavelength array nx, ny, nlam = cubedat.shape cubewcs = None else: wave = input.wavelength / (1. + zgal) cubedat = input.data cubewcs = input.wcs ### Establish dimensions of input cube xs = fmt.index('x') ys = fmt.index('y') sp = fmt.index('lam') cdims = cubedat.shape nlam = cdims[sp] nx = cdims[xs] ny = cdims[ys] ### Rearrange the cube (temporarily) : (y,x,lam) cubedat_tp = np.transpose(cubedat, axes=[ys, xs, sp]) fmt_internal = ['y', 'x', 'lam'] ### Set up kernel to convolve spaxels dwv = np.abs(wave[1] - wave[0]) fwhm_specpix = dlam_rest / dwv # FWHM in number of pixels stddev_specpix = fwhm_specpix / (2.0 * (2.0 * np.log(2.0))**0.5) spec_kernel = Gaussian1DKernel(stddev_specpix) ### Rebin, if desired, and convolve if dlam_rb is None: specconv_cube = np.zeros((ny, nx, nlam)) newwave = wave for spaxx in range(nx): for spaxy in range(ny): spax_spec = cubedat_tp[spaxy, spaxx, :] conv_spec = convolve(spax_spec, spec_kernel, normalize_kernel=True) specconv_cube[spaxy, spaxx, :] = conv_spec else: waveq = wave * u.Angstrom newwave = np.arange(int(wave[0]), int(wave[-1]), dlam_rb) * u.Angstrom specconv_cube = np.zeros((ny, nx, len(newwave))) for spaxx in range(nx): for spaxy in range(ny): spax_spec = cubedat_tp[spaxy, spaxx, :] conv_spec = convolve(spax_spec, spec_kernel, normalize_kernel=True) # Use the linetools rebinning method csX1d = XSpectrum1D(wave=waveq, flux=conv_spec) cs_rb = csX1d.rebin(newwave) try: specconv_cube[spaxy, spaxx, :] = cs_rb.flux except: import pdb pdb.set_trace() if cubewcs is not None: cubewcs.wcs.pc[2, 2] = dlam_rb ### Probably shouldn't be hard-coded ### Transpose back to input dimensions axs = ['a'] * 3 for cc in fmt_internal: axs[fmt.index(cc)] = fmt_internal.index(cc) newdat = np.transpose(specconv_cube, axes=axs) if return_cube: newcube = DataCube(wavelength=newwave, data=newdat, include_wcs=cubewcs) return newwave, newcube else: return newwave, specconv_cube
def addWcsRtModel(inp, ref, outfile, spatial_scale=0.2, zgal=0.6942, center=('12 36 19.811', '+62 12 51.831'), PA=27): ### Load in the model file inpdat = fits.open(inp) rtcube = DataCube(inp, include_wcs=False) rtcube.wavelength = inpdat[2].data rtcube.data = inpdat[1].data wavearr = rtcube.wavelength ### Load in the reference file if necessary if not isinstance(ref, DataCube): refcube = DataCube(ref) else: refcube = inp refdat = refcube.data refwave = refcube.wavelength nbhdu = transform.narrowband(refcube, 4000., 5000.) refnb = nbhdu.data refwcs = WCS(nbhdu.header) ### Rearrange the cube newdat = np.transpose(rtcube.data, axes=[2, 1, 0]) ### Get the pixel scale in the spectral dimension diff = wavearr[1:] - wavearr[:-1] if not np.all(diff == diff[0]): raise ValueError('Wavelength array not uniformly sampled') spectral_scale = diff[0] ### Set scale and reference positions wave1 = wavearr[0] * (1. + zgal) spectral_scale *= (1. + zgal) ### Get the bright pixel from reference cube brightpix, brightcoords = utils.bright_pix_coords(refnb, refwcs) ### Create the new WCS newwcs = WCS(naxis=3) spatscaledeg = spatial_scale * cosmo.arcsec_per_kpc_proper(zgal) / 3600. print(spatscaledeg) if center is not None: cencoords = SkyCoord(center[0], center[1], unit=(u.hourangle, u.deg)) else: cencoords = brightcoords newwcs.wcs.crpix = np.array([150.5, 150.5, 1]) newwcs.wcs.crval = np.array([cencoords.ra.deg, cencoords.dec.deg, wave1]) newwcs.wcs.cdelt = np.array([8.0226e-6, 8.0226e-6, spectral_scale]) newwcs.wcs.cunit = ['deg', 'deg', 'Angstrom'] newwcs.wcs.ctype = ('RA---TAN', 'DEC--TAN', 'VAC') rotangle = np.radians(PA) # Assuming PA given in degrees psmat = np.array([[ newwcs.wcs.cdelt[0] * np.cos(rotangle), -newwcs.wcs.cdelt[1] * np.sin(rotangle), 0. ], [ newwcs.wcs.cdelt[0] * np.sin(rotangle), newwcs.wcs.cdelt[1] * np.cos(rotangle), 0. ], [0., 0., 1.]]) newwcs.wcs.cd = psmat newhdu = newwcs.to_fits() newhdu[0].header['PC3_3'] = spectral_scale newhdu[0].data = newdat newhdu.writeto(outfile, overwrite=True)
def align_cubes(cubelist, obj_align, interp_method='nearest'): ra_obj = obj_align.ra.deg dec_obj = obj_align.dec.deg wobjs = [] cenpixs = [] interps = [] for i, cube in enumerate(cubelist): if isinstance(cube, str): cube = DataCube(cube) dat = cube.data thisw = cube.wcs else: dat = cube.data thisw = cube.wcs if i == 0: cubedim = np.shape(dat) print(cubedim) inp = (np.arange(cubedim[0]), np.arange(cubedim[1]), np.arange(cubedim[2])) wobjs.append(thisw) cp = thisw.wcs_world2pix([[ra_obj, dec_obj, 1]], 1) # (ra,dec,lambda) cenpixs.append(cp[0]) try: thisinterp = RegularGridInterpolator((inp[0], inp[1], inp[2]), dat, method=interp_method, bounds_error=False) except: import pdb pdb.set_trace() interps.append(thisinterp) ### Must now figure out dimensions of new cube! cenpixs = np.array(cenpixs) try: xmin = np.min(cenpixs[:, 0]) except: import pdb pdb.set_trace() #import pdb; pdb.set_trace() xmax = np.max(cenpixs[:, 0]) ymin = np.min(cenpixs[:, 1]) ymax = np.max(cenpixs[:, 1]) xdiff = np.ceil(xmax - xmin) ydiff = np.ceil(ymax - ymin) ### Generate new data cubes with bigger sizes but that will align newcubedims = (cubedim[0], int(cubedim[1] + xdiff), int((cubedim[2] + ydiff))) # Modify original header to put object coords in center newhdr = cube.header.copy() newhdr['CRVAL1'] = ra_obj newhdr['CRVAL2'] = dec_obj newhdr['CRPIX1'] = (newcubedims[2] + 1.) / 2. newhdr['CRPIX2'] = (newcubedims[1] + 1.) / 2. newwcs = WCS(newhdr) newcubes = [] # Find coordinates of each pixel in newcube idxs = (np.arange(newcubedims[0]), np.arange(newcubedims[1]), np.arange(newcubedims[2])) idxgrid = np.meshgrid(idxs[0], idxs[1], idxs[2], indexing='ij') newcoords = newwcs.wcs_pix2world(idxgrid[2] + 1, idxgrid[1] + 1, idxgrid[0], 1) #pixs = newwcs.wcs_world2pix(coords[0], coords[1], coords[2], 1) #pixs = np.array(pixs) for i, terp in enumerate(interps): # What pixels in the old cube would correspond to the new cubes coords? thiscubepix_newcoords = wobjs[i].wcs_world2pix(newcoords[0], newcoords[1], newcoords[2], 0) thiscubepix_newcoords = np.array(thiscubepix_newcoords) tcp_nc_x, tcp_nc_y, tcp_nc_wave = thiscubepix_newcoords # What would the new pixel values and flux in the single cube be? newflux = terp((tcp_nc_wave, tcp_nc_y, tcp_nc_x)) newcubes.append(newflux) return newcubes, newwcs
def white_light_offset(icubelist, outputdir_nb='nb_off/', outputdir_cubes='corrCubes/', waverange=[4000., 5500.], slicer='M', write_aligned_nb=True, cube_prefix='newBrightOffset_', varcubelist=None, pixrange=None, trim=True, nb_subgrad=True): import os ### make narrowband output directory if necessary if not os.path.isdir(outputdir_nb): os.makedirs(outputdir_nb) if isinstance(icubelist[0], DataCube): pass else: cl = [DataCube(cc) for cc in icubelist] icubelist = cl ### prep variance cubes if provided if varcubelist is not None: if isinstance(varcubelist[0], DataCube): pass else: vcl = [DataCube(cc) for cc in varcubelist] varcubelist = vcl ### choose range of pixels appropriate for slicer if slicer in ['M', 'medium', 'Medium']: if pixrange is None: pixrange = [20, 79, 7, 29] trimrange = [20, 79, 7, 29] elif slicer in ['L', 'large', 'Large']: if pixrange is None: pixrange = [16, 80, 4, 25] trimrange = [16, 80, 4, 25] ### trim cubes if desired if trim is True: tricubelist = [] trvcubelist = [] for i, cc in enumerate(icubelist): tcube = trim_cube(cc, trimrange[0] + 1, trimrange[1] + 1, trimrange[2] + 1, trimrange[3] + 1) vcube = trim_cube(varcubelist[i], trimrange[0] + 1, trimrange[1] + 1, trimrange[2] + 1, trimrange[3] + 1) tricubelist.append(tcube) trvcubelist.append(vcube) icubelist = tricubelist varcubelist = trvcubelist ### create narrowband images nbimages = [] for cube in icubelist: nbout = outputdir_nb + 'nb_' + cube.filename.split('/')[-1] nb = narrowband(cube, waverange[0], waverange[1], outfile=nbout) if nb_subgrad: nbsubdat, nbsubwcs = subtract_gradient(nbout, degree=1, trim=None, outfile=nbout) nbsub = DataCube(nbout) nbimages.append(nbsub) else: nbimages.append(nb) ### pick one of the narrowband images to use as reference refnb = nbimages[0] refdat = refnb.data refwcs = WCS(refnb.header) ### perform the offset for i, cube in enumerate(icubelist): thisnbw = WCS(nbimages[i].header) thisnbdat = nbimages[i].data neww = change_coord_alignmax(refwcs, thisnbw, refdat, thisnbdat, range_mod=pixrange, range_ref=pixrange) cube.wcs.wcs.crval[0] = neww.wcs.crval[0] cube.wcs.wcs.crval[1] = neww.wcs.crval[1] cube.wcs.wcs.crpix[0] = neww.wcs.crpix[0] cube.wcs.wcs.crpix[1] = neww.wcs.crpix[1] if not os.path.isdir(outputdir_cubes): os.makedirs(outputdir_cubes) cube.write(outputdir_cubes + cube_prefix + cube.filename.split('/')[-1]) ### offset variance cube if provided if varcubelist is not None: vcube = varcubelist[i] vcube.wcs.wcs.crval[0] = neww.wcs.crval[0] vcube.wcs.wcs.crval[1] = neww.wcs.crval[1] vcube.wcs.wcs.crpix[0] = neww.wcs.crpix[0] vcube.wcs.wcs.crpix[1] = neww.wcs.crpix[1] vcube.write(outputdir_cubes + cube_prefix + vcube.filename.split('/')[-1]) ### if desired, write out white light images from corrected cubes if write_aligned_nb: aligned_nb_outdir = outputdir_cubes + 'nb/' if not os.path.isdir(aligned_nb_outdir): os.makedirs(aligned_nb_outdir) narrowband(cube, waverange[0], waverange[1], outfile=aligned_nb_outdir + 'nb_' + cube.filename.split('/')[-1]) ########## if varcubelist is not None: for i, cube in enumerate(varcubelist): try: thisnbw = WCS(nbimages[i].header) except: import pdb pdb.set_trace() thisnbdat = nbimages[i].data neww = change_coord_alignmax(refwcs, thisnbw, refdat, thisnbdat, range_mod=pixrange, range_ref=pixrange) cube.wcs.wcs.crval[0] = neww.wcs.crval[0] cube.wcs.wcs.crval[1] = neww.wcs.crval[1] cube.wcs.wcs.crpix[0] = neww.wcs.crpix[0] cube.wcs.wcs.crpix[1] = neww.wcs.crpix[1] if not os.path.isdir(outputdir_cubes): os.makedirs(outputdir_cubes) cube.write(outputdir_cubes + cube_prefix + cube.filename.split('/')[-1]) brightcoords = SkyCoord(neww.wcs.crval[0], neww.wcs.crval[1], unit='deg') return brightcoords
def addWcsRtModel(inp, ref, outfile, spatial_scale_xy=[0.679, 0.290], zgal=0.6942, center=('12 36 19.811', '+62 12 51.831'), PA=27): ### Load in the model file inpdat = fits.open(inp) rtcube = DataCube(inp, include_wcs=False) rtcube.wavelength = inpdat[2].data rtcube.data = inpdat[1].data wavearr = rtcube.wavelength ### Load in the reference file if necessary if not isinstance(ref, DataCube): refcube = DataCube(ref) else: refcube = inp refdat = refcube.data refwave = refcube.wavelength nbhdu = transform.narrowband(refcube, 4000., 5000.) refnb = nbhdu.data refwcs = WCS(nbhdu.header) ### Rearrange the cube and find brightest pixel newdat = np.transpose(rtcube.data, axes=[2, 1, 0]) sumdat = np.sum(newdat, axis=0) maxdat = np.max(sumdat) brightmodpix = np.where(sumdat == maxdat) print(brightmodpix) ### Get the pixel scale in the spectral dimension diff = wavearr[1:] - wavearr[:-1] if not np.all(np.abs(diff - diff[0]) < 1e-3): import pdb pdb.set_trace() raise ValueError('Wavelength array not uniformly sampled') spectral_scale = diff[0] ### Set scale and reference position in model wave1 = wavearr[0] * (1. + zgal) spectral_scale *= (1. + zgal) ### Get the bright pixel from reference cube brightpix, brightcoords = utils.bright_pix_coords(refnb, refwcs) ### Create the new WCS newwcs = WCS(naxis=3) if center is not None: cencoords = SkyCoord(center[0], center[1], unit=(u.hourangle, u.deg)) else: cencoords = brightcoords # coordinates are (y, x, lam) and '1' indexed in FITS files newwcs.wcs.crpix = np.array( [brightmodpix[1][0] + 1, brightmodpix[0][0] + 1, 1]) newwcs.wcs.crval = np.array([cencoords.ra.deg, cencoords.dec.deg, wave1]) newwcs.wcs.cdelt = np.array([ spatial_scale_xy[0] / 3600., spatial_scale_xy[1] / 3600., spectral_scale ]) newwcs.wcs.cunit = ['deg', 'deg', 'Angstrom'] newwcs.wcs.ctype = ('RA---TAN', 'DEC--TAN', 'VAC') rotangle = np.radians(PA) # Assuming PA given in degrees psmat = np.array([[ newwcs.wcs.cdelt[0] * np.cos(rotangle), -newwcs.wcs.cdelt[1] * np.sin(rotangle), 0. ], [ newwcs.wcs.cdelt[0] * np.sin(rotangle), newwcs.wcs.cdelt[1] * np.cos(rotangle), 0. ], [0., 0., 1.]]) newwcs.wcs.cd = psmat newhdu = newwcs.to_fits() newhdu[0].header['PC3_3'] = spectral_scale newhdu[0].data = newdat newhdu.writeto(outfile, overwrite=True)
def subtract_master_sky(scicubes, mastersky, suffix='mskysub.fits'): for i, sc in enumerate(scicubes): cube = DataCube(sc) cubedatsub = cube.data.transpose() - mastersky cube.data = cubedatsub.transpose() cube.write(sc.split('/')[-1][:-5] + '_' + suffix)