def combine_flat(flatlist,outfilepath="flat.fits"): """Combines a series of flatfield exposures to create a single flatfield image. Uses only the information contained inside the RSS aperture, which is the only significant difference between this routine and the familiar flat combination routines common to CCD astronomy. Inputs: flatlist -> A list of strings, each the path to a flatfield exposure outfilepath -> A string, the path of the output file (default 'flat.fits') """ imagelist = [] for i in range(len(flatlist)): imagelist.append(openfits(flatlist[i])) xgrid, ygrid = np.meshgrid(np.arange(imagelist[i][0].data.shape[1]),np.arange(imagelist[i][0].data.shape[0])) imagelist[i][0].data=imagelist[i][0].data/np.median(imagelist[i][0].data[np.power((xgrid-imagelist[i][0].header["fpaxcen"]),2)+np.power((ygrid-imagelist[i][0].header["fpaycen"]),2)<np.power(imagelist[i][0].header["fparad"],2)]) imagestack = np.empty((len(flatlist),imagelist[0][0].data.shape[0],imagelist[0][0].data.shape[1])) for i in range(len(flatlist)): imagestack[i,:,:] = imagelist[i][0].data flatarray = np.median(imagestack,axis=0) flatarray[flatarray<0.000001]=0 writefits(outfilepath,flatarray,clobber=True) #Close images for i in range(len(flatlist)): imagelist[i].close() return
def fit_velmap_ha_n2_mode(wavelist, intylist, outdir, uncertlist=None, clobber=False): """ """ #Create blank lists for filling with images wavefilelist = [] intyfilelist = [] if not (uncertlist is None): uncertfilelist = [] #Open images and populate the lists for i in range(len(wavelist)): wavefilelist.append(openfits(wavelist[i])) intyfilelist.append(openfits(intylist[i])) if not (uncertlist is None): uncertfilelist.append(openfits(uncertlist[i])) #Create blank arrays for filling with data wavecube = np.zeros((intyfilelist[0][0].data.shape[0],intyfilelist[0][0].data.shape[1],len(wavelist))) intycube = np.zeros((intyfilelist[0][0].data.shape[0],intyfilelist[0][0].data.shape[1],len(wavelist))) if not (uncertlist is None): uncertcube = np.zeros((intyfilelist[0][0].data.shape[0],intyfilelist[0][0].data.shape[1],len(wavelist))) #Fill the cube arrays with data for i in range(len(wavelist)): wavecube[:,:,i] = wavefilelist[i][0].data intycube[:,:,i] = intyfilelist[i][0].data if not (uncertlist is None): uncertcube[:,:,i] = uncertfilelist[i][0].data #Create blank arrays for the velocity+etc fits contarray = np.zeros_like(wavefilelist[0][0].data) intyarray = np.zeros_like(wavefilelist[0][0].data) intyratioarray = np.zeros_like(wavefilelist[0][0].data) wavearray = np.zeros_like(wavefilelist[0][0].data) two_line_success_array = np.zeros_like(wavefilelist[0][0].data,dtype="bool") one_line_success_array = np.zeros_like(wavefilelist[0][0].data,dtype="bool") #Create x and y arrays for the "progress bar" numb_updates=20 #Number of progress updates xgrid, ygrid = np.meshgrid(np.arange(contarray.shape[1]),np.arange(contarray.shape[0])) xgrid = xgrid.flatten() ygrid = ygrid.flatten() progX = [] progY = [] progPerc = [] for i in range(1,numb_updates+1): progX.append(xgrid[np.int(len(xgrid)*i/numb_updates)-1]) progY.append(ygrid[np.int(len(xgrid)*i/numb_updates)-1]) progPerc.append(i*100/numb_updates) progX = np.array(progX) progY = np.array(progY) progPerc = np.array(progPerc) #Loop over pixels for y in range(wavearray.shape[0]): for x in range(wavearray.shape[1]): #Display the "progress bar" if appropriate if np.any(np.logical_and(x==progX,y==progY)): print "Velocity map approximately "+repr(progPerc[np.logical_and(progX==x,progY==y)][0])+"% complete..." #Get the spectrum to fit waves = wavecube[y,x,:] intys = intycube[y,x,:] if not (uncertlist is None): uncerts = uncertcube[y,x,:] else: uncerts = None # #Attempt the two-lined fit (halpha and NII) # if np.sum(waves!=0)>0.5*len(waves): fit, success = fit_ha_and_n2(waves[waves!=0], intys[intys!=0], uncerts[uncerts!=0]) # else: fit, success = np.zeros(8), False # #Was the fit successful # if success: # contarray[y,x] = fit[0] # intyarray[y,x] = fit[1] # intyratioarray[y,x] = fit[2]/fit[1] # wavearray[y,x] = fit[3] # two_line_success_array[y,x] = True # #If not, let's try only fitting the halpha line # else: # if np.sum(waves!=0)>0.5*len(waves): fit, success = fit_only_ha(waves[waves!=0], intys[intys!=0], uncerts[uncerts!=0]) # else: fit, success = np.zeros(5), False # if success: # contarray[y,x] = fit[0] # intyarray[y,x] = fit[1] # wavearray[y,x] = fit[2] # one_line_success_array[y,x] = True #Fit with voigtfit if np.sum(waves!=0)>0.5*len(waves): fit,_err,_chi2 = voigtfit.voigtfit(waves[waves!=0],intys[intys!=0],uncerts[uncerts!=0],voigtfit.voigtguess(waves[waves!=0],intys[intys!=0]),[True,True,True,True,True]) contarray[y,x] = fit[0] intyarray[y,x] = fit[1] wavearray[y,x] = fit[2] #Convert wavelengths to velocities velarray = np.zeros_like(wavearray) velarray[wavearray!=0] = 299792.458*((wavearray[wavearray!=0]/6562.81)**2-1)/((wavearray[wavearray!=0]/6562.81)**2+1) #Save the output images writefits(join(outdir,"velocity.fits"), velarray, clobber=clobber) writefits(join(outdir,"intensity.fits"), intyarray, clobber=clobber) writefits(join(outdir,"intyratio.fits"), intyratioarray, clobber=clobber) writefits(join(outdir,"continuum.fits"), contarray, clobber=clobber) #writefits(join(outdir,"2linesuccess.fits"), two_line_success_array, clobber=clobber) #writefits(join(outdir,"1linesuccess.fits"), one_line_success_array, clobber=clobber) #Close input images for i in range(len(wavelist)): wavefilelist[i].close() intyfilelist[i].close() if not (uncertlist is None): uncertfilelist[i].close() return
def make_final_image(input_image, output_image, output_wave_image, desired_fwhm, input_uncert_image=None, output_uncert_image=None, clobber=False): """This routine makes the 'final' images for a data cube. At least the paths to the input image, output image, and output wavelength image are necessary for this. Beyond that, the user may also have the routine create uncertainty images as well. Images are convolved to the resolution 'desired_fwhm'. If the current fwhm is already higher than that, the routine will throw an error. A number of fits header keywords are necessary for this program to function properly. Any of these missing will throw an error. The output images are intensity-weighted, i.e. the wavelength image will be created such that the wavelengths at each pixel are the 'most likely' wavelength for the intensity at that pixel, etc. Inputs: input_image -> Path to the input image. output_image -> Path to the output image. output_wave_image -> Path to the output wavelength image. desired_fwhm -> Desired FWHM for the resultant image to have. Optional Inputs: input_uncert_image -> Path to the input uncertainty image, if it exists. output_uncert_image -> Path to the output uncertainty image, if it exists. clobber -> Overwrite output images if they already exist. Default is False. """ print "Making final data cube images for image "+input_image #Measure the sky background level in the input image skyavg, skysig = fit_sky_level([input_image]) #Open the input image and get various header keywords, crash if necessary intyimage = openfits(input_image) intygrid = intyimage[0].data fwhm = intyimage[0].header.get("fpfwhm") wave0 = intyimage[0].header.get("fpwave0") calf = intyimage[0].header.get("fpcalf") xcen = intyimage[0].header.get("fpxcen") ycen = intyimage[0].header.get("fpycen") if fwhm == None: crash("Error! FWHM not measured for image "+input_image+".") if wave0 == None or calf == None: crash("Error! Wavelength solution does "+ "not exist for image "+input_image+".") if xcen == None or ycen == None: crash("Error! Center values not measured "+ "image "+input_image+".") if fwhm>desired_fwhm: crash("Error! Desired FWHM too low for image "+ input_image+".") #Subtract the sky background from the image intygrid[intygrid!=0] -= skyavg[0] #Calculate the necessary FWHM for convolution and make the gaussian kernel fwhm_conv = np.sqrt(desired_fwhm**2-fwhm**2) sig = fwhm_conv/2.3548+0.0001 ksize = np.ceil(4*sig) #Generate the kernel to 4-sigma kxgrid, kygrid = np.meshgrid(np.linspace(-ksize,ksize,2*ksize+1),np.linspace(-ksize,ksize,2*ksize+1)) kern = np.exp(-(kxgrid**2+kygrid**2)/(2*sig**2)) #Gaussian (unnormalized because sig can be 0) kern = kern/np.sum(kern) #Normalize the kernel #Open and convolve the uncertainty image if one exists. Save the output. if input_uncert_image != None: uncertimage = openfits(input_uncert_image) uncertgrid = uncertimage[0].data #Add the sky background uncertainty to the uncertainty grid uncertgrid[intygrid!=0] = np.sqrt(uncertgrid[intygrid!=0]**2+skysig[0]**2) #Convolve the uncertainties appropriately new_uncert_grid = convolve_uncert(uncertgrid, intygrid, kern) #Write to output file writefits(output_uncert_image,new_uncert_grid,header=uncertimage[0].header,clobber=clobber) uncertimage.close() #Create and convolve the wavelength image. Save the output. xgrid, ygrid = np.meshgrid(np.arange(intyimage[0].data.shape[1]), np.arange(intyimage[0].data.shape[0])) r2grid = (xgrid-xcen)**2 + (ygrid-ycen)**2 wavegrid = wave0 / np.sqrt(1+r2grid/calf**2) newwavegrid = convolve_wave(wavegrid, intygrid, kern) writefits(output_wave_image,newwavegrid,header=intyimage[0].header,clobber=clobber) #Convolve the intensity image. Save the output newintygrid = convolve_inty(intygrid, kern) intyimage[0].header["fpfwhm"] = desired_fwhm #Update header FWHM keyword writefits(output_image,newintygrid,header=intyimage[0].header,clobber=clobber) #Close images intyimage.close() return