def test_curved_equal_vertical_extraction(sample_data, orders): # Currently extract always uses the vertical extraction, making this kind of useless img, spec, slitf = sample_data tilt = 0 shear = 0 spec_curved, sunc_curved, slitf_curved, _ = extract.extract(img, orders, tilt=tilt, shear=shear) spec_vert, sunc_vert, slitf_vert, _ = extract.extract(img, orders) assert np.allclose(spec_curved, spec_vert, rtol=1e-2) # assert np.allclose(sunc_curved, sunc_vert, rtol=0.1) assert np.allclose(slitf_curved, slitf_vert, rtol=1e-1)
def test_vertical_extraction(sample_data, orders, width, height, noise, oversample): img, spec, slitf = sample_data spec_vert, sunc_vert, slitf_vert, _ = extract.extract(img, orders) assert isinstance(spec_vert, np.ma.masked_array) assert spec_vert.ndim == 2 assert spec_vert.shape[0] == orders.shape[0] assert spec_vert.shape[1] == width assert isinstance(sunc_vert, np.ma.masked_array) assert sunc_vert.ndim == 2 assert sunc_vert.shape[0] == orders.shape[0] assert sunc_vert.shape[1] == width assert isinstance(slitf_vert, np.ndarray) assert slitf_vert.ndim == 2 assert slitf_vert.shape[0] == orders.shape[0] assert slitf_vert.shape[1] <= height * oversample assert not np.any(spec_vert == 0) assert np.abs(np.diff(spec / spec_vert[0])).max() <= noise + 1e-1 assert not np.any(sunc_vert == 0) assert np.abs( sunc_vert / spec_vert).max() <= noise * 1.1 * oversample + 1e-2
def test_wavecal(files, instr, instrument, mode, mask, orders, settings, order_range): name = "wavecal_master" if len(files[name]) == 0: pytest.skip(f"No wavecal files found for instrument {instrument}") orders, column_range = orders files = files[name][0] orig, thead = instr.load_fits(files, mode, mask=mask) thead["obase"] = (0, "base order number") # Extract wavecal spectrum thar, _, _, _ = extract( orig, orders, gain=thead["e_gain"], readnoise=thead["e_readn"], dark=thead["e_drk"], extraction_type="arc", column_range=column_range, order_range=order_range, extraction_width=settings[name]["extraction_width"], plot=False, ) assert isinstance(thar, np.ndarray) assert thar.ndim == 2 assert thar.shape[0] == order_range[1] - order_range[0] assert thar.shape[1] == orig.shape[1] assert np.issubdtype(thar.dtype, np.floating) # assert np.min(thar) == 0 # assert np.max(thar) == 1 reference = instr.get_wavecal_filename(thead, mode, **settings["instrument"]) reference = np.load(reference, allow_pickle=True) linelist = reference["cs_lines"] name = "wavecal" module = WavelengthCalibration( plot=False, manual=False, threshold=settings[name]["threshold"], degree=settings[name]["degree"], ) wave, solution = module.execute(thar, linelist) assert isinstance(wave, np.ndarray) assert wave.ndim == 2 assert wave.shape[0] == order_range[1] - order_range[0] assert wave.shape[1] == orig.shape[1] assert np.issubdtype(wave.dtype, np.floating)
def test_normflat(flat, orders, settings, order_range, scatter, instrument): flat, fhead = flat orders, column_range = orders settings = settings["norm_flat"] if flat[0] is None: pytest.skip(f"No flat exists for instrument {instrument}") norm, _, blaze, _ = extract( flat, orders, scatter=scatter, gain=fhead["e_gain"], readnoise=fhead["e_readn"], dark=fhead["e_drk"], column_range=column_range, order_range=order_range, extraction_type="normalize", extraction_width=settings["extraction_width"], threshold=settings["threshold"], lambda_sf=settings["smooth_slitfunction"], lambda_sp=settings["smooth_spectrum"], swath_width=settings["swath_width"], plot=False, ) assert isinstance(norm, np.ndarray) assert norm.ndim == flat.ndim assert norm.shape[0] == flat.shape[0] assert norm.shape[1] == flat.shape[1] assert norm.dtype == flat.dtype assert np.ma.min(norm) > 0 assert not np.any(np.isnan(norm)) assert isinstance(blaze, np.ndarray) assert blaze.ndim == 2 assert blaze.shape[0] == order_range[1] - order_range[0] assert blaze.shape[1] == flat.shape[1] assert np.issubdtype(blaze.dtype, np.floating) assert not np.any(np.isnan(blaze)) for i, j in enumerate(range(order_range[0], order_range[1])): cr = column_range[j] assert np.all(blaze[i, :cr[0]].mask == True) assert np.all(blaze[i, cr[1]:].mask == True)
def extracted(original, orders, order_range, settings): original, chead = original orders, column_range = orders settings = settings["curvature"] if original is None: return None extracted, _, _, _ = extract( original, orders, gain=chead["e_gain"], readnoise=chead["e_readn"], dark=chead["e_drk"], extraction_type="arc", column_range=column_range, order_range=order_range, plot=False, extraction_width=settings["extraction_width"], ) return extracted
def test_extract(sample_data, orders): img, spec, slitf = sample_data with pytest.raises(ValueError): extract.extract(img, orders, extraction_type="foobar")
def test_science( files, instrument, mode, mask, extension, bias, normflat, orders, settings, order_range, ): flat, blaze = normflat bias, _ = bias orders, column_range = orders settings = settings["science"] # Fix column ranges for i in range(blaze.shape[0]): column_range[i] = np.where(blaze[i] != 0)[0][[0, -1]] f = files["science"][0] im, head = util.load_fits( f, instrument, mode, extension, mask=mask, dtype=np.float32 ) # Correct for bias and flat field im -= bias im /= flat # Optimally extract science spectrum spec, sigma, _, _ = extract( im, orders, gain=head["e_gain"], readnoise=head["e_readn"], dark=head["e_drk"], column_range=column_range, order_range=order_range, extraction_type=settings["extraction_method"], extraction_width=settings["extraction_width"], lambda_sf=settings["smooth_slitfunction"], lambda_sp=settings["smooth_spectrum"], osample=settings["oversampling"], swath_width=settings["swath_width"], plot=False, ) assert isinstance(spec, np.ma.masked_array) assert spec.ndim == 2 assert spec.shape[0] == order_range[1] - order_range[0] assert spec.shape[1] == bias.shape[1] assert np.issubdtype(spec.dtype, np.floating) assert not np.any(np.isnan(spec)) assert not np.all(np.all(spec.mask, axis=0)) assert isinstance(sigma, np.ma.masked_array) assert sigma.ndim == 2 assert sigma.shape[0] == order_range[1] - order_range[0] assert sigma.shape[1] == bias.shape[1] assert np.issubdtype(sigma.dtype, np.floating) assert not np.any(np.isnan(sigma)) assert not np.all(np.all(sigma.mask, axis=0))
def spec( files, instrument, mode, mask, extension, bias, normflat, orders, settings, output_dir, order_range, ): """Load or create science spectrum Parameters ---------- files : dict(str:str) raw input files instrument : str instrument name mode : str observing mode mask : array(bool) Bad pixel mask extension : int fits data extension bias : array(float) bias calibration data normflat : array(float) normalized flat field orders : array(float) order tracing polynomials and column_ranges settings : dict(str:obj) run settings output_dir : str output data directory Returns ------- spec : array(float) of size (norders, ncol) extracted science spectra sigma : array(float) of size (norders, ncol) uncertainty on the extracted science spectra """ orders, column_range = orders specfile = os.path.join(output_dir, "test_spec.ech") settings = settings["science"] try: science = echelle.read(specfile, raw=True) head = science.header spec = science["spec"] sigma = science["sig"] mask = np.full(spec.shape, True) for iord in range(spec.shape[0]): cr = column_range[iord] mask[iord, cr[0]:cr[1]] = False spec = np.ma.array(spec, mask=mask) sigma = np.ma.array(sigma, mask=mask) except FileNotFoundError: flat, blaze = normflat bias, _ = bias # Fix column ranges for i in range(blaze.shape[0]): column_range[i] = np.where(blaze[i] != 0)[0][[0, -1]] f = files["science"][0] im, head = util.load_fits(f, instrument, mode, extension, mask=mask, dtype=np.float32) # Correct for bias and flat field im -= bias im /= flat # Optimally extract science spectrum spec, sigma, _, columns = extract( im, orders, gain=head["e_gain"], readnoise=head["e_readn"], dark=head["e_drk"], column_range=column_range, order_range=order_range, extraction_type=settings["extraction_method"], extraction_width=settings["extraction_width"], lambda_sf=settings["smooth_slitfunction"], lambda_sp=settings["smooth_spectrum"], osample=settings["oversampling"], swath_width=settings["swath_width"], plot=False, ) echelle.save(specfile, head, spec=spec, sig=sigma, columns=columns) return spec, sigma
def wave(files, instrument, mode, extension, mask, orders, settings, output_dir, order_range): """Load or create wavelength calibration files Parameters ---------- files : dict(str:str) calibration file names instrument : str instrument name mode : str observing mode extension : int fits data extension mask : array(bool) Bad pixel mask orders : tuple(array, array) order tracing polynomials and column ranges settings : dict(str:obj) run settings output_dir : str output data directory Returns ------- wave : array(float) of size (norder, ncol) Wavelength along the spectral orders """ orders, column_range = orders wavefile = os.path.join(output_dir, "test_wavecal.thar.ech") settings = settings["wavecal"] if os.path.exists(wavefile): data = np.load(wavefile, allow_pickle=True) thar = data["thar"] wave = data["wave"] solution = data["solution"] else: files = files["wavecal"][0] orig, thead = util.load_fits(files, instrument, mode, extension, mask=mask) thead["obase"] = (0, "base order number") # Extract wavecal spectrum thar, _, _, _ = extract( orig, orders, gain=thead["e_gain"], readnoise=thead["e_readn"], dark=thead["e_drk"], extraction_type=settings["extraction_method"], column_range=column_range, order_range=order_range, extraction_width=settings["extraction_width"], plot=False, ) reference = instruments.instrument_info.get_wavecal_filename( thead, instrument, mode) reference = np.load(reference, allow_pickle=True) linelist = reference["cs_lines"] module = WavelengthCalibration(plot=False, manual=False) wave, solution = module.execute(thar, linelist) np.savez(wavefile, thar=thar, wave=wave, solution=solution) return wave, thar
def test_science( files, instr, instrument, mode, mask, bias, normflat, orders, settings, order_range, ): if len(files["science"]) == 0: pytest.skip(f"No science files found for instrument {instrument}") flat, blaze = normflat bias, bhead = bias orders, column_range = orders settings = settings["science"] # Fix column ranges for i in range(blaze.shape[0]): column_range[i] = np.where(blaze[i] != 0)[0][[0, -1]] f = files["science"][0] im, head = combine_calibrate( [f], instr, mode, mask=mask, bias=bias, bhead=bhead, norm=flat, bias_scaling=settings["bias_scaling"], ) # Optimally extract science spectrum spec, sigma, _, _ = extract( im, orders, gain=head["e_gain"], readnoise=head["e_readn"], dark=head["e_drk"], column_range=column_range, order_range=order_range, extraction_type=settings["extraction_method"], extraction_width=settings["extraction_width"], lambda_sf=settings["smooth_slitfunction"], lambda_sp=settings["smooth_spectrum"], osample=settings["oversampling"], swath_width=settings["swath_width"], plot=False, ) assert isinstance(spec, np.ma.masked_array) assert spec.ndim == 2 assert spec.shape[0] == order_range[1] - order_range[0] assert spec.shape[1] == im.shape[1] assert np.issubdtype(spec.dtype, np.floating) assert not np.any(np.isnan(spec)) assert not np.all(np.all(spec.mask, axis=0)) assert isinstance(sigma, np.ma.masked_array) assert sigma.ndim == 2 assert sigma.shape[0] == order_range[1] - order_range[0] assert sigma.shape[1] == im.shape[1] assert np.issubdtype(sigma.dtype, np.floating) assert not np.any(np.isnan(sigma)) assert not np.all(np.all(sigma.mask, axis=0))