def test_mosaic_detectors_gmos_binning(astrofaker, hemi, ccd): """ Tests that the spacing between amplifier centres for NxN binned data is precisely N times smaller than for unbinned data when run through mosaicDetectors() """ for binning in (1, 2, 4): try: ad = astrofaker.create('GMOS-{}'.format(hemi), ['IMAGE', ccd]) except ValueError: # No e2v for GMOS-S pytest.skip() ad.init_default_extensions(binning=binning, overscan=False) for ext in ad: shape = ext.data.shape ext.add_star(amplitude=10000, x=0.5 * (shape[1] - 1), y=0.5 * (shape[0] - 1), fwhm=0.5 * binning) p = GMOSImage([ad]) ad = p.mosaicDetectors([ad])[0] ad = p.detectSources([ad])[0] x = np.array(sorted(ad[0].OBJCAT['X_IMAGE'])) if binning == 1: unbinned_positions = x else: diffs = np.diff(unbinned_positions) - binning * np.diff(x) assert np.max(abs(diffs)) < 0.01
def test_measureBG(self, ad): p = GMOSImage([ad]) ad = p.measureBG()[0] correct = [ 726.18213, 724.36047, 727.34491, 728.49664, 728.08966, 719.83728 ] for rv, cv in zip(ad.hdr['SKYLEVEL'], correct): assert abs(rv - cv) < 0.1, 'Wrong background level' assert (ad.phu['SKYLEVEL'] - 727.174) < 0.1 f = open(logfilename) for line in f.readlines(): if 'BG band' in line: assert line.split()[6] == 'BG80', 'Wrong BG band' ad.phu['REQBG'] = '50-percentile' ad = p.measureBG()[0] assert any('WARNING: BG requirement not met' in line for line in f.readlines()), 'No BG warning'
def test_measureIQ(self): ad = astrodata.open( os.path.join(TESTDATAPATH, 'GMOS', 'N20150624S0106_refcatAdded.fits')) p = GMOSImage([ad]) ad = p.measureIQ()[0] # Try to give a reasonable-sized goal assert abs(ad.phu['MEANFWHM'] - 0.42) < 0.02, 'Wrong FWHM' assert abs(ad.phu['MEANELLP'] - 0.09) < 0.02, 'Wrong ellipticity' f = open(logfilename, 'r') for line in f.readlines(): if 'IQ range' in line: assert line.split()[8] == 'IQ20', 'Wrong IQ band' ad.phu['REQIQ'] = '70-percentile' for ext in ad: ext.OBJCAT['PROFILE_FWHM'] *= 2.5 ext.OBJCAT['PROFILE_EE50'] *= 2.5 ad = p.measureIQ()[0] iqwarn = False for line in f.readlines(): if 'IQ range' in line: assert line.split()[8] == 'IQ85', 'Wrong IQ band after edit' iqwarn |= 'WARNING: IQ requirement not met' in line assert iqwarn, 'NO IQ warning'
def plot(ad): """ Displays the tiled arrays with the DQ mask for analysing the data. Parameters ---------- ad : multi-extension data """ from astropy.visualization import ImageNormalize, ZScaleInterval from copy import deepcopy import numpy as np import matplotlib.pyplot as plt p = GMOSImage([deepcopy(ad)]) _ad = p.tileArrays().pop() fig, axs = plt.subplots(num=ad.filename, ncols=len(_ad), sharey=True) norm = ImageNormalize( np.concatenate([ext.data.ravel()[ext.mask.ravel() == 0] for ext in _ad]), interval=ZScaleInterval()) vmin = norm.vmin vmax = norm.vmax for i, ext in enumerate(_ad): data = np.ma.masked_array(ext.data, mask=ext.mask) cmap = plt.get_cmap('viridis') cmap.set_bad('red', alpha='0.5') axs[i].imshow(data, origin='lower', cmap=cmap, vmin=vmin, vmax=vmax) # axs[i].imshow(data.data, origin='lower', vmin=vmin, vmax=vmax) plt.show()
def test_measureCC(self): ad = astrodata.open( os.path.join(TESTDATAPATH, 'GMOS', 'N20150624S0106_refcatAdded.fits')) p = GMOSImage([ad]) ad = p.measureCC()[0] correct = [28.18, 28.16, 28.14, 28.11, 28.17, 28.12] for rv, cv in zip(ad.hdr['MEANZP'], correct): assert abs(rv - cv) < 0.02, 'Wrong zeropoint' f = open(logfilename, 'r') for line in f.readlines(): if 'CC bands' in line: assert 'CC50, CC70' in line, 'Wrong CC bands' for ext in ad: ext.OBJCAT['MAG_AUTO'] += 0.3 ad = p.measureCC()[0] correct = [c - 0.3 for c in correct] for rv, cv in zip(ad.hdr['MEANZP'], correct): assert abs(rv - cv) < 0.02, 'Wrong zeropoint after edit' ccwarn = False for line in f.readlines(): if 'CC bands' in line: assert 'CC70, CC80' in line, 'Wrong CC bands after edit' ccwarn |= 'WARNING: CC requirement not met' in line assert ccwarn, 'No CC warning'
def test_measureIQ(self, ad): p = GMOSImage([ad]) ad = p.measureIQ()[0] # Try to give a reasonable-sized goal assert abs(ad.phu['MEANFWHM'] - 0.42) < 0.02, 'Wrong FWHM' assert abs(ad.phu['MEANELLP'] - 0.09) < 0.02, 'Wrong ellipticity' f = open(logfilename) for line in f.readlines(): if 'IQ range' in line: assert line.split()[8] == 'IQ20', 'Wrong IQ band' ad.phu['REQIQ'] = '70-percentile' for ext in ad: ext.OBJCAT['PROFILE_FWHM'] *= 2.5 ext.OBJCAT['PROFILE_EE50'] *= 2.5 ad = p.measureIQ()[0] iqwarn = False for line in f.readlines(): if 'IQ range' in line: assert line.split()[8] == 'IQ85', 'Wrong IQ band after edit' iqwarn |= 'WARNING: IQ requirement not met' in line assert iqwarn, 'NO IQ warning'
def test_add_object_mask_to_dq(astrofaker): ad_orig = astrofaker.create('F2', 'IMAGE') # astrodata.open(os.path.join(TESTDATAPATH, 'GMOS', 'N20150624S0106_refcatAdded.fits')) p = GMOSImage([deepcopy(ad_orig)]) ad = p.addObjectMaskToDQ()[0] for ext, ext_orig in zip(ad, ad_orig): assert all( ext.mask[ext.OBJMASK == 0] == ext_orig.mask[ext.OBJMASK == 0]) assert all( ext.mask[ext.OBJMASK == 1] == ext_orig.mask[ext.OBJMASK == 1] | 1)
def test_add_oiwfs_runs_normally(caplog, ext_num, filename, x0, y0): """ Test that the primitive does not run if the input file does not have a DQ plan. Parameters ---------- caplog : fixture filename : str """ caplog.set_level(logging.DEBUG) file_path = download_from_archive(filename) ad = astrodata.open(file_path) p = GMOSImage([ad]) p.addDQ() p.addVAR(read_noise=True) p.addOIWFSToDQ() # plot(p.streams['main'][0]) assert len(caplog.records) > 0 assert any("Guide star location found at" in r.message for r in caplog.records) # Some kind of regression test for r in caplog.records: if r.message.startswith("Guide star location found at"): coords = re.findall(r"\((.*?)\)", r.message).pop().split(',') x = float(coords[0]) y = float(coords[1]) n = int(r.message.split(' ')[-1]) assert abs(x - x0) < 1 assert abs(y - y0) < 1 assert n == ext_num
def test_add_oiwfs_warns_when_wfs_if_not_in_field(caplog, filename): """ Test that the primitive does not run if the input file does not have a DQ plan. Parameters ---------- caplog : fixture filename : str """ caplog.set_level(logging.DEBUG) file_path = download_from_archive(filename) ad = astrodata.open(file_path) p = GMOSImage([ad]) p.addDQ() p.addVAR(read_noise=True) p.addOIWFSToDQ() # plot(p.streams['main'][0]) print(caplog.records) assert any("No good rows in" in r.message for r in caplog.records) assert any("Cannot distinguish probe region from sky for" in r.message for r in caplog.records)
def test_gmos_wcs_stability(raw_ad_path, do_prepare, do_overscan_correct, tile_all): raw_ad = astrodata.open(raw_ad_path) # Ensure it's tagged IMAGE so we can get an imaging WCS and can use SkyCoord raw_ad.phu['GRATING'] = 'MIRROR' # Check the reference extension is what we think and find the middle ref_index = find_reference_extension(raw_ad) assert ref_index == (len(raw_ad) - 1) // 2 # works for GMOS y, x = [length // 2 for length in raw_ad[ref_index].shape] c0 = SkyCoord(*raw_ad[ref_index].wcs(x, y), unit="deg") p = GMOSImage([raw_ad]) # TODO: support for other instruments geotable = import_module('.geometry_conf', p.inst_lookups) chip_gaps = geotable.tile_gaps[raw_ad.detector_name()] # Test that prepare keeps the reference extenion's WCS intact if do_prepare: p.prepare() c = SkyCoord(*raw_ad[ref_index].wcs(x, y), unit="deg") assert c0.separation(c) < 1e-10 * u.arcsec # Test that slicing the NDData keeps the WCS valid if do_overscan_correct: xshift, _, yshift, _ = raw_ad[ref_index].data_section() p.overscanCorrect() x -= xshift y -= yshift c = SkyCoord(*raw_ad[ref_index].wcs(x, y), unit="deg") assert c0.separation(c) < 1e-10 * u.arcsec # Test that tiling doesn't affect the reference extension's WCS new_ref_index = 0 if ( tile_all or raw_ad.detector_roi_setting() == 'Central Stamp') else 1 p.tileArrays(tile_all=tile_all) ad = p.streams['main'][0] first = 0 if tile_all else (len(raw_ad) // 3) # index of first raw extension # These extension widths are either overscan-trimmed or not, as # required and so no alternative logic is required x += sum([ext.shape[1] for ext in raw_ad[first:ref_index]]) if tile_all and raw_ad.detector_roi_setting() != 'Central Stamp': x += chip_gaps // raw_ad.detector_x_bin() c = SkyCoord(*ad[new_ref_index].wcs(x, y), unit="deg") assert c0.separation(c) < 1e-10 * u.arcsec # Now write the file to disk and read it back in and check WCS stability ad.write(TEMPFILE, overwrite=True) ad = astrodata.open(TEMPFILE) c = SkyCoord(*ad[new_ref_index].wcs(x, y), unit="deg") assert c0.separation(c) < 1e-9 * u.arcsec os.remove(TEMPFILE)
def test_add_object_mask_to_dq(): try: import AstroFaker except ImportError: pytest.skip("AstroFaker not installed") ad_orig = AstroFaker.create('F2', 'IMAGE') #astrodata.open(os.path.join(TESTDATAPATH, 'GMOS', 'N20150624S0106_refcatAdded.fits')) p = GMOSImage([deepcopy(ad_orig)]) ad = p.addObjectMaskToDQ()[0] for ext, ext_orig in zip(ad, ad_orig): assert all( ext.mask[ext.OBJMASK == 0] == ext_orig.mask[ext.OBJMASK == 0]) assert all( ext.mask[ext.OBJMASK == 1] == ext_orig.mask[ext.OBJMASK == 1] | 1)
def test_oiwfs_not_used_in_observation(caplog, filename): """ Test that nothing happens when the input file does not use the OIWFS. Parameters ---------- caplog : fixture filename : str """ caplog.set_level(logging.DEBUG) file_path = download_from_archive(filename) ad = astrodata.open(file_path) p = GMOSImage([ad]) p.addOIWFSToDQ() print(caplog.records) assert len(caplog.records) > 0 assert any("OIWFS not used for image" in r.message for r in caplog.records)
def test_warn_if_dq_does_not_exist(caplog, filename): """ Test that the primitive does not run if the input file does not have a DQ plan. Parameters ---------- caplog : fixture filename : str """ caplog.set_level(logging.DEBUG) file_path = download_from_archive(filename) ad = astrodata.open(file_path) p = GMOSImage([ad]) p.addOIWFSToDQ() assert len(caplog.records) > 0 assert any("No DQ plane for" in r.message for r in caplog.records)
def test_measureBG(self): ad = astrodata.open( os.path.join(TESTDATAPATH, 'GMOS', 'N20150624S0106_refcatAdded.fits')) p = GMOSImage([ad]) ad = p.measureBG()[0] correct = [ 726.18213, 724.36047, 727.34491, 728.49664, 728.08966, 719.83728 ] for rv, cv in zip(ad.hdr['SKYLEVEL'], correct): assert abs(rv - cv) < 0.1, 'Wrong background level' assert (ad.phu['SKYLEVEL'] - 727.174) < 0.1 f = open(logfilename, 'r') for line in f.readlines(): if 'BG band' in line: assert line.split()[6] == 'BG80', 'Wrong BG band' ad.phu['REQBG'] = '50-percentile' ad = p.measureBG()[0] assert any('WARNING: BG requirement not met' in line for line in f.readlines()), 'No BG warning'
def test_inverse_transform_gmos(astrofaker, binning): # Creates GMOS images with stars at predefined points ad = astrofaker.create('GMOS-N') ad.init_default_extensions(binning=binning, overscan=False) for ext in ad: ext.add(np.random.randn(*ext.shape)) for ystar, xstar in GMOS_STAR_LOCATIONS: ext.add_star(amplitude=10000, x=xstar / binning, y=ystar / binning) adg = transform.create_mosaic_transform(ad, geotable) admos = adg.transform(attributes=None, order=1) adout = adg.inverse_transform(admos, order=3) p = GMOSImage([adout]) p.detectSources() adout = p.streams['main'][0] xbin, ybin = ad.detector_x_bin(), ad.detector_y_bin() for ext in adout: objcat = ext.OBJCAT objcat.sort(['Y_IMAGE']) for row, location in zip(objcat, GMOS_STAR_LOCATIONS): # OBJCAT is 1-indexed assert abs(row['Y_IMAGE'] - location[0] / ybin - 1) < 0.1 assert abs(row['X_IMAGE'] - location[1] / xbin - 1) < 0.1
def test_measureCC(self, ad): p = GMOSImage([ad]) ad = p.measureCC()[0] correct = [28.18, 28.16, 28.14, 28.11, 28.17, 28.12] for rv, cv in zip(ad.hdr['MEANZP'], correct): assert abs(rv - cv) < 0.02, 'Wrong zeropoint' f = open(logfilename) for line in f.readlines(): if 'CC bands' in line: assert 'CC50, CC70' in line, 'Wrong CC bands' for ext in ad: ext.OBJCAT['MAG_AUTO'] += 0.3 ad = p.measureCC()[0] correct = [c - 0.3 for c in correct] for rv, cv in zip(ad.hdr['MEANZP'], correct): assert abs(rv - cv) < 0.02, 'Wrong zeropoint after edit' ccwarn = False for line in f.readlines(): if 'CC bands' in line: assert 'CC70, CC80' in line, 'Wrong CC bands after edit' ccwarn |= 'WARNING: CC requirement not met' in line assert ccwarn, 'No CC warning'
def test_plot_spectra_for_qa(input_ads): for i, ad in enumerate(input_ads): # Plot single frame p = primitives_visualize.Visualize([]) p.plotSpectraForQA(adinputs=[ad]) # Gives some time to page refresh time.sleep(10) # Plot Stack if i >= 1: print('Reducing stack') stack_ad = GMOSImage([]).stackFrames(adinputs=input_ads[:i + 1])[0] p.plotSpectraForQA(adinputs=[stack_ad]) # Gives some time to page refresh time.sleep(10)
def test_fit_continuum_slit_image(fname, fwhm, change_working_dir): with change_working_dir(): log_file = 'log_{}.log'.format(fname.replace('.fits', '')) logutils.config(file_name=log_file) ad = astrodata.open(astrodata.testing.download_from_archive(fname)) p = GMOSImage([ad]) p.prepare(attach_mdf=True) p.addDQ() p.trimOverscan() p.ADUToElectrons() p.mosaicDetectors() tbl = gt.fit_continuum(p.streams['main'][0])[0] assert isinstance(tbl, Table) assert len(tbl) == 1 assert abs(tbl['fwhm_arcsec'].data[0] - fwhm) < 0.05
def test_fit_continuum_slit_image(path_to_inputs): results = {'N20180118S0344': 1.32} for fname, fwhm in results.items(): ad = astrodata.open( os.path.join(path_to_inputs, 'gt/slit_images', '{}.fits'.format(fname))) p = GMOSImage([ad]) p.prepare(attach_mdf=True) p.addDQ() p.trimOverscan() p.ADUToElectrons() p.mosaicDetectors() tbl = gt.fit_continuum(p.streams['main'][0])[0] assert isinstance(tbl, Table) assert len(tbl) == 1 assert abs(tbl['fwhm_arcsec'].data[0] - fwhm) < 0.05