def rotate_cube_wcs(cube_name, cube_folder="", outwcs_folder=None, rotangle=0., **kwargs): """Routine to remove potential Nan around an image and reconstruct an optimal WCS reference image. The rotation angle is provided as a way to optimise the extent of the output image, removing Nan along X and Y at that angle. Args: cube_name (str): input image name. No default. cube_folder (str): input image folder [''] outwcs_folder (str): folder where to write the output frame. Default is None which means that it will use the folder of the input image. rotangle (float): rotation angle in degrees [0] **kwargs: in_suffix (str): in suffix to remove from name ['prealign'] out_suffix (str): out suffix to add to name ['rotwcs'] margin_factor (float): factor to extend the image [1.1] Returns: """ # Reading the input names and setting output folder fullname = joinpath(cube_folder, cube_name) cube_folder, cube_name = os.path.split(fullname) if outwcs_folder is None: outwcs_folder = cube_folder # Suffix in_suffix = kwargs.pop("in_suffix", "prealign") out_suffix = kwargs.pop("out_suffix", "rotwcs") # Get margin if needed margin_factor = kwargs.pop("margin_factor", 1.1) extend_fraction = np.maximum(0., (margin_factor - 1.)) upipe.print_info("Will use a {:5.2f}% extra margin".format( extend_fraction * 100.)) # Opening the image via mpdaf cubewcs = Cube(fullname) imawcs = cubewcs.sum(axis=0) extra_pixels = (np.array(imawcs.shape) * extend_fraction).astype(np.int) # New dimensions and extend current image new_dim = tuple(np.array(imawcs.shape).astype(np.int) + extra_pixels) ima_ext = imawcs.regrid(newdim=new_dim, refpos=imawcs.get_start(), refpix=tuple(extra_pixels / 2.), newinc=imawcs.get_step()[0] * 3600.) # Copy and rotate WCS new_wcs = copy.deepcopy(ima_ext.wcs) upipe.print_info( "Rotating spatial WCS of Cube by {} degrees".format(rotangle)) new_wcs.rotate(rotangle) # New rotated image ima_rot = Image(data=np.nan_to_num(ima_ext.data), wcs=new_wcs) # Then resample the image using the initial one as your reference ima_rot_resampled = ima_rot.align_with_image(ima_ext, flux=True) # Crop NaN ima_rot_resampled.crop() # get the new header with wcs and rotate back finalwcs = ima_rot_resampled.wcs finalwcs.rotate(-rotangle) # create the final image data_cube_rot = np.repeat(ima_rot_resampled[np.newaxis, :, :].data, cubewcs.shape[0], axis=0) final_rot_cube = Cube(data=data_cube_rot, wave=cubewcs.wave, wcs=finalwcs) # Save image if isinstance(in_suffix, str) and in_suffix != "" and in_suffix in cube_name: out_name = cube_name.replace(in_suffix, out_suffix) else: name, extension = os.path.splitext(cube_name) if out_suffix != "": out_suffix = "_{}".format(out_suffix) out_name = "{0}{1}{2}".format(name, out_suffix, extension) # write output final_rot_cube.write(joinpath(outwcs_folder, out_name)) return outwcs_folder, out_name
class check_musepipe(object): """Graphic output to check MUSE data reduction products """ def __init__(self, cube_folder='./', cube_name=None, verbose=False) : """ """ self.verbose = verbose self.cube_folder = cube_folder self.cube_name = cube_name # Open the cube and extract spectra if cube name is given self.open_cube(cube_folder, cube_name) if self._isCube : self.get_set_spectra() self.get_set_images() def open_cube(self, cube_folder=None, cube_name=None) : """Open the cube """ # Check if cube folder and name are given if cube_folder is not None : self.cube_folder = cube_folder if cube_name is not None : self.cube_name = cube_name # Check if cube exists if (self.cube_folder is None) | (self.cube_name is None) : self._isCube = False print("WARNING: No appropriate Cube name and folder defined") return cubepath = joinpath(self.cube_folder, self.cube_name) if os.path.isfile(cubepath) : self._isCube = True self.cube_galaxy = Cube(cubepath) else : self._isCube = False print("WARNING: Cube {0} not found".format(cubepath)) def open_image(self, image_folder="./", image_name=None) : """Open the image """ self.image_folder = image_folder self._isImage = True self.image_name = image_name if (imagein is None) | (not os.path.isfile(joinpath(image_folder, imagein))): self._isImage = False else : self._isImage = True self.image_galaxy = Image(joinpath(image_folder, image_name)) def get_spectrum_from_cube(self, nx=None, ny=None, width=0) : if not self._isCube : print("WARNING: No Cube is defined, yet") return if nx == None : nx = self.cube_galaxy.shape[2] // 2 if ny == None : ny = self.cube_galaxy.shape[1] // 2 width2 = width // 2 return (self.cube_galaxy[:, ny - width2: ny + width2 + 1, nx - width2: nx + width2 + 1]).sum(axis=(1,2)) def get_image_from_cube(self, nlambda=None, width=0) : if not self._isCube : print("WARNING: No Cube is defined, yet") return if nlambda == None : nlambda = self.cube_galaxy.shape[0] // 2 width2 = width // 2 return (self.cube_galaxy[nlambda - width2: nlambda + width2 + 1, :, :].sum(axis=0)) def get_set_images(self) : """Get a set of standard images from the Cube """ pass def get_set_spectra(self) : """Get a set of standard spectra from the Cube """ if self._isCube : self.spec_fullgalaxy = self.cube_galaxy.sum(axis=(1,2)) self.spec_4quad = self.get_quadrant_spectra_from_cube() self.spec_central_aper = [self.get_spectrum_from_cube(width=0), self.get_spectrum_from_cube(width=20), self.get_spectrum_from_cube(width=40)] def get_quadrant_spectra_from_cube(self, width=0) : """Get quadrant spectra from the Cube Input ---- width : width of integration """ if not self._isCube : print("WARNING: No Cube is defined, yet") return ny4 = self.cube_galaxy.shape[1] // 4 nx4 = self.cube_galaxy.shape[2] // 4 nx34, ny34 = 3 * nx4, 3 * ny4 spec1 = self.get_spectrum_from_cube( nx4, ny4, width) spec2 = self.get_spectrum_from_cube( nx4, ny34, width) spec3 = self.get_spectrum_from_cube(nx34, ny4, width) spec4 = self.get_spectrum_from_cube(nx34, ny34, width) return spec1, spec2, spec3, spec4 def check_bias(self) : pass # bias = RawFile(self. ..) def check_flat(self) : pass def check_finalcube(self) : pass
f = open('psf_results.dat','w') f.write('Wavelengh (A) Gaussian FWHM (") Moffat n/beta (") Moffat fwhm (") Moffat alpha(")\n') f.write('--------------------------------------------------------------------------------------------------------\n') ## Read star list and open output results id,ra,dec = np.loadtxt(args.star_list,unpack=True) ## Load cube and bin c = Cube(args.cube) c = c.rebin((2*368,1,1)) sample_fwhm = [] sample_gfwhm= [] sample_n = [] sample_alpha = [] white = c.sum(axis=0) (gfwhm,std_gfwhm,fwhm,std_fwhm,n,std_n) = measure_psf(white,ra,dec) alpha = fwhm / (2 *np.sqrt(2 * (1/n) - 1)) err_alpha = std_fwhm / (2 *np.sqrt(2 * (1/n) - 1)) + std_n * fwhm / (2 * np.sqrt(2/n- n*n)) ## ugly derivative with Wolfram Alpha f.write('white light \t %0.2f +/- %0.2f \t %0.2f +/- %0.2f \t %0.2f +/- %0.2f \t %0.2f +/- %0.2f \n' %(gfwhm,std_gfwhm,n,std_n,fwhm,std_fwhm, alpha,err_alpha)) f.write('--------------------------------------------------------------------------------------------------------\n') for k in range(0,c.shape[0]): print('Measusing %s out of 5 slices'%k) im = c[k] im.wcs = c.wcs ## Not elegant, but the wcs is not keept when you only select one slice (gfwhm,std_gfwhm,fwhm,std_fwhm,n,std_n) = measure_psf(im,ra,dec) ## Convert mpdaf fwhm in proper moffat parameters
def make_MagE_cube_v2(config_file, format='txt'): """A new version to create the MagE cubes, it uses MPDAF objects. It works for .fits 1-d spectra files stored in a directory with a specific format. In particular: XXX_yyy_??.txt Errors are looked for in the same directory with *_sig.fits extension Parameters ---------- config_file : str Configuration file with important parameters. See mage.dump_config_make_MagE_cube() format : str Either 'fits' of 'txt' Returns: Cube fits files associated to each "XX_yyy" """ # read config_filename and add filename to params f = open(config_file) params = json.load(f) params['config_filename'] = config_file # reference files reference_mage_file = params['reference_mage'] reference_muse_file = params['reference_muse'] # Add comment on how the header was created comment = 'Cube created by pyntejos.mage.make_MagE_cube.py based on headers from {} and {}. Astrometry ' \ 'and wavelength axis given by input configuration ' \ 'file {}.'.format(reference_mage_file.split('/')[-1],reference_muse_file.split('/')[-1], params['config_filename']) # Print message print('') print(comment.replace("Cube created", "MagE cube will be created")) dirname = params['directory_mage'] # filenames = glob.glob(dirname+"/*syn_??.fits") if format == 'txt': rootname = params["rootname"] print('rootname: '+rootname) filenames = glob.glob(dirname+"/{}_??.txt".format(rootname)) # print(filenames) elif format == 'fits': raise NotImplementedError("Not properly implemented. It's almost there but depends on the file structures.") if len(filenames) == 0: raise ValueError("No files found matching the rootname: {}".format(rootname)) # sort them filenames.sort() # create the new datacube structure # spec_ref = readspec(filenames[0]) nw, ny, nx = params['NAXIS3'], params['NAXIS2'], params['NAXIS1'] # get wavecoord # hdr = spec_ref.header # hdr['CUNIT1'] = 'Angstrom' crpix = params['CRPIX3'] cdelt = params['CD3_3'] crval = params['CRVAL3'] wave = WaveCoord(hdr=None, crpix=crpix, cdelt=cdelt, crval=crval, cunit=u.AA, ctype='LINEAR', shape=None) # wave = WaveCoord(hdr=hdr) # get WCS crpix_yx = params['CRPIX2'], params['CRPIX1'] # note y,x order crval_decra = params['CRVAL2'], params['CRVAL1'] # ditto cdelt_yx = params['PIXSCALE_Y'], -1*params['PIXSCALE_X'] # ditto (negative to decrease towards east) PA = params['POS_ANGLE'] if PA == "None": # get angle from MagE reference header print("No PA given in parameter file. Reding PA from MagE reference .fits header") hdulist_mage = fits.open(params['reference_mage']) PA = hdulist_mage[0].header['ROTANGLE'] - 44.5 # this is the current offset in angle print("PA={}deg".format(PA)) shape = (ny, nx) wcs = WCS(crpix=crpix_yx, crval=crval_decra, cdelt=cdelt_yx, deg=True, shape=shape, rot=-1*PA) # for some reason negative PA works # redefine wcs to have CD matrix rather than PC matrix if 1: #rot != 0: hdr = wcs.to_header() hdr.rename_keyword('PC1_1','CD1_1') hdr.rename_keyword('PC2_1','CD2_1') hdr.rename_keyword('PC1_2','CD1_2') hdr.rename_keyword('PC2_2','CD2_2') # hdr['CD1_1'] = hdr['PC1_1'] # hdr['CD2_1'] = hdr['PC2_1'] # hdr['CD1_2'] = hdr['PC1_2'] # hdr['CD2_2'] = hdr['PC2_2'] wcs = WCS(hdr=hdr) # create data structures data = np.zeros_like(np.ndarray(shape=(nw,ny,nx))) var = np.zeros_like(data) # read the files and fill the data cubes (cube and variance) print("Reading files from directory {} ordered as:".format(dirname)) for ii,fname in enumerate(filenames): fn = fname.split('/')[-1] yspaxel = ny - ii # larger y will be the northern one print("\t {}: {} --goes to--> spaxel (1,{})".format(ii + 1, fn, yspaxel)) # MAKE SURE THE SPECTRA IS PROPERLY SORTED nfile = fn.split('.')[0].split('_')[-1] nfile = int(nfile) assert nfile == ii + 1, "The files in the directory are not sorted properly. Please check." if format=='fits': try: spec = readspec(fname) if 0: # dummy spec.flux = 1 spec.sig = 0 data[:,yspaxel-1,0] = spec.flux.value # position "01" is the most north, y increase to north if np.isnan(spec.sig): try: spec_sig = readspec(fname.replace('flux','sigm')) spec.sig = spec_sig.flux.value except: spec.sig = 0 var[:,yspaxel-1,0] = (spec.sig.value)**2 except: print("Something is wrong with spectrum {}".format(fname.split('/')[-1])) import pdb; pdb.set_trace() raise ValueError("Something is wrong with spectrum {}".format(fname.split('/')[-1])) elif format=='txt': spec = read_single_mage_file(fname) data[:, yspaxel - 1, 0] = spec.flux var[:, yspaxel - 1, 0] = (spec.sig)**2 # import pdb;pdb.set_trace() # create the Cube object cube = Cube(data=data, var=var, wcs=wcs, wave=wave) outputname = '{}_cube_{}.fits'.format(params['rootname'], params['datestamp']) cube.write(outputname) print('Wrote file: {}'.format(outputname)) # create white image white = cube.sum(axis=0) white.write(outputname.replace('cube', 'white')) print('Wrote file: {}'.format(outputname.replace('cube', 'white'))) # import pdb; pdb.set_trace() return cube
def make_MagE_cube_v2(config_file, format='txt'): """A new version to create the MagE cubes, it uses MPDAF objects. It works for .fits 1-d spectra files stored in a directory with a specific format. In particular: XXX_yyy_??.txt Where XXX -> Name of object yyy -> ['flx', 'nor', syn'] ?? -> ['01', '02', ..., '11'] Each individual file must contain its error array Parameters ---------- config_file : str Configuration file with important parameters. See mage.dump_config_make_MagE_cube() for an example format : str Only '.txt' format is allowed. The convention is set by N.Tejos and S.Lopez northernmost_ypixel : str What is the Northernmost spaxel, either '11' or '1' Returns: Cube fits files associated to each "XX_yyy" object It writes the .fits to disk """ # read config_filename and add filename to params f = open(config_file) params = json.load(f) params['config_filename'] = config_file # reference files reference_mage_file = params['reference_mage'] reference_muse_file = params['reference_muse'] # Add comment on how the header was created comment = 'Cube created by pyntejos.mage.make_MagE_cube.py based on headers from {} and {}. Astrometry ' \ 'and wavelength axis given by input configuration ' \ 'file {}.'.format(reference_mage_file.split('/')[-1],reference_muse_file.split('/')[-1], params['config_filename']) # Print message print('') print(comment.replace("Cube created", "MagE cube will be created")) dirname = params['directory_mage'] rootname = params['rootname'] # filenames = glob.glob(dirname+"/*syn_??.fits") print('rootname: ' + rootname) if format == 'txt': # import pdb; pdb.set_trace() filenames = glob.glob(dirname + "/{}_??.txt".format(rootname)) print('This format is deprecated. Please use .fits instead.') # print(filenames) #elif format == 'fits': # filenames = glob.glob(dirname + "/{}_flux_??.fits".format(rootname)) else: #raise ValueError('Only implemented for .txt or .fits files.') raise ValueError( 'Only implemented for .txt files (with a special format convention).' ) if len(filenames) == 0: raise ValueError( "No files found matching the rootname: {}".format(rootname)) # sort them filenames.sort() # the structure must be consistent with that specified by the user in the config file nw, ny, nx = params['NAXIS3'], params['NAXIS2'], params['NAXIS1'] # get wavecoord # hdr = spec_ref.header # hdr['CUNIT1'] = 'Angstrom' crpix = params['CRPIX3'] cdelt = params['CDELT3'] crval = params['CRVAL3'] wave = WaveCoord(hdr=None, crpix=crpix, cdelt=cdelt, crval=crval, cunit=u.AA, ctype='LINEAR', shape=None) # wave = WaveCoord(hdr=hdr) # get WCS crpix_yx = params['CRPIX2'], params['CRPIX1'] # note y,x order crval_decra = params['CRVAL2'], params['CRVAL1'] # ditto cdelt_yx = params['PIXSCALE_Y'], -1 * params[ 'PIXSCALE_X'] # ditto (negative to decrease towards east) PA = params['POS_ANGLE'] if PA == "None": # get angle from MagE reference header print( "No PA given in parameter file. Reading PA from MagE reference .fits header" ) hdulist_mage = fits.open(params['reference_mage']) PA = hdulist_mage[0].header[ 'ROTANGLE'] - 44.5 # this is the current offset in angle print("\tPA={}deg".format(PA)) shape = (ny, nx) wcs = WCS(crpix=crpix_yx, crval=crval_decra, cdelt=cdelt_yx, deg=True, shape=shape, rot=-1 * PA) # for some reason negative PA works # redefine wcs to have CD matrix rather than PC matrix if 1: #rot != 0: hdr = wcs.to_header() hdr.rename_keyword('PC1_1', 'CD1_1') hdr.rename_keyword('PC2_1', 'CD2_1') hdr.rename_keyword('PC1_2', 'CD1_2') hdr.rename_keyword('PC2_2', 'CD2_2') # hdr['CD1_1'] = hdr['PC1_1'] # hdr['CD2_1'] = hdr['PC2_1'] # hdr['CD1_2'] = hdr['PC1_2'] # hdr['CD2_2'] = hdr['PC2_2'] wcs = WCS(hdr=hdr) # create data structures data = np.zeros_like(np.ndarray(shape=(nw, ny, nx))) var = np.zeros_like(data) # read the files and fill the data cubes (cube and variance) print("Reading files from directory {} ordered as:".format(dirname)) print('Northernmost position is {}'.format( params['northernmost_position'])) for ii, fname in enumerate(filenames): fn = fname.split('/')[-1] if params['northernmost_position'] == '11': yspaxel = ny - ii # larger y will be the northern one elif params['northernmost_position'] == '01': yspaxel = ii + 1 else: raise ValueError( '`northernmost_position` must be either `11` or `01` (str) in the configuration file.' ) print("\t {}: {} --goes to--> spaxel (1,{}) ; i.e. y_python={}".format( ii + 1, fn, yspaxel, yspaxel - 1)) # MAKE SURE THE SPECTRA IS PROPERLY SORTED nfile = fn.split('.')[0].split('_')[-1] nfile = int(nfile) assert nfile == ii + 1, "The files in the directory are not sorted properly. Please check." ''' if format=='fits': spec = readspec(fname) if 0: # dummy spec.flux = 1 spec.sig = 0 if spec.sig_is_set: flux_aux = spec.flux.value sigm_aux = spec.sig.value else: # get the sigma values from another file try: # import pdb; pdb.set_trace() sigma_file = fname.replace('flux', 'sigm') spec_sig = readspec(sigma_file) spec.sig = spec_sig.flux except: print("No sigma spectrum was found in the directory with the right name: {}".format(sigma_file)) spec.sig = 0 flux_aux = spec.flux.value sigm_aux = spec.sig.value data[:, yspaxel-1, 0] = flux_aux var[:, yspaxel-1, 0] = (sigm_aux) ** 2 print("Reading {}, storing it into y={}".format(fname, yspaxel-1)) ''' if format == 'txt': spec = read_single_mage_file(fname) data[:, yspaxel - 1, 0] = spec.flux var[:, yspaxel - 1, 0] = (spec.sig)**2 # import pdb;pdb.set_trace() # create the Cube object cube = Cube(data=data, var=var, wcs=wcs, wave=wave) outputname = '{}_cube_{}.fits'.format(params['rootname'], params['datestamp']) cube.write(outputname) print('Wrote file: {}'.format(outputname)) # create white image white = cube.sum(axis=0) white.write(outputname.replace('cube', 'white')) print('Wrote file: {}'.format(outputname.replace('cube', 'white'))) # import pdb; pdb.set_trace() return cube