def test_qphot_run_proper_motions(self): # Do photometry on Barnard's Star, the star with the largest-known # proper motion relative to the Solar System. Its coordinates are # J2000, but the DSS image dates back from 1993: qphot.run() must # correct the right ascension and declination before doing photometry, # adjusting for the change in its position over those seven years. barnard_path = "./test/test_data/fits/Barnard's_Star.fits" barnard = astromatic.Coordinates(269.452075, 4.693391, -0.79858, 10.32812) nbits = methods.get_nbits() if nbits == 64: expected_output = ( # x y mag sum flux stdev qphot.QPhotResult(440.947, 382.595, 17.245, 8563646, 5311413, 1039.844)) else: assert nbits == 32 expected_output = ( # <<>> qphot.QPhotResult(440.947, 382.595, 17.245, 8563646, 5312029, 1039.844)) path = fix_DSS_image(barnard_path) with test.test_fitsimage.FITSImage(path) as img: # Fix incorrect date in FITS header: '1993-07-26T04:87:00'. # Subtract sixty minutes and add one hour: 4h87m == 5h27m keyword = 'DATE-OBS' assert img.read_keyword(keyword) == '1993-07-26T04:87:00' img.update_keyword(keyword, '1993-07-26T05:27:00') # The proper-motion corrected coordinates year = img.year(exp_keyword = 'EXPOSURE') expected_coordinates = barnard.get_exact_coordinates(year) result = qphot.run(img, [barnard], **self.QPHOT_KWARGS)[0] self.assertEqual(result, expected_output) # Transform the pixel coordinates that IRAF's qphot outputs for # each measured object to celestial coordinates. This allows us to # make sure that photometry has been effectively done on the right, # proper-motion corrected coordinates. wcs = astropy.wcs.WCS(img._header) ra, dec = wcs.all_pix2world(result.x, result.y, 1) f = self.assertAlmostEqual f(ra, expected_coordinates.ra, delta = 1e-3) # delta = 0.24 arcsec f(dec, expected_coordinates.dec, delta = 1e-3) # delta = 3.6 arcsec
def test_qphot_run_nonzero_cbox(self): # A call to run() with a 'cbox' other than zero. Although the four # input coordinates are the same as in the previous test case, the # output image coordinates are slightly different, as qphot has # computed the accurate center for each object using the centroid # centering algorithm. ngc2264_path = './test/test_data/fits/NGC_2264.fits' ngc2264_input_coords = ( astromatic.Coordinates(100.1543316, 9.7909363), astromatic.Coordinates(100.1597762, 9.7878795), astromatic.Coordinates(100.1598790, 9.9627296), astromatic.Coordinates(100.1191901, 9.8177770)) ngc2264_expected_output = [ # x y mag sum flux stdev qphot.QPhotResult(752.713, 76.071, 17.904, 5820262, 2894284, 548.6724), qphot.QPhotResult(735.552, 65.18, 17.785, 6019633, 3231141, 575.0005), qphot.QPhotResult(734.0, 689.025, 17.639, 6075931, 3694561, 567.6364)] nbits = methods.get_nbits() if nbits == 64: ngc2264_expected_output += [ # <<>> qphot.QPhotResult(877.992, 171.373, 17.627, 6248653, 3737111, 484.8067)] else: assert nbits == 32 ngc2264_expected_output += [ # <<>> qphot.QPhotResult(877.992, 171.373, 17.627, 6248653, 3737479, 484.8067)] kwargs = self.QPHOT_KWARGS.copy() kwargs['cbox'] = 5 path = fix_DSS_image(ngc2264_path) with test.test_fitsimage.FITSImage(path) as img: result = qphot.run(img, ngc2264_input_coords, **kwargs) for phot, expected_phot in zip(result, ngc2264_expected_output): self.assertEqual(phot, expected_phot)
def test_qphot_run(self): # A simple test: do photometry on the DSS image of NGC 2264, measuring # ten astronomical objects whose celestial coordinates (right ascension # and declination) we know. Then, compare the photometric measurements, # returned as qphot.QPhotResult objects, to the expected values. This # is a simple case in which the objects do not have proper motions: we # are mostly testing here that IRAF's qphot runs without any problems. ngc2264_path = './test/test_data/fits/NGC_2264.fits' ngc2264_input_coords = ( astromatic.Coordinates(100.1543316, 9.7909363), astromatic.Coordinates(100.1597762, 9.7878795), astromatic.Coordinates(100.2147546, 9.8636567), astromatic.Coordinates(100.2502955, 9.8714701), astromatic.Coordinates(100.2933265, 9.8838196), astromatic.Coordinates(100.1191901, 9.8177770), astromatic.Coordinates(100.1598790, 9.9627296), astromatic.Coordinates(100.2446191, 9.8962391), astromatic.Coordinates(100.2579343, 9.8802548), astromatic.Coordinates(100.3635468, 9.8540181)) ngc2264_expected_output = [ # x y mag sum flux stdev qphot.QPhotResult(755.241, 75.308, 17.821, 6015410, 3124231, 579.0784), qphot.QPhotResult(736.138, 64.345, 17.777, 6035459, 3254578, 572.4526), qphot.QPhotResult(542.399, 334.835, 18.01, 5197306, 2624735, 374.3998), qphot.QPhotResult(417.419, 362.544, 18.305, 4541155, 2001931, 362.4446), qphot.QPhotResult(266.116, 406.437, 18.12, 4804557, 2372792, 378.5256)] # IRAF returns different values depending on the architecture (32 vs 64 # bits). This is a very strange and confusing behavior, since most of # the time only the *flux* is different, while the magnitude, total # number of counts and even the standard deviation are the same. The # difference looks too big and specific to be only caused by the # limitations of floating-point arithmetic. Until the transition to # Astropy's photutils, take into account both cases (32- vs 64-bit # architecture). See issue #56 for futher information: # https://github.com/vterron/lemon/issues/57 nbits = methods.get_nbits() if nbits == 64: ngc2264_expected_output += [ # <<>> qphot.QPhotResult(878.62, 171.496, 17.623, 6266626, 3749740, 484.9941), qphot.QPhotResult(734.601, 689.319, 17.631, 6102620, 3723123, 555.338) , qphot.QPhotResult(437.227, 451.111, 18.54, 9239881, 1611601, 3583.002), qphot.QPhotResult(390.527, 393.897, 17.768, 5925938, 3280150, 450.3236), qphot.QPhotResult(19.449, 299.555, 17.409, 7143799, 4567058, 540.6945)] else: assert nbits == 32 ngc2264_expected_output += [ # <<>> qphot.QPhotResult(878.62, 171.496, 17.623, 6266626, 3750371, 484.9941), qphot.QPhotResult(734.601, 689.319, 17.631, 6102620, 3723439, 555.338) , qphot.QPhotResult(437.227, 451.111, 18.54, 9239881, 1611932, 3583.002), # <<>> qphot.QPhotResult(390.527, 393.897, 17.768, 5925937, 3280362, 450.3236), qphot.QPhotResult(19.449, 299.555, 17.409, 7143799, 4567332, 540.6945)] path = fix_DSS_image(ngc2264_path) with test.test_fitsimage.FITSImage(path) as img: result = qphot.run(img, ngc2264_input_coords, **self.QPHOT_KWARGS) for phot, expected_phot in zip(result, ngc2264_expected_output): self.assertEqual(phot, expected_phot) # When none of the coordinates have a known proper motion, KeyError is # *not* raised if 'datek' / 'timek' cannot be found in the FITS header: # since there are no proper motions to correct, qphot.run() does not # even bother reading the keywords from the header. kwargs = self.QPHOT_KWARGS.copy() kwargs['datek'] = 'MISSING-KWD' kwargs['timek'] = 'MISSING-KWD' path = fix_DSS_image(ngc2264_path) with test.test_fitsimage.FITSImage(path) as img: # Make sure that both keywords are missing from the FITS header with self.assertRaises(KeyError): img.read_keyword(kwargs['datek']) with self.assertRaises(KeyError): img.read_keyword(kwargs['timek']) # No exception raised, although both keywords are missing qphot.run(img, ngc2264_input_coords, **kwargs)