def make_data_cube( detectid=None, coords=None, shotid=None, pixscale=0.25 * u.arcsec, imsize=30.0 * u.arcsec, wave_range=[3470, 5540], dwave=2.0, dcont=50.0, convolve_image=True, ffsky=True, subcont=False, ): """ Function to make a datacube from either a detectid or from a coordinate/shotid combination. Paramaters ---------- detectid: int detectid from the continuum or lines catalog. Default is None. Provide a coords/shotid combo if this isn't given coords: SkyCoords object coordinates to define the centre of the data cube pixscale: astropy angle quantity plate scale imsize: astropy angle quantity spatial length of cube (equal dims is only option) wave_range: list start and stop value for the wavelength range in Angstrom dwave step in wavelength range in Angstrom convolve_image: bool option to convolve image with shotid seeing ffsky: bool option to use full frame calibrated fibers. Default is True. subcont: bool option to subtract continuum. Default is False. This will measure the continuum 50AA below and above the input wave_range dcont width in angstrom to measure the continuum. Default is to measure 50 AA wide regions on either side of the line Returns ------- hdu: PrimaryHDU object the data cube 3D array and associated 3d header Units are '10^-17 erg cm-2 s-1 per spaxel' Examples -------- Can either pass in a detectid: >>> detectid_obj=2101602788 >>> hdu = make_data_cube( detectid=detectid_obj) >>> hdu.writeto( str(detectid_obj) + '.fits', overwrite=True) or can put in an SkyCoord object: >>> star_coords = SkyCoord(9.625181, -0.043587, unit='deg') >>> hdu = make_data_cube( coords=star_coords[0], shotid=20171016108, dwave=2.0) >>> hdu.writeto( 'star.fits', overwrite=True) """ global config, detecth5, surveyh5 if detectid is not None: detectid_obj = detectid det_info = detecth5.root.Detections.read_where( 'detectid == detectid_obj')[0] shotid = det_info["shotid"] coords = SkyCoord(det_info["ra"], det_info["dec"], unit="deg") if coords is None or shotid is None: print("Provide a detectid or both a coords and shotid") E = Extract() E.load_shot(shotid, fibers=False) # get spatial dims: ndim = int(imsize / pixscale) center = int(ndim / 2) # get wave dims: nwave = int((wave_range[1] - wave_range[0]) / dwave + 1) w = wcs.WCS(naxis=3) w.wcs.crval = [coords.ra.deg, coords.dec.deg, wave_range[0]] w.wcs.crpix = [center, center, 1] w.wcs.ctype = ["RA---TAN", "DEC--TAN", "WAVE"] w.wcs.cdelt = [-pixscale.to(u.deg).value, pixscale.to(u.deg).value, dwave] rad = imsize.to(u.arcsec).value info_result = E.get_fiberinfo_for_coord(coords, radius=rad, ffsky=False) ifux, ifuy, xc, yc, ra, dec, data, error, mask = info_result # get ifu center: ifux_cen, ifuy_cen = E.convert_radec_to_ifux_ifuy(ifux, ifuy, ra, dec, coords.ra.deg, coords.dec.deg) # get FWHM and PA surveyh5 = tb.open_file(config.surveyh5, "r") shotid_obj = shotid pa = surveyh5.root.Survey.read_where("shotid == shotid_obj")["pa"][0] if convolve_image: fwhm = surveyh5.root.Survey.read_where( "shotid == shotid_obj")["fwhm_virus"][0] else: fwhm = 1.8 # just a dummy variable as convolve_image=False surveyh5.close() # add in rotation sys_rot = 1.55 rot = 360. - (90. + pa + sys_rot) w.wcs.crota = [0, rot, 0] # rrot = np.deg2rad(rot) # w.wcs.pc = [[np.cos(rrot), # np.sin(rrot),0], # [-1.0*np.sin(rrot), # np.cos(rrot),0], [0,0,0]] im_cube = np.zeros((nwave, ndim, ndim)) wave_i = wave_range[0] i = 0 while wave_i <= wave_range[1]: try: im_src = E.make_narrowband_image( ifux_cen, ifuy_cen, ifux, ifuy, data, mask, scale=pixscale.to(u.arcsec).value, wrange=[wave_i, wave_i + dwave], nchunks=1, seeing_fac=fwhm, convolve_image=convolve_image, boxsize=imsize.to(u.arcsec).value, ) im_slice = im_src[0] if subcont: zarray_blue = E.make_narrowband_image( ifux_cen, ifuy_cen, ifux, ifuy, data, mask, seeing_fac=fwhm, scale=pixscale.to(u.arcsec).value, boxsize=imsize.to(u.arcsec).value, nchunks=2, wrange=[wave_i - dcont, wave_i], convolve_image=convolve_image, ) zarray_red = E.make_narrowband_image( ifux_cen, ifuy_cen, ifux, ifuy, data, mask, seeing_fac=fwhm, nchunks=2, scale=pixscale.to(u.arcsec).value, boxsize=imsize.to(u.arcsec).value, wrange=[wave_i + dwave, wave_i + dwave + dcont], convolve_image=convolve_image, ) im_cont = (zarray_blue[0] + zarray_red[0]) / (2 * dcont) im_slice = im_src[0] - dwave * im_cont im_cube[i, :, :] = im_slice except Exception: im_cube[i, :, :] = np.zeros((ndim, ndim)) wave_i += dwave i += 1 hdu = fits.PrimaryHDU(im_cube, header=w.to_header()) E.close() return hdu
def make_narrowband_image( detectid=None, coords=None, shotid=None, pixscale=0.25 * u.arcsec, imsize=30.0 * u.arcsec, wave_range=None, convolve_image=True, ffsky=True, subcont=False, dcont=50., include_error=False, ): """ Function to make narrowband image from either a detectid or from a coordinate/shotid combination. Paramaters ---------- detectid: int detectid from the continuum or lines catalog. Default is None. Provide a coords/shotid combo if this isn't given coords: SkyCoords object coordinates to define the centre of the data cube pixscale: astropy angle quantity plate scale imsize: astropy angle quantity image size wave_range: list or None start and stop value for the wavelength range in Angstrom. If not given, the detectid linewidth is used convolve_image: bool option to convolve image with shotid seeing ffsky: bool option to use full frame calibrated fibers. Default is True. subcont: bool option to subtract continuum. Default is False. This will measure the continuum 50AA below and above the input wave_range dcont width in angstrom to measure the continuum. Default is to measure 50 AA wide regions on either side of the line include_error bool option to include error array Returns ------- hdu: PrimaryHDU object the 2D summed data array and associated 2d header Units are '10^-17 erg cm-2 s-1' If include_error=True will include addiional hdu Examples -------- For a specific detectid: >>> hdu = make_narrowband_image(detectid=2101046271) For a SkyCoords object. You must provide shotid and wavelength range >>> coords = SkyCoord(188.79312, 50.855747, unit='deg') >>> wave_obj = 4235.84 #in Angstrom >>> hdu = make_narrowband_image(coords=coords, shotid=20190524021, wave_range=[wave_obj-10, wave_obj+10]) """ global config, detecth5, surveyh5 if detectid is not None: detectid_obj = detectid det_info = detecth5.root.Detections.read_where( 'detectid == detectid_obj')[0] shotid_obj = det_info["shotid"] wave_obj = det_info["wave"] linewidth = det_info["linewidth"] wave_range = [wave_obj - 2.0 * linewidth, wave_obj + 2.0 * linewidth] coords = SkyCoord(det_info["ra"], det_info["dec"], unit="deg") elif coords is not None: if shotid is not None: shotid_obj = shotid else: print("Provide a shotid") if wave_range is None: print("Provide a wavelength range to collapse. \ Example wave_range=[4500,4540]") else: print("Provide a detectid or both a coords and shotid") fwhm = surveyh5.root.Survey.read_where( "shotid == shotid_obj")["fwhm_virus"][0] pa = surveyh5.root.Survey.read_where("shotid == shotid_obj")["pa"][0] E = Extract() E.load_shot(shotid_obj, fibers=False) # get spatial dims: ndim = int(imsize / pixscale) center = int(ndim / 2) rad = imsize.to(u.arcsec).value # convert to arcsec value, not quantity info_result = E.get_fiberinfo_for_coord(coords, radius=rad, ffsky=ffsky) ifux, ifuy, xc, yc, ra, dec, data, error, mask = info_result # get ifu center: ifux_cen, ifuy_cen = E.convert_radec_to_ifux_ifuy(ifux, ifuy, ra, dec, coords.ra.deg, coords.dec.deg) if include_error: zarray = E.make_narrowband_image( ifux_cen, ifuy_cen, ifux, ifuy, data, mask, error=error, seeing_fac=fwhm, scale=pixscale.to(u.arcsec).value, boxsize=imsize.to(u.arcsec).value, wrange=wave_range, convolve_image=convolve_image, ) imslice = zarray[0] imerror = zarray[1] else: zarray = E.make_narrowband_image( ifux_cen, ifuy_cen, ifux, ifuy, data, mask, seeing_fac=fwhm, scale=pixscale.to(u.arcsec).value, boxsize=imsize.to(u.arcsec).value, wrange=wave_range, convolve_image=convolve_image, ) imslice = zarray[0] if subcont: zarray_blue = E.make_narrowband_image( ifux_cen, ifuy_cen, ifux, ifuy, data, mask, seeing_fac=fwhm, scale=pixscale.to(u.arcsec).value, boxsize=imsize.to(u.arcsec).value, wrange=[wave_range[0] - dcont - 10, wave_range[0] - 10], convolve_image=convolve_image, ) zarray_red = E.make_narrowband_image( ifux_cen, ifuy_cen, ifux, ifuy, data, mask, seeing_fac=fwhm, scale=pixscale.to(u.arcsec).value, boxsize=imsize.to(u.arcsec).value, wrange=[wave_range[1] + 10, wave_range[1] + dcont + 10], convolve_image=convolve_image, ) dwave = wave_range[1] - wave_range[0] im_cont = (zarray_blue[0] + zarray_red[0]) / (2 * dcont) imslice = zarray[0] - dwave * im_cont w = wcs.WCS(naxis=2) imsize = imsize.to(u.arcsec).value w.wcs.crval = [coords.ra.deg, coords.dec.deg] w.wcs.crpix = [center, center] w.wcs.ctype = ["RA---TAN", "DEC--TAN"] w.wcs.cdelt = [-pixscale.to(u.deg).value, pixscale.to(u.deg).value] # get rotation: sys_rot = 1.55 rot = 360. - (90. + pa + sys_rot) rrot = np.deg2rad(rot) # w.wcs.crota = [ 0, rot] w.wcs.pc = [[np.cos(rrot), np.sin(rrot)], [-1.0 * np.sin(rrot), np.cos(rrot)]] hdu = fits.PrimaryHDU(imslice, header=w.to_header()) E.close() if include_error: hdu_error = fits.ImageHDU(imerror, header=w.to_header()) hdu_x = fits.ImageHDU(zarray[2], header=w.to_header()) hdu_y = fits.ImageHDU(zarray[3], header=w.to_header()) return fits.HDUList([hdu, hdu_error, hdu_x, hdu_y]) else: return hdu
def get_source_spectra_mp(source_dict, shotid, manager, args): E = Extract() FibIndex = FiberIndex(args.survey) if args.survey == "hdr1": source_num_switch = 20 else: source_num_switch = 0 if len(args.matched_sources[shotid]) > 0: args.log.info("Working on shot: %s" % shotid) if args.survey == "hdr1": fwhm = args.survey_class.fwhm_moffat[args.survey_class.shotid == shotid][0] else: fwhm = args.survey_class.fwhm_virus[args.survey_class.shotid == shotid][0] moffat = E.moffat_psf(fwhm, 10.5, 0.25) if len(args.matched_sources[shotid]) > source_num_switch: E.load_shot(shotid, fibers=True, survey=args.survey) else: E.load_shot(shotid, fibers=False, survey=args.survey) for ind in args.matched_sources[shotid]: try: info_result = E.get_fiberinfo_for_coord( args.coords[ind], radius=args.rad, ffsky=args.ffsky, return_fiber_info=True, ) except TypeError: info_result = E.get_fiberinfo_for_coord( args.coords, radius=args.rad, ffsky=args.ffsky, return_fiber_info=True, ) if info_result is not None: if np.size(args.ID) > 1: args.log.info("Extracting %s" % args.ID[ind]) else: args.log.info("Extracting %s" % args.ID) ifux, ifuy, xc, yc, ra, dec, data, error, mask, fiberid, \ multiframe = info_result weights = E.build_weights(xc, yc, ifux, ifuy, moffat) # added by EMC 20210609 norm = np.sum(weights, axis=0) weights = weights / norm[np.newaxis, :] result = E.get_spectrum(data, error, mask, weights, remove_low_weights=False) spectrum_aper, spectrum_aper_error = [res for res in result] # apply aperture correction spectrum_aper /= norm spectrum_aper_error /= norm weights *= norm[np.newaxis, :] #add in the total weight of each fiber (as the sum of its weight per wavebin) if args.fiberweights: try: fiber_weights = np.array([ x for x in zip(ra, dec, np.sum(weights * mask, axis=1)) ]) except: fiber_weights = [] else: fiber_weights = [] # get fiber info no matter what so we can flag try: fiber_info = np.array([ x for x in zip(fiberid, multiframe, ra, dec, np.sum(weights * mask, axis=1)) ]) except: args.log.warning( 'Could not get fiber info, no flagging created') fiber_info = [] if len(fiber_info) > 0: try: flags = FibIndex.get_fiber_flags( coord=args.coords[ind], shotid=shotid) except: flags = FibIndex.get_fiber_flags(coord=args.coords, shotid=shotid) else: flags = None if np.size(args.ID) > 1: if args.ID[ind] in source_dict: source_dict[args.ID[ind]][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] else: source_dict[args.ID[ind]] = manager.dict() source_dict[args.ID[ind]][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] else: if args.ID in source_dict: source_dict[args.ID][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] else: source_dict[args.ID] = manager.dict() source_dict[args.ID][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] E.shoth5.close() FibIndex.close() return source_dict
def get_flim_sig_erin(detectid=None, coord=None, wave=None, datevobs=None, shotid=None): """ Script to grab flim_1sigma and sn_sig on demand from calibrated fiber extractions Parameters ---------- detectid int detectid for source coord astropy SkyCoord object wave central wavelength shotid observation ID Returns ------- flim_1sigma the 1 sigma sensitivity calculated over 7 pixels of the PSF-weighted extracted spectra """ detectid_obj = detectid det_info = source_table[source_table['detectid'] == detectid][0] shotid = det_info['shotid'] wave = det_info['wave'] coord = SkyCoord(ra=det_info['ra'], dec=det_info['dec'], unit='deg') fwhm = det_info['fwhm'] if datevobs is None: datevobs = '{}v{}'.format( str(shotid)[0:8], str(shotid)[8:]) if shotid is None: shotid_obj = int(datevobs[0:8] + datevobs[9:]) else: shotid_obj = shotid try: E = Extract() E.load_shot(datevobs, fibers=False) info_result = E.get_fiberinfo_for_coord(coord, radius=3.5, fiber_lower_limit=2 ) ifux, ifuy, xc, yc, ra, dec, data, error, mask = info_result #print(len(ifux)) moffat = E.moffat_psf(fwhm, 10.5, 0.25) I = None fac = None weights, I, fac = E.build_weights(xc, yc, ifux, ifuy, moffat, I=I, fac=fac, return_I_fac = True) norm = np.sum(weights, axis=0) weights = weights/norm result = E.get_spectrum(data, error, mask, weights, remove_low_weights=False) spec, spec_err = [res for res in result] w_index = np.where(E.wave >= wave)[0][0] nfib = np.shape(weights)[0] flim_1sigma = 2 * np.sqrt( np.nansum( (spec_err[w_index-3:w_index+4])**2)) sn_sig = 2 * np.sum( spec[w_index-3:w_index+4]) / flim_1sigma npix = np.sum(np.isfinite(spec[w_index-3:w_index+4])) apcor = np.sum( norm[w_index-3:w_index+4])/len( norm[w_index-3:w_index+4]) E.close() # XXX divide by apcor .... return flim_1sigma/apcor, apcor except: return 999
coords = SkyCoord(ra * u.deg, dec * u.deg) L = [] kk = 0 for coord, S, xi in zip(coords, sp, xid): if coord.dec.deg > 0.: pn = '+' else: pn = '-' coord_tup = (coord.ra.hms.h, coord.ra.hms.m, coord.ra.hms.s, pn, np.abs(coord.dec.dms.d), np.abs(coord.dec.dms.m), np.abs(coord.dec.dms.s)) coord_str = '%02dh%02dm%02ds%s%02dd%02dm%02ds' % coord_tup E.log.info('Working on coordinate: %s' % coord_str) E.log.info('Index: %i' % kk) kk +=1 info_result = E.get_fiberinfo_for_coord(coord, radius=7.) if info_result is None: continue E.log.info('Found fibers for coordinate: %s' % coord.to_string(style='hmsdms')) ifux, ifuy, xc, yc, ra, dec, data, error, mask = info_result # Re-centroid? If so, do it here before building aperture (i.e., change xc, yc) image = E.make_collapsed_image(xc, yc, ifux, ifuy, data, mask, scale=0.25, seeing_fac=1.5, boxsize=10.75, wrange=[4900, 5300], nchunks=3, convolve_image=False) flam = 10**(-0.4 * (xi['g']-23.9)) * 1e-29 * 3e18 / 5000.**2 weights = E.build_weights(xc, yc, ifux, ifuy, psf) result = E.get_spectrum(data, error, mask, weights) spectrum, spectrum_error = [res*1. for res in result]
def get_source_spectra(shotid, args): E = Extract() source_dict = {} if args.survey == "hdr1": source_num_switch = 20 else: source_num_switch = 0 if len(args.matched_sources[shotid]) > 0: args.log.info("Working on shot: %s" % shotid) if args.survey == "hdr1": fwhm = args.survey_class.fwhm_moffat[args.survey_class.shotid == shotid][0] else: fwhm = args.survey_class.fwhm_virus[args.survey_class.shotid == shotid][0] moffat = E.moffat_psf(fwhm, 10.5, 0.25) if len(args.matched_sources[shotid]) > source_num_switch: E.load_shot(shotid, fibers=True, survey=args.survey) else: E.load_shot(shotid, fibers=False, survey=args.survey) for ind in args.matched_sources[shotid]: try: info_result = E.get_fiberinfo_for_coord( args.coords[ind], radius=args.rad, ffsky=args.ffsky, return_fiber_info=True, ) except TypeError: info_result = E.get_fiberinfo_for_coord( args.coords, radius=args.rad, ffsky=args.ffsky, return_fiber_info=True, ) if info_result is not None: try: args.log.info("Extracting %s" % args.ID[ind]) except: args.log.info("Extracting %s" % args.ID) ifux, ifuy, xc, yc, ra, dec, data, error, mask, fiberid, \ multiframe = info_result weights = E.build_weights(xc, yc, ifux, ifuy, moffat) result = E.get_spectrum(data, error, mask, weights) spectrum_aper, spectrum_aper_error = [res for res in result] #add in the total weight of each fiber (as the sum of its weight per wavebin) if args.fiberweights: try: fiber_weights = np.array( [x for x in zip(ra, dec, np.sum(weights*mask, axis=1))]) except: fiber_weights = [] else: fiber_weights = [] # get fiber info no matter what so we can flag try: fiber_info = np.array( [ x for x in zip(fiberid, multiframe, ra, dec, np.sum(weights*mask, axis=1))]) except: fiber_info = [] if len(fiber_info) > 0: flags = get_flags(fiber_info) else: flags = None if np.size(args.ID) > 1: if args.ID[ind] in source_dict: source_dict[args.ID[ind]][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] else: source_dict[args.ID[ind]] = dict() source_dict[args.ID[ind]][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] else: if args.ID in source_dict: source_dict[args.ID][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] else: source_dict[args.ID] = dict() source_dict[args.ID][shotid] = [ spectrum_aper, spectrum_aper_error, weights.sum(axis=0), fiber_weights, fiber_info, flags, ] E.shoth5.close() return source_dict