import unittest
import os
import numpy as np
import numbers
import lsst.utils.tests
from lsst.utils import getPackageDir
from lsst.afw.cameraGeom import PIXELS, FOCAL_PLANE, SCIENCE
import lsst.afw.geom as afwGeom
from lsst.sims.coordUtils import lsst_camera
from lsst.sims.coordUtils import focalPlaneCoordsFromPupilCoordsLSST
from lsst.sims.coordUtils import focalPlaneCoordsFromPupilCoords
from lsst.sims.coordUtils import pupilCoordsFromFocalPlaneCoordsLSST
from lsst.sims.coordUtils import DMtoCameraPixelTransformer
from lsst.sims.utils import ObservationMetaData
from lsst.sims.utils import pupilCoordsFromRaDec
from lsst.sims.utils import radiansFromArcsec
from lsst.sims.utils import angularSeparation
from lsst.sims.coordUtils import chipNameFromPupilCoordsLSST
from lsst.sims.coordUtils import chipNameFromRaDecLSST
from lsst.sims.coordUtils import _chipNameFromRaDecLSST
from lsst.sims.coordUtils import pixelCoordsFromRaDecLSST
from lsst.sims.coordUtils import _pixelCoordsFromRaDecLSST
from lsst.sims.coordUtils import pixelCoordsFromRaDec
from lsst.sims.coordUtils import pixelCoordsFromPupilCoordsLSST
from lsst.sims.coordUtils import pupilCoordsFromPixelCoordsLSST
from lsst.sims.coordUtils import raDecFromPixelCoordsLSST
from lsst.sims.coordUtils import _raDecFromPixelCoordsLSST
from lsst.sims.coordUtils.LsstZernikeFitter import _rawPupilCoordsFromObserved
from lsst.sims.coordUtils import clean_up_lsst_camera
def setup_module(module):
lsst.utils.tests.init()
class FocalPlaneTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
pix_transformer = DMtoCameraPixelTransformer()
data_dir = os.path.join(getPackageDir('sims_data'),
'FocalPlaneData',
'UnitTestData')
cls._data_dir = data_dir
phosim_dtype = np.dtype([('id', int), ('phot', int),
('xpix', float), ('ypix', float)])
camera = lsst_camera()
cls._phosim_positions = {}
for i_band in range(6):
id_arr = None
x_arr = None
y_arr = None
for det in camera:
if det.getType() != SCIENCE:
continue
det_name = det.getName()
name = det_name.replace(':','').replace(',','')
name = name.replace(' ','_')
file_name = 'centroid_lsst_e_2_f%d_%s_E000.txt' % (i_band, name)
data = np.genfromtxt(os.path.join(data_dir, 'PhoSimData',
file_name),
dtype=phosim_dtype,
skip_header=1)
dm_x, dm_y = pix_transformer.dmPixFromCameraPix(data['xpix'],
data['ypix'],
det_name)
pix_to_focal = det.getTransform(PIXELS, FOCAL_PLANE)
x_mm = np.zeros(len(dm_x))
y_mm = np.zeros(len(dm_y))
for ii in range(len(x_mm)):
pix_pt = afwGeom.Point2D(dm_x[ii], dm_y[ii])
focal_pt = pix_to_focal.applyForward(pix_pt)
x_mm[ii] = focal_pt.getX()
y_mm[ii] = focal_pt.getY()
if id_arr is None:
id_arr = data['id']
x_arr = x_mm
y_arr = y_mm
else:
id_arr = np.append(id_arr, data['id'])
x_arr = np.append(x_arr, x_mm)
y_arr = np.append(y_arr, y_mm)
sorted_dex = np.argsort(id_arr)
id_arr = id_arr[sorted_dex]
x_arr = x_arr[sorted_dex]
y_arr = y_arr[sorted_dex]
cls._phosim_positions[i_band] = {}
cls._phosim_positions[i_band]['id'] = id_arr
cls._phosim_positions[i_band]['xmm'] = x_arr
cls._phosim_positions[i_band]['ymm'] = y_arr
@classmethod
def tearDownClass(cls):
clean_up_lsst_camera()
def test_focal_plane_from_pupil(self):
"""
Test conversion from pupil coords to focal plane coords
using data generated by PhoSim
"""
catsim_dtype = np.dtype([('id', int),
('xmm', float), ('ymm', float),
('xpup', float), ('ypup', float),
('raObs', float), ('decObs', float)])
catsim_data = np.genfromtxt(os.path.join(self._data_dir, 'CatSimData',
'predicted_positions.txt'),
dtype=catsim_dtype)
for i_band, band in enumerate('ugrizy'):
np.testing.assert_array_equal(catsim_data['id'],
self._phosim_positions[i_band]['id'])
xmm, ymm = focalPlaneCoordsFromPupilCoordsLSST(catsim_data['xpup'],
catsim_data['ypup'],
band)
distance = np.sqrt((xmm-self._phosim_positions[i_band]['xmm'])**2 +
(ymm-self._phosim_positions[i_band]['ymm'])**2)
# make sure predicted positions are accurate to within
# 1 pixel = 0.01 mm
self.assertLess(distance.max(), 0.01)
class FullTransformationTestCase(unittest.TestCase):
"""
Test that we can go from astrophysical coordinates (RA, Dec)
to pixel coordinates
"""
longMessage = True
@classmethod
def setUpClass(cls):
cls._data_dir = os.path.join(getPackageDir('sims_data'),
'FocalPlaneData',
'UnitTestData',
'FullUnitTest')
truth_name = os.path.join(cls._data_dir, 'truth_catalog.txt')
with open(truth_name, 'r') as in_file:
header = in_file.readline()
params = header.strip().split()
ra = float(params[2])
dec = float(params[4])
rotSkyPos = float(params[6])
mjd = float(params[8])
cls._obs = ObservationMetaData(pointingRA=ra,
pointingDec=dec,
rotSkyPos=rotSkyPos,
mjd=mjd)
cls._obs.site._humidity = 0.0
cls._obs.site._pressure = 0.0
assert cls._obs.site.humidity == 0.0
assert cls._obs.site.pressure == 0.0
truth_dtype = np.dtype([('id', int), ('ra', float), ('dec', float),
('pmra', float), ('pmdec', float),
('px', float), ('vrad', float)])
cls._truth_data = np.genfromtxt(truth_name, dtype=truth_dtype,
delimiter=', ')
phosim_dtype = np.dtype([('id', int), ('phot', int),
('xcam', float), ('ycam', float)])
list_of_files = os.listdir(cls._data_dir)
cls._phosim_data = {}
for file_name in list_of_files:
if 'centroid' not in file_name:
continue
full_name = os.path.join(cls._data_dir, file_name)
data = np.genfromtxt(full_name, dtype=phosim_dtype,
skip_header=1)
if len(data.shape)>0:
valid = np.where(data['phot']>0)
188 ↛ 189line 188 didn't jump to line 189, because the condition on line 188 was never true if len(valid[0]) == 0:
continue
data = data[valid]
else:
192 ↛ 193line 192 didn't jump to line 193, because the condition on line 192 was never true if data['phot'] == 0:
continue
params = file_name.split('_')
chip_name = params[5]+'_'+params[6]
filter_name = int(params[4][1])
if len(data.shape) == 0:
data_raw = data
data = {}
data['id'] = np.array([data_raw['id']])
data['phot'] = np.array([data_raw['phot']])
data['xcam'] = np.array([data_raw['xcam']])
data['ycam'] = np.array([data_raw['ycam']])
cls._phosim_data[(chip_name, 'ugrizy'[filter_name])] = data
@classmethod
def tearDownClass(cls):
clean_up_lsst_camera()
def test_chip_name_from_pupil_coords_lsst(self):
camera = lsst_camera()
x_pup, y_pup = pupilCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs)
for band in 'ugrizy':
chip_name_list = chipNameFromPupilCoordsLSST(x_pup, y_pup, band=band)
n_checked = 0
for ii in range(len(chip_name_list)):
chip_name = chip_name_list[ii]
if chip_name is None:
for kk in self._phosim_data:
if kk[1] == band:
try:
assert self._truth_data['id'][ii] not in self._phosim_data[kk]['id']
except AssertionError:
# check that source wasn't just on the edge of the chip
dex = np.where(self._phosim_data[kk]['id']==self._truth_data['id'][ii])[0]
xx = self._phosim_data[kk]['xcam'][dex]
yy = self._phosim_data[kk]['ycam'][dex]
237 ↛ 238line 237 didn't jump to line 238, because the condition on line 237 was never true if xx>10.0 and xx<3990.0 and yy>10.0 and yy<3990.0:
msg = '\nxpix: %.3f\nypix: %.3f\n' % (xx, yy)
self.assertNotIn(self._truth_data['id'][ii],
self._phosim_data[kk]['id'],
msg=msg)
continue
det = camera[chip_name]
if det.getType() != SCIENCE:
continue
n_checked += 1
chip_name = chip_name.replace(':','').replace(',','')
chip_name = chip_name.replace(' ','_')
self.assertIn(self._truth_data['id'][ii],
self._phosim_data[(chip_name, band)]['id'])
self.assertGreater(n_checked, 200)
def test_chip_name_from_pupil_coords_lsst_one_at_a_time(self):
"""
Test that chipNameFromPupilCoordsLSST works on scalars
"""
rng = np.random.RandomState(76621)
x_pup, y_pup = pupilCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs)
for band in 'ugrizy':
chip_name_list = chipNameFromPupilCoordsLSST(x_pup, y_pup, band=band)
self.assertIsInstance(chip_name_list, np.ndarray)
n_none = 0
n_not_none = 0
subsample = rng.choice(np.arange(len(chip_name_list), dtype=int),
size=50, replace=False)
for ii in subsample:
name = chipNameFromPupilCoordsLSST(x_pup[ii], y_pup[ii], band=band)
if name is not None:
self.assertIsInstance(name, str)
n_not_none += 1
else:
n_none += 1
self.assertEqual(name, chip_name_list[ii])
self.assertGreater(n_not_none, n_none//2)
def test_pupil_coords_from_ra_dec(self):
"""
Verify that pupilCoordsFromRaDec gives results consistent
with the naive pupil coordinate method used by the
Zernike fitter
"""
phosim_catalog_file = os.path.join(self._data_dir, 'phosim_catalog.txt')
ra_obs = []
dec_obs = []
unique_id = []
with open(phosim_catalog_file,'r') as input_file:
for line in input_file:
params = line.strip().split()
if params[0] != 'object':
if params[0] == 'rightascension':
ra_pointing = float(params[1])
if params[0] == 'declination':
dec_pointing = float(params[1])
305 ↛ 307line 305 didn't jump to line 307, because the condition on line 305 was never false if params[0] == 'rotskypos':
rotskypos = float(params[1])
continue
unique_id.append(int(params[1]))
ra_obs.append(float(params[2]))
dec_obs.append(float(params[3]))
unique_id = np.array(unique_id)
ra_obs = np.array(ra_obs)
dec_obs = np.array(dec_obs)
x_pup, y_pup = _rawPupilCoordsFromObserved(np.radians(ra_obs),
np.radians(dec_obs),
np.radians(ra_pointing),
np.radians(dec_pointing),
np.radians(rotskypos))
sorted_dex = np.argsort(unique_id)
unique_id = unique_id[sorted_dex]
x_pup = x_pup[sorted_dex]
y_pup = y_pup[sorted_dex]
(x_pup_test,
y_pup_test) = pupilCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs)
sorted_dex = np.argsort(self._truth_data['id'])
truth_id = self._truth_data['id'][sorted_dex]
x_pup_test = x_pup_test[sorted_dex]
y_pup_test = y_pup_test[sorted_dex]
np.testing.assert_array_equal(unique_id, truth_id)
distance = np.sqrt((x_pup-x_pup_test)**2 +
(y_pup-y_pup_test)**2)
self.assertLess(distance.max(), 1.0e-12)
def test_focal_coords_from_pupil_coords(self):
"""
Test that using pupilCoordsFromRaDec and
focalPlaneCoordsFromPupilCoordsLSST gives answers
consistent with PhoSim
"""
camera = lsst_camera()
pix_transformer = DMtoCameraPixelTransformer()
x_pup, y_pup = pupilCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs)
(xf_no_optics,
yf_no_optics) = focalPlaneCoordsFromPupilCoords(x_pup,
y_pup, camera=lsst_camera())
for band in 'ugrizy':
n_check = 0
d_max = None
n_old_better = 0
n_new_better = 0
(xf_optics,
yf_optics) = focalPlaneCoordsFromPupilCoordsLSST(x_pup, y_pup, band)
for det in camera:
if det.getType() != SCIENCE:
continue
det_name = det.getName()
name = det_name.replace(':','').replace(',','').replace(' ','_')
key_tuple = (name, band)
if key_tuple not in self._phosim_data:
continue
phosim_data = self._phosim_data[key_tuple]
pixel_to_focal = det.getTransform(PIXELS, FOCAL_PLANE)
(xdm_arr,
ydm_arr) = pix_transformer.dmPixFromCameraPix(phosim_data['xcam'],
phosim_data['ycam'],
det_name)
for id_val, xdm, ydm in zip(phosim_data['id'],xdm_arr, ydm_arr):
dex = np.where(self._truth_data['id'] == id_val)
xf = xf_optics[dex]
yf = yf_optics[dex]
pixel_pt = afwGeom.Point2D(xdm, ydm)
focal_pt = pixel_to_focal.applyForward(pixel_pt)
dist = np.sqrt((xf-focal_pt.getX())**2+(yf-focal_pt.getY())**2)
r_center = np.sqrt(focal_pt.getX()**2 + focal_pt.getY()**2)
old_dist = np.sqrt((xf_no_optics[dex]-focal_pt.getX())**2 +
(yf_no_optics[dex]-focal_pt.getY())**2)
msg = '\nObject %d' % id_val
msg += '\nchip %s' % det_name
msg += '\nband %s' % band
msg += '\ndistance from center: %.4e' % r_center
msg += '\nPupil: %.4e %.4e' % (x_pup[dex], y_pup[dex])
msg += '\nPhosim: %.4f %.4f' % (focal_pt.getX(),focal_pt.getY())
msg += '\nCatSim: %.4f %.4f'% (xf, yf)
msg += '\nPixels: %.4f %.4f' % (xdm, ydm)
msg += '\nnew dist %.4e old_dist %.4e' % (dist, old_dist)
if dist<old_dist:
n_new_better += 1
else:
n_old_better += 1
# Near the center of the focal plane, the old transformation
# with no filter-dependence is actually better, but neither
# is off by more than a pixel
#
# It also occasionally happens that the old transformation
# was slightly better at the very edge of the focal plane
# (in some filters)
if old_dist<dist:
if r_center < 100.0:
# if we in the heart of the focal plane, make
# sure that the fit has not degraded by more
# than half a pixel and that the difference
# between CatSim and PhoSim is still less
# than a pixel
self.assertLess(dist-old_dist, 0.005, msg=msg)
self.assertLess(dist, 0.01, msg=msg)
else:
# if we are near the edge of the focal plane,
# make sure that the difference between
# CatSim and PhoSim is less than 2 pixels
self.assertLess(dist, 0.02, msg=msg)
else:
if r_center < 100.0:
# if we are in the heart of the focal plane,
# make sure that the difference between
# CatSim and PhoSim is less than a pixel
self.assertLess(dist, 0.01, msg=msg)
else:
# If we are at the edge of the focal plane,
# make sure that the difference between
# CatSim and PhoSim is less than five pixels,
# and if the difference is less than 2 pixels,
# make sure that the difference under the old
# transformation is more than 15 pixels (indicating
# that we are in a difficult-to-fit part of the
# focal plane)
self.assertLess(dist, 0.05, msg=msg)
if dist > 0.02:
self.assertGreater(old_dist, 0.15, msg=msg)
n_check += 1
self.assertGreater(n_check, 200)
self.assertGreater(n_new_better, 4*n_old_better)
def test_focal_coords_from_pupil_coords_vectorized(self):
"""
Test that focalPlaneCoordsFromPupilCoordsLSST acting
on numpy arrays gives the same result as acting on
scalars
"""
rng = np.random.RandomState(192312)
camera = lsst_camera()
pix_transformer = DMtoCameraPixelTransformer()
x_pup, y_pup = pupilCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs)
for band in 'ugrizy':
x_f, y_f = focalPlaneCoordsFromPupilCoordsLSST(x_pup,
y_pup,
band=band)
subsample = rng.choice(np.arange(len(x_pup), dtype=int),
size=50, replace=False)
for ii in subsample:
x_f1, y_f1 = focalPlaneCoordsFromPupilCoordsLSST(x_pup[ii],
y_pup[ii],
band=band)
self.assertIsInstance(x_f1, numbers.Number)
self.assertIsInstance(y_f1, numbers.Number)
self.assertAlmostEqual(x_f1, x_f[ii], 8)
self.assertAlmostEqual(y_f1, y_f[ii], 8)
def test_pixel_coords_from_ra_dec(self):
"""
Test that pixelCoordsFromRaDecLSST() works correctly
"""
pix_transformer = DMtoCameraPixelTransformer()
x_pup, y_pup = pupilCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs)
(x_pix_no_optics,
y_pix_no_optics) = pixelCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
camera=lsst_camera())
for band in 'ugrizy':
x_pix, y_pix = pixelCoordsFromRaDecLSST(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
(x_f,
y_f) = focalPlaneCoordsFromPupilCoordsLSST(x_pup, y_pup, band=band)
r_center = np.sqrt(x_f**2 + y_f**2)
n_check = 0
n_diff_chip = 0
n_old_better = 0
n_new_better = 0
dist_arr = []
for det in lsst_camera():
if det.getType() != SCIENCE:
continue
det_name = det.getName()
name = det_name.replace(':','').replace(',','').replace(' ','_')
key_tuple = (name, band)
if key_tuple not in self._phosim_data:
continue
phosim_data = self._phosim_data[key_tuple]
for id_val, xcam, ycam in zip(phosim_data['id'],
phosim_data['xcam'],
phosim_data['ycam']):
dex = np.where(self._truth_data['id'] == id_val)
self.assertEqual(len(dex[0]), 1)
dex = dex[0][0]
x_pix_val = x_pix[dex]
y_pix_val = y_pix[dex]
if np.isnan(x_pix_val):
# PhoSim centroid files will report flux from bright
# stars that spill over onto neighboring chips. In
# this case, CatSim will report chipName=None and
# xpix=ypix=Nan. In these cases, we will force
# CatSim to calculate the pixel coordinates of the
# object on the chip that PhoSim is reporting and
# compare that result to the contents of the PhoSim
# centroid file.
#
n_diff_chip += 1
(x_pix_val,
y_pix_val) = pixelCoordsFromRaDecLSST(self._truth_data['ra'][dex],
self._truth_data['dec'][dex],
chipName = det_name,
pm_ra=self._truth_data['pmra'][dex],
pm_dec=self._truth_data['pmdec'][dex],
parallax=self._truth_data['px'][dex],
v_rad=self._truth_data['vrad'][dex],
obs_metadata=self._obs,
band=band)
self.assertIsInstance(x_pix_val, np.float)
self.assertIsInstance(y_pix_val, np.float)
x_pix_no_optics_val = x_pix_no_optics[dex]
y_pix_no_optics_val = y_pix_no_optics[dex]
if np.isnan(x_pix_no_optics_val):
x, y = pixelCoordsFromRaDec(self._truth_data['ra'][dex],
self._truth_data['dec'][dex],
chipName = det_name,
pm_ra=self._truth_data['pmra'][dex],
pm_dec=self._truth_data['pmdec'][dex],
parallax=self._truth_data['px'][dex],
v_rad=self._truth_data['vrad'][dex],
obs_metadata=self._obs,
camera=lsst_camera())
x_pix_no_optics_val = x
y_pix_no_optics_val = y
self.assertIsInstance(x_pix_no_optics_val, np.float)
self.assertIsInstance(y_pix_no_optics_val, np.float)
x_dm, y_dm = pix_transformer.dmPixFromCameraPix(xcam, ycam, det_name)
dd = np.sqrt((x_dm-x_pix_val)**2 + (y_dm-y_pix_val)**2)
dist_arr.append(dd)
dd_no_optics = np.sqrt((x_dm-x_pix_no_optics_val)**2 +
(y_dm-y_pix_no_optics_val)**2)
msg = '\nObject %d; chip %s' % (id_val, det_name)
msg += '\nband %s' % band
msg += '\ndist from center %.4e pixels' % (r_center[dex]/0.01)
msg += '\nPupil: %.4e %.4e' % (x_pup[dex], x_pup[dex])
msg += '\nPhoSim: %.4f %.4f' % (x_dm, y_dm)
msg += '\nCatSim: %.4f %.4f -- %.4e' % (x_pix_val, y_pix_val, dd)
msg += '\nno Optics: %.4f %.4f -- %.4e' % (x_pix_no_optics_val,
y_pix_no_optics_val,
dd_no_optics)
if dd<dd_no_optics:
n_new_better += 1
else:
n_old_better += 1
# Near the center of the focal plane, the old transformation
# with no filter-dependence is actually better, but neither
# is off by more than a pixel
#
# It also occasionally happens that the old transformation
# was slightly better at the very edge of the focal plane
# (in some filters)
if dd_no_optics<dd:
if r_center[dex] < 100.0:
# if we in the heart of the focal plane, make
# sure that the fit has not degraded by more
# than half a pixel and that the difference
# between CatSim and PhoSim is still less
# than a pixel
self.assertLess(dd-dd_no_optics, 5.0, msg=msg)
self.assertLess(dd, 1.0, msg=msg)
else:
# if we are near the edge of the focal plane,
# make sure that the difference between
# CatSim and PhoSim is less than 2 pixels
self.assertLess(dd, 2.0, msg=msg)
else:
if r_center[dex] < 100.0:
# if we are in the heart of the focal plane,
# make sure that the difference between
# CatSim and PhoSim is less than a pixel
self.assertLess(dd, 1.0, msg=msg)
else:
# If we are at the edge of the focal plane,
# make sure that the difference between
# CatSim and PhoSim is less than five pixels,
# and if the difference is less than 2 pixels,
# make sure that the difference under the old
# transformation is more than 15 pixels (indicating
# that we are in a difficult-to-fit part of the
# focal plane)
self.assertLess(dd, 5.0, msg=msg)
if dd > 2.0:
self.assertGreater(dd_no_optics, 15.0, msg=msg)
n_check += 1
if dd > 1.0:
if dd_no_optics>15.0:
self.assertLess(dd, 5.0, msg=msg)
else:
self.assertLess(dd, 2.0, msg=msg)
self.assertGreater(n_check, 200)
self.assertLess(n_diff_chip, n_check//2)
self.assertGreater(n_new_better, 4*n_old_better)
dist_arr = np.array(dist_arr)
dist_arr = np.sort(dist_arr)
def test_pixel_coords_from_ra_dec_one_at_a_time(self):
"""
Test that pixelCoordsFromRaDecLSST works correctly on
scalars
"""
rng = np.random.RandomState(1845332)
for band in 'ugrizy':
x_pix, y_pix = pixelCoordsFromRaDecLSST(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
self.assertIsInstance(x_pix, np.ndarray)
self.assertIsInstance(y_pix, np.ndarray)
n_nan = 0
n_good = 0
subsample = rng.choice(np.arange(len(x_pix), dtype=int),
size=50, replace=False)
for ii in subsample: # only test on a subsample; this is slow
x_pix1, y_pix1 = pixelCoordsFromRaDecLSST(self._truth_data['ra'][ii],
self._truth_data['dec'][ii],
pm_ra=self._truth_data['pmra'][ii],
pm_dec=self._truth_data['pmdec'][ii],
parallax=self._truth_data['px'][ii],
v_rad=self._truth_data['vrad'][ii],
obs_metadata=self._obs,
band=band)
self.assertIsInstance(x_pix1, numbers.Number)
self.assertIsInstance(y_pix1, numbers.Number)
if not np.isnan(x_pix1):
self.assertAlmostEqual(x_pix1, x_pix[ii], 8)
self.assertAlmostEqual(y_pix1, y_pix[ii], 8)
n_good += 1
else:
n_nan += 1
self.assertLess(n_nan, n_good//2)
def test_pupil_coords_from_focal_plane_coords_LSST(self):
"""
Test that pupilCoordsFromFocalPlaneCoordsLSST inverts
focalPlaneCoordsFromPupilCoordsLSST
"""
x_f = np.arange(-317.0, 317.0, 20.0)
y_f = np.arange(-317.0, 317.0, 20.0)
mesh = np.meshgrid(x_f, y_f)
x_f = mesh[0].flatten()
y_f = mesh[1].flatten()
for band in 'ugrizy':
x_p, y_p = pupilCoordsFromFocalPlaneCoordsLSST(x_f, y_f, band=band)
x_f1, y_f1 = focalPlaneCoordsFromPupilCoordsLSST(x_p, y_p,
band=band)
dd = np.sqrt((x_f-x_f1)**2 + (y_f-y_f1)**2)
self.assertLess(dd.max(), 3.0e-6)
def test_pupil_coords_from_focal_plane_coords_LSST_one_at_a_time(self):
"""
Test that pupilCoordsFromFocalPlaneCoordsLSST works on scalars
"""
rng = np.random.RandomState(8123412)
x_f = np.arange(-317.0, 317.0, 20.0)
y_f = np.arange(-317.0, 317.0, 20.0)
mesh = np.meshgrid(x_f, y_f)
x_f = mesh[0].flatten()
y_f = mesh[1].flatten()
for band in 'ugrizy':
x_p, y_p = pupilCoordsFromFocalPlaneCoordsLSST(x_f, y_f, band=band)
self.assertIsInstance(x_p, np.ndarray)
self.assertIsInstance(y_p, np.ndarray)
subsample = rng.choice(np.arange(len(x_p), dtype=int),
size=50, replace=False)
for ii in subsample:
x_p1, y_p1 = pupilCoordsFromFocalPlaneCoordsLSST(x_f[ii], y_f[ii],
band=band)
self.assertIsInstance(x_p1, numbers.Number)
self.assertIsInstance(y_p1, numbers.Number)
self.assertAlmostEqual(x_p1, x_p[ii], 16)
self.assertAlmostEqual(y_p1, y_p[ii], 16)
def test_chip_name_from_ra_dec_lsst(self):
"""
Test that chipNameFromRaDecLSST is consistent with
chipNameFromPupilCoordsLSST
"""
x_pup, y_pup = pupilCoordsFromRaDec(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs)
for band in 'ugrizy':
chip_name_list = chipNameFromPupilCoordsLSST(x_pup, y_pup, band=band)
chip_name_list_1 = chipNameFromRaDecLSST(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
np.testing.assert_array_equal(chip_name_list, chip_name_list_1)
n_none = np.where(np.char.find(chip_name_list.astype(str), 'None')==0)
self.assertLess(len(n_none[0]), len(chip_name_list)//4)
def test_chip_name_from_ra_dec_lsst_one_at_a_time(self):
"""
Test that chipNameFromRaDecLSST works on scalars
"""
rng = np.random.RandomState(65673)
for band in 'ugrizy':
chip_name_list = chipNameFromRaDecLSST(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
self.assertIsInstance(chip_name_list, np.ndarray)
n_none = 0
n_not_none = 0
subsample = rng.choice(np.arange(len(chip_name_list), dtype=int),
size=50, replace=False)
for ii in subsample:
name = chipNameFromRaDecLSST(self._truth_data['ra'][ii],
self._truth_data['dec'][ii],
pm_ra=self._truth_data['pmra'][ii],
pm_dec=self._truth_data['pmdec'][ii],
parallax=self._truth_data['px'][ii],
v_rad=self._truth_data['vrad'][ii],
obs_metadata=self._obs,
band=band)
if name is not None:
n_not_none += 1
self.assertIsInstance(name, str)
else:
n_none += 1
self.assertEqual(name, chip_name_list[ii])
self.assertGreater(n_not_none, n_none//2)
def test_radians(self):
"""
Test the radians versions of pixelCoordsFromRaDecLSST and
chipNameFromRaDecLSST
"""
for band in 'ugrizy':
x_pix, y_pix = pixelCoordsFromRaDecLSST(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
(x_pix_r,
y_pix_r) = _pixelCoordsFromRaDecLSST(np.radians(self._truth_data['ra']),
np.radians(self._truth_data['dec']),
pm_ra=radiansFromArcsec(self._truth_data['pmra']),
pm_dec=radiansFromArcsec(self._truth_data['pmdec']),
parallax=radiansFromArcsec(self._truth_data['px']),
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
np.testing.assert_array_equal(x_pix, x_pix_r)
np.testing.assert_array_equal(y_pix, y_pix_r)
chip_name_list = chipNameFromRaDecLSST(self._truth_data['ra'],
self._truth_data['dec'],
pm_ra=self._truth_data['pmra'],
pm_dec=self._truth_data['pmdec'],
parallax=self._truth_data['px'],
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
chip_name_list_r = _chipNameFromRaDecLSST(np.radians(self._truth_data['ra']),
np.radians(self._truth_data['dec']),
pm_ra=radiansFromArcsec(self._truth_data['pmra']),
pm_dec=radiansFromArcsec(self._truth_data['pmdec']),
parallax=radiansFromArcsec(self._truth_data['px']),
v_rad=self._truth_data['vrad'],
obs_metadata=self._obs,
band=band)
np.testing.assert_array_equal(chip_name_list, chip_name_list_r)
def test_pupil_coords_from_pixel_coords_LSST(self):
"""
Test that pupilCoordsFromPixelCoordsLSST inverts
pixelCoordsFromPupilCoordsLSST
"""
xpix = np.arange(-2000.0, 2000.0, 100.0)
ypix = np.arange(-2000.0, 2000.0, 100.0)
mesh = np.meshgrid(xpix, ypix)
xpix = mesh[0].flatten()
ypix = mesh[1].flatten()
chip_name = 'R:3,1 S:1,2'
chip_name_list = ['None']
for det in lsst_camera():
if det.getType() == SCIENCE:
chip_name_list.append(det.getName())
chip_name_list = np.array(chip_name_list)
rng = np.random.RandomState(81231)
chip_name_sample = rng.choice(chip_name_list, size=len(xpix),
replace=True)
for band in 'ugrizy':
xpup, ypup = pupilCoordsFromPixelCoordsLSST(xpix, ypix,
chipName=chip_name,
band=band)
xpix1, ypix1 = pixelCoordsFromPupilCoordsLSST(xpup, ypup,
chipName=chip_name,
band=band)
dd = np.sqrt((xpix-xpix1)**2 + (ypix-ypix1)**2)
self.assertLess(dd.max(), 1.0e-4)
xpup, ypup = pupilCoordsFromPixelCoordsLSST(xpix, ypix,
chipName=chip_name_sample,
band=band)
xpix1, ypix1 = pixelCoordsFromPupilCoordsLSST(xpup, ypup,
chipName=chip_name_sample,
band=band)
valid = np.where(np.char.find(chip_name_sample, 'None')<0)
self.assertGreater(len(valid[0]), 0)
self.assertLess(len(valid[0]), len(xpix))
dd = np.sqrt((xpix[valid]-xpix1[valid])**2 + (ypix[valid]-ypix1[valid])**2)
self.assertLess(dd.max(), 1.0e-4)
for dist in dd:
self.assertFalse(np.isnan(dist))
invalid = np.where(np.char.find(chip_name_sample, 'None')==0)
for ii in invalid[0]:
self.assertTrue(np.isnan(xpix1[ii]))
self.assertTrue(np.isnan(ypix1[ii]))
def test_ra_dec_from_pixel_coords_lsst(self):
"""
Test that raDecFromPixelCoordsLSST inverts
pixelCoordsFromRaDecLSST
"""
rng = np.random.RandomState(1811231)
n_samples = 500
rr = rng.random_sample(n_samples)*2.2
theta = rng.random_sample(n_samples)*2.0*np.pi
ra = self._obs.pointingRA + rr*np.cos(theta)
dec = self._obs.pointingDec + rr*np.sin(theta)
name_list = [None]
for det in lsst_camera():
if det.getType() == SCIENCE:
name_list.append(det.getName())
name_list = np.array(name_list)
name_sample = rng.choice(name_list, size=n_samples, replace=True)
for band in 'ugrizy':
xpix, ypix = pixelCoordsFromRaDecLSST(ra, dec,
chipName=name_sample,
band=band,
obs_metadata=self._obs)
ra1, dec1 = raDecFromPixelCoordsLSST(xpix, ypix, chipName=name_sample,
band=band,
obs_metadata=self._obs)
valid = np.where(np.isfinite(ra1))
valid_name = np.where(np.char.find(name_sample.astype(str), 'None')<0)
np.testing.assert_array_equal(valid[0], valid_name[0])
invalid = np.where(np.isnan(ra1))
invalid_name = np.where(np.char.find(name_sample.astype(str), 'None')==0)
np.testing.assert_array_equal(invalid[0], invalid_name[0])
self.assertGreater(len(invalid[0]), 0)
self.assertGreater(len(valid[0]), 0)
dist = angularSeparation(ra[valid], dec[valid], ra1[valid], dec1[valid])
dist *= 3600.0
self.assertLess(dist.max(), 1.0e-5)
# test one at a time
for ii in range(len(ra1)):
ra2, dec2 = raDecFromPixelCoordsLSST(xpix[ii], ypix[ii],
chipName=str(name_sample[ii]),
band=band,
obs_metadata=self._obs)
self.assertIsInstance(ra2, numbers.Number)
self.assertIsInstance(dec2, numbers.Number)
if name_sample[ii] is None:
self.assertTrue(np.isnan(ra2))
self.assertTrue(np.isnan(dec2))
else:
self.assertEqual(ra2, ra1[ii])
self.assertEqual(dec2, dec1[ii])
def test_ra_dec_from_pixel_coords_lsst_radians(self):
"""
Test that radians version of raDecFromPixelCoordsLSST
agrees with degrees version
"""
rng = np.random.RandomState(56123)
n_samples = 500
name_list = [None]
for det in lsst_camera():
if det.getType() == SCIENCE:
name_list.append(det.getName())
name_list = np.array(name_list)
name_sample = rng.choice(name_list, size=n_samples, replace=True)
invalid = np.where(np.char.find(name_sample.astype(str), 'None')==0)
self.assertLess(len(invalid[0]), n_samples//2)
xpix = rng.random_sample(n_samples)*4000.0
ypix = rng.random_sample(n_samples)*4000.0
for band in 'ugrizy':
ra_deg, dec_deg = raDecFromPixelCoordsLSST(xpix, ypix, chipName=name_sample,
obs_metadata=self._obs)
ra_rad, dec_rad = _raDecFromPixelCoordsLSST(xpix, ypix, chipName=name_sample,
obs_metadata=self._obs)
valid = np.where(np.isfinite(ra_deg))
np.testing.assert_array_equal(np.degrees(ra_rad[valid]), ra_deg[valid])
np.testing.assert_array_equal(np.degrees(dec_rad[valid]), dec_deg[valid])
self.assertGreater(len(valid[0]), n_samples//2)
for ii in invalid[0]:
self.assertTrue(np.isnan(ra_rad[ii]))
self.assertTrue(np.isnan(dec_rad[ii]))
for ii in range(n_samples):
ra1, dec1 = _raDecFromPixelCoordsLSST(xpix[ii], ypix[ii],
chipName=str(name_sample[ii]),
obs_metadata=self._obs)
self.assertIsInstance(ra1, numbers.Number)
self.assertIsInstance(dec1, numbers.Number)
if name_sample[ii] is None:
self.assertTrue(np.isnan(ra1))
self.assertTrue(np.isnan(dec1))
else:
self.assertEqual(ra1, ra_rad[ii])
self.assertEqual(dec1, dec_rad[ii])
def test_nans(self):
"""
Test that points outside the focal plane get NaNs for pupil
and focal plane coords
"""
rng = np.random.RandomState(66)
n_samples = 100
rr = rng.random_sample(n_samples)*600.0
theta = rng.random_sample(n_samples)*2.0*np.pi
self.assertGreater(rr.max(), 500.0)
xf = rr*np.cos(theta)
yf = rr*np.sin(theta)
xp, yp = pupilCoordsFromFocalPlaneCoordsLSST(xf, yf, band='g')
name_list = chipNameFromPupilCoordsLSST(xp, yp, band='g')
xpix, ypix = pixelCoordsFromPupilCoordsLSST(xp, yp,
chipName='R:2,2 S:1,1',
band='g')
ra, dec = raDecFromPixelCoordsLSST(xpix, ypix, 'R:2,2 S:1,1',
obs_metadata=self._obs,
band='g')
xpix2, ypix2 = pixelCoordsFromPupilCoordsLSST(xp, yp,
band='g')
invalid = np.where(rr>500.0)[0]
self.assertGreater(len(invalid), 0)
self.assertLess(len(invalid), n_samples)
non_nan_pix = 0
non_none_name = 0
for ii in range(n_samples):
if ii in invalid:
self.assertTrue(np.isnan(xp[ii]))
self.assertTrue(np.isnan(yp[ii]))
self.assertTrue(np.isnan(xpix[ii]))
self.assertTrue(np.isnan(ypix[ii]))
self.assertTrue(np.isnan(xpix2[ii]))
self.assertTrue(np.isnan(ypix2[ii]))
self.assertTrue(np.isnan(ra[ii]))
self.assertTrue(np.isnan(dec[ii]))
self.assertIsNone(name_list[ii])
else:
self.assertFalse(np.isnan(xp[ii]))
self.assertFalse(np.isnan(yp[ii]))
self.assertFalse(np.isnan(xpix[ii]))
self.assertFalse(np.isnan(ypix[ii]))
self.assertFalse(np.isnan(ra[ii]))
self.assertFalse(np.isnan(dec[ii]))
# this test is because, even if an object
# has finite pupil or focal plane coordinates,
# it could still land in a chip gap, causing
# chip_name=None, xpix=ypix=NaN
if not np.isnan(xpix2[ii]) and not np.isnan(ypix2[ii]):
non_nan_pix += 1
if name_list[ii] is not None:
non_none_name += 1
self.assertGreater(non_nan_pix, 0)
self.assertGreater(non_none_name, 0)
rr = rng.random_sample(n_samples)*0.05
xp = rr*np.cos(theta)
yp = rr*np.sin(theta)
xf2, yf2 = focalPlaneCoordsFromPupilCoordsLSST(xp, yp, band='i')
xpix, ypix = pixelCoordsFromPupilCoordsLSST(xp, yp, chipName='R:2,2 S:1,1',
band='i')
ra, dec = raDecFromPixelCoordsLSST(xpix, ypix, 'R:2,2 S:1,1',
obs_metadata=self._obs,
band='i')
xpix2, ypix2 = pixelCoordsFromPupilCoordsLSST(xp, yp,
band='g')
invalid = np.where(rr>0.04841)[0]
self.assertGreater(len(invalid), 0)
self.assertLess(len(invalid), n_samples)
non_nan_pix = 0
for ii in range(n_samples):
if ii in invalid:
self.assertTrue(np.isnan(xf2[ii]))
self.assertTrue(np.isnan(yf2[ii]))
self.assertTrue(np.isnan(xpix[ii]))
self.assertTrue(np.isnan(ypix[ii]))
self.assertTrue(np.isnan(xpix2[ii]))
self.assertTrue(np.isnan(ypix2[ii]))
self.assertTrue(np.isnan(ra[ii]))
self.assertTrue(np.isnan(dec[ii]))
else:
self.assertFalse(np.isnan(xf2[ii]))
self.assertFalse(np.isnan(yf2[ii]))
self.assertFalse(np.isnan(xpix[ii]))
self.assertFalse(np.isnan(ypix[ii]))
self.assertFalse(np.isnan(ra[ii]))
self.assertFalse(np.isnan(dec[ii]))
# this test is because, even if an object
# has finite pupil or focal plane coordinates,
# it could still land in a chip gap, causing
# chip_name=None, xpix=ypix=NaN
if not np.isnan(xpix2[ii]) and not np.isnan(ypix2[ii]):
non_nan_pix += 1
self.assertGreater(non_nan_pix, 0)
xf = np.array([1.1, 2.1, np.NaN, 4.5])
yf = np.array([2.1, np.NaN, 1.2, 3.0])
xp, yp = pupilCoordsFromFocalPlaneCoordsLSST(xf, yf, band='r')
self.assertTrue(np.isnan(xp[2]))
self.assertTrue(np.isnan(yp[2]))
self.assertTrue(np.isnan(xp[1]))
self.assertTrue(np.isnan(yp[1]))
self.assertFalse(np.isnan(xp[0]))
self.assertFalse(np.isnan(yp[0]))
self.assertFalse(np.isnan(xp[3]))
self.assertFalse(np.isnan(yp[3]))
xp, yp = pupilCoordsFromFocalPlaneCoordsLSST(np.NaN, 1.0, band='g')
self.assertTrue(np.isnan(xp))
self.assertTrue(np.isnan(yp))
xp, yp = pupilCoordsFromFocalPlaneCoordsLSST(2.1, np.NaN, band='g')
self.assertTrue(np.isnan(xp))
self.assertTrue(np.isnan(yp))
xp = np.array([0.0011, 0.0021, np.NaN, 0.0045])
yp = np.array([0.0021, np.NaN, 0.0012, 0.0030])
xf, yf = focalPlaneCoordsFromPupilCoordsLSST(xp, yp, band='r')
self.assertTrue(np.isnan(xf[2]))
self.assertTrue(np.isnan(yf[2]))
self.assertTrue(np.isnan(xf[1]))
self.assertTrue(np.isnan(yf[1]))
self.assertFalse(np.isnan(xf[0]))
self.assertFalse(np.isnan(yf[0]))
self.assertFalse(np.isnan(xf[3]))
self.assertFalse(np.isnan(yf[3]))
xf, yf = focalPlaneCoordsFromPupilCoordsLSST(np.NaN, 0.001, band='g')
self.assertTrue(np.isnan(xf))
self.assertTrue(np.isnan(yf))
xf, yf = pupilCoordsFromFocalPlaneCoordsLSST(0.002, np.NaN, band='g')
self.assertTrue(np.isnan(xf))
self.assertTrue(np.isnan(yf))
class MemoryTestClass(lsst.utils.tests.MemoryTestCase):
pass
1216 ↛ 1217line 1216 didn't jump to line 1217, because the condition on line 1216 was never trueif __name__ == "__main__":
lsst.utils.tests.init()
unittest.main()
|