def fromMarzJSON(json_spectrum): from astropy.nddata import ( VarianceUncertainty, StdDevUncertainty, InverseVariance, ) wavelength = Quantity(json_spectrum["wavelength"], u.Angstrom) spectrum = SpectrumList() uncertainty = None if "variance" in json_spectrum.keys(): uncertainty = StdDevUncertainty( Quantity(np.array(json_spectrum["variance"], dtype=np.float))) for key in json_spectrum.keys(): if key != 'wavelength' and key != 'variance': flux = Quantity(np.array(json_spectrum[key], dtype=np.float)) if key == 'intensity' and uncertainty: aspectrum = Spectrum1D(flux=flux, spectral_axis=wavelength, uncertainty=uncertainty, mask=np.isnan(flux), meta={'purpose': 'reduced'}) else: aspectrum = Spectrum1D(flux=flux, spectral_axis=wavelength, mask=np.isnan(flux), meta={'purpose': key}) spectrum.append(aspectrum) return spectrum
def load_aaomega_file(filename, *args, **kwargs): with read_fileobj_or_hdulist(filename, *args, **kwargs) as fits_file: fits_header = fits_file[AAOMEGA_SCIENCE_INDEX].header # fits_file is the hdulist var_idx = None rwss_idx = None for idx, extn in enumerate(fits_file): if extn.name == "VARIANCE": var_idx = idx if extn.name == "RWSS": rwss_idx = idx # science data fits_data = fits_file[AAOMEGA_SCIENCE_INDEX].data # read in Fibre table data.... ftable = Table(fits_file[AAOMEGA_FIBRE_INDEX].data) # A SpectrumList to hold all the Spectrum1D objects sl = SpectrumList() # the row var contains the pixel data from the science frame for i, row in enumerate(fits_data): # Definitely need deepcopy here, otherwise it does *NOT* work! fib_header = deepcopy(fits_header) # Adjusting some values from primary header so individual fibre # spectra have meaningful headers fib_header["FLDNAME"] = (fits_header["OBJECT"], "Name of 2dF .fld file") fib_header["FLDRA"] = ( fits_header["MEANRA"], "Right Ascension of 2dF field", ) fib_header["FLDDEC"] = (fits_header["MEANDEC"], "Declination of 2dF field") # Now for the fibre specific information from the Fibre Table # (extension 2) # Caution: RA and DEC are stored in RADIANS in the FIBRE TABLE! fib_header["RA"] = ( ftable["RA"][i] * 180.0 / np.pi, "Right Ascension of fibre from configure .fld file", ) fib_header["DEC"] = ( ftable["DEC"][i] * 180.0 / np.pi, "Declination of fibre from configure .fld file", ) fib_header["OBJECT"] = ( ftable["NAME"][i], "Name of target observed by fibre", ) fib_header["OBJCOM"] = ( ftable["COMMENT"][i], "Comment from configure .fld file for target", ) fib_header["OBJMAG"] = ( ftable["MAGNITUDE"][i], "Magnitude of target observed by fibre", ) fib_header["OBJTYPE"] = ( ftable["TYPE"][i], "Type of target observed by fibre", ) fib_header["OBJPIV"] = ( ftable["PIVOT"][i], "Pivot number used to observe target", ) fib_header["OBJPID"] = ( ftable["PID"][i], "Program ID from configure .fld file", ) fib_header["OBJX"] = ( ftable["X"][i], "X coord of target observed by fibre (microns)", ) fib_header["OBJY"] = ( ftable["Y"][i], "Y coord of target observed by fibre (microns)", ) fib_header["OBJXERR"] = ( ftable["XERR"][i], "X coord error of target observed by fibre (microns)", ) fib_header["OBJYERR"] = ( ftable["YERR"][i], "Y coord error of target observed by fibre (microns)", ) fib_header["OBJTHETA"] = ( ftable["THETA"][i], "Angle of fibre used to observe target", ) fib_header["OBJRETR"] = ( ftable["RETRACTOR"][i], "Retractor number used to observe target", ) # WLEN added around 2005 according to AAOmega obs manual... # so not always available if "WLEN" in ftable.colnames: fib_header["OBJWLEN"] = ( ftable["WLEN"][i], "Retractor of target observed by fibre", ) # ftable['TYPE'][i]: # P == program (science) # S == sky # U == unallocated or unused # F == fiducial (guide) fibre # N == broken, dead or no fibre meta = {"header": fib_header} if ftable["TYPE"][i] == "P": meta["purpose"] = "reduced" elif ftable["TYPE"][i] == "S": meta["purpose"] = "sky" else: # Don't include other fibres that are not science or sky continue wcs = compute_wcs_from_keys_and_values(fib_header, **AAOMEGA_2DF_WCS_SETTINGS) flux = row * AAOMEGA_2DF_FLUX_UNIT meta["fibre_index"] = i # Our science spectrum spectrum = Spectrum1D(wcs=wcs, flux=flux, meta=meta) # If the VARIANCE spectrum exists, add it as an additional spectrum # in the meta dict with key 'variance' if var_idx is not None: var_data = fits_file[var_idx].data var_flux = var_data[i] * AAOMEGA_2DF_FLUX_UNIT**2 spectrum.uncertainty = VarianceUncertainty(var_flux) # If the RWSS spectrum exists, add it as an additional spectrum in # the meta dict with key 'science_sky' # This is an optional extension produced by 2dfdr on request: all # spectra without the average/median sky subtraction # Useful in case users want to do their own sky subtraction. if rwss_idx is not None: rwss_data = fits_file[rwss_idx].data rwss_flux = rwss_data[i] * AAOMEGA_2DF_FLUX_UNIT rwss_meta = {"header": fib_header, "purpose": "science_sky"} spectrum.meta["science_sky"] = Spectrum1D(wcs=wcs, flux=rwss_flux, meta=rwss_meta) # Add our spectrum to the list. # The additional spectra are accessed using # spectrum.meta['variance'] and spectrum.meta['science_sky'] sl.append(spectrum) add_labels(sl) return sl
ss_spectrum, "Custom pipeline sky subtracted spectrum", sky_flux=avg_sky_flux, c_range=low_region, h_range=high_region) plt.savefig(output_dir / (fits_file_name + ".pdf"), dpi=300) plt.close() # Diagnostics - plot the spectra from every fibre (to a different file to the other plots - it's big!!) if plot_rss_spectra: plotting.plot_rss_spectra(non_ss_spectra, flux_ratios, fits_file_name, sky_mask, obj_mask, low_region, high_region, output_dir, expand_rss_spectra) fits_group_ss_spectra.append(ss_spectrum) # Combine the spectra in the group image_file_name = output_dir / f"ss_{fits_group}.pdf" grp_spectra = SpectrumCollectionEx.from_spectra( fits_group_ss_spectra, fits_group) grp_spectrum = Spectrum1DEx(flux=np.mean(grp_spectra.flux, axis=0), spectral_axis=grp_spectra.spectral_axis[0]) plotting.plot_spectrum( grp_spectrum, filename=image_file_name, title= f"Custom pipeline sky subtracted & combined spectrum for observations {fits_group}" ) # Save to a new fits file