Coverage for tests/test_functors.py : 14%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# This file is part of pipe_tasks.
2#
3# Developed for the LSST Data Management System.
4# This product includes software developed by the LSST Project
5# (http://www.lsst.org).
6# See the COPYRIGHT file at the top-level directory of this distribution
7# for details of code ownership.
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 3 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
22import astropy.units as u
23import copy
24import functools
25import numpy as np
26import os
27import pandas as pd
28import unittest
29import tempfile
30import shutil
32import lsst.daf.base as dafBase
33import lsst.afw.geom as afwGeom
34import lsst.geom as geom
35from lsst.sphgeom import HtmPixelization
36import lsst.meas.base as measBase
37import lsst.utils.tests
38from lsst.pipe.tasks.parquetTable import MultilevelParquetTable
39from lsst.daf.butler import Butler, DatasetType
40from lsst.pipe.tasks.functors import (CompositeFunctor, CustomFunctor, Column, RAColumn,
41 DecColumn, Mag, MagDiff, Color, StarGalaxyLabeller,
42 DeconvolvedMoments, SdssTraceSize, PsfSdssTraceSizeDiff,
43 HsmTraceSize, PsfHsmTraceSizeDiff, HsmFwhm,
44 LocalPhotometry, LocalNanojansky, LocalNanojanskyErr,
45 LocalMagnitude, LocalMagnitudeErr,
46 LocalWcs, ComputePixelScale, ConvertPixelToArcseconds)
48ROOT = os.path.abspath(os.path.dirname(__file__))
51class FunctorTestCase(unittest.TestCase):
53 def simulateMultiParquet(self, dataDict):
54 """Create a simple test MultilevelParquetTable
55 """
56 simpleDF = pd.DataFrame(dataDict)
57 dfFilterDSCombos = []
58 for ds in self.datasets:
59 for filterName in self.filters:
60 df = copy.copy(simpleDF)
61 df.reindex(sorted(df.columns), axis=1)
62 df['dataset'] = ds
63 df['filter'] = filterName
64 df.columns = pd.MultiIndex.from_tuples(
65 [(ds, filterName, c) for c in df.columns],
66 names=('dataset', 'filter', 'column'))
67 dfFilterDSCombos.append(df)
69 df = functools.reduce(lambda d1, d2: d1.join(d2), dfFilterDSCombos)
71 return MultilevelParquetTable(dataFrame=df)
73 def getDatasetHandle(self, parq):
74 df = parq._df
75 lo, hi = HtmPixelization(7).universe().ranges()[0]
76 value = np.random.randint(lo, hi)
77 ref = self.butler.put(df, self.datasetType, dataId={'htm7': value})
78 return self.butler.getDeferred(ref)
80 def setUp(self):
81 np.random.seed(1234)
82 self.datasets = ['forced_src', 'meas', 'ref']
83 self.filters = ['HSC-G', 'HSC-R']
84 self.columns = ['coord_ra', 'coord_dec']
85 self.nRecords = 5
86 self.dataDict = {
87 "coord_ra": [3.77654137, 3.77643059, 3.77621148, 3.77611944, 3.77610396],
88 "coord_dec": [0.01127624, 0.01127787, 0.01127543, 0.01127543, 0.01127543]}
90 # Set up butler
91 self.root = tempfile.mkdtemp(dir=ROOT)
92 Butler.makeRepo(self.root)
93 self.butler = Butler(self.root, run="test_run")
94 self.datasetType = DatasetType("data", dimensions=('htm7',), storageClass="DataFrame",
95 universe=self.butler.registry.dimensions)
96 self.butler.registry.registerDatasetType(self.datasetType)
98 def tearDown(self):
99 if os.path.exists(self.root):
100 shutil.rmtree(self.root, ignore_errors=True)
102 def _funcVal(self, functor, parq):
103 self.assertIsInstance(functor.name, str)
104 self.assertIsInstance(functor.shortname, str)
106 handle = self.getDatasetHandle(parq)
108 val = functor(parq)
109 val2 = functor(handle)
110 self.assertTrue((val == val2).all())
111 self.assertIsInstance(val, pd.Series)
113 val = functor(parq, dropna=True)
114 val2 = functor(handle, dropna=True)
115 self.assertTrue((val == val2).all())
116 self.assertEqual(val.isnull().sum(), 0)
118 return val
120 def _differenceVal(self, functor, parq1, parq2):
121 self.assertIsInstance(functor.name, str)
122 self.assertIsInstance(functor.shortname, str)
124 handle1 = self.getDatasetHandle(parq1)
125 handle2 = self.getDatasetHandle(parq2)
127 val = functor.difference(parq1, parq2)
128 val2 = functor.difference(handle1, handle2)
129 self.assertTrue(val.equals(val2))
130 self.assertIsInstance(val, pd.Series)
132 val = functor.difference(parq1, parq2, dropna=True)
133 val2 = functor.difference(handle1, handle2, dropna=True)
134 self.assertTrue(val.equals(val2))
135 self.assertEqual(val.isnull().sum(), 0)
137 val1 = self._funcVal(functor, parq1)
138 val2 = self._funcVal(functor, parq2)
140 self.assertTrue(np.allclose(val, val1 - val2))
142 return val
144 def testColumn(self):
145 self.columns.append("base_FootprintArea_value")
146 self.dataDict["base_FootprintArea_value"] = \
147 np.full(self.nRecords, 1)
148 parq = self.simulateMultiParquet(self.dataDict)
149 func = Column('base_FootprintArea_value', filt='HSC-G')
150 self._funcVal(func, parq)
152 def testCustom(self):
153 self.columns.append("base_FootprintArea_value")
154 self.dataDict["base_FootprintArea_value"] = \
155 np.random.rand(self.nRecords)
156 parq = self.simulateMultiParquet(self.dataDict)
157 func = CustomFunctor('2*base_FootprintArea_value', filt='HSC-G')
158 val = self._funcVal(func, parq)
160 func2 = Column('base_FootprintArea_value', filt='HSC-G')
162 np.allclose(val.values, 2*func2(parq).values, atol=1e-13, rtol=0)
164 def testCoords(self):
165 parq = self.simulateMultiParquet(self.dataDict)
166 ra = self._funcVal(RAColumn(), parq)
167 dec = self._funcVal(DecColumn(), parq)
169 columnDict = {'dataset': 'ref', 'filter': 'HSC-G',
170 'column': ['coord_ra', 'coord_dec']}
171 coords = parq.toDataFrame(columns=columnDict, droplevels=True) / np.pi * 180.
173 self.assertTrue(np.allclose(ra, coords[('ref', 'HSC-G', 'coord_ra')], atol=1e-13, rtol=0))
174 self.assertTrue(np.allclose(dec, coords[('ref', 'HSC-G', 'coord_dec')], atol=1e-13, rtol=0))
176 def testMag(self):
177 self.columns.extend(["base_PsfFlux_instFlux", "base_PsfFlux_instFluxErr"])
178 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 1000)
179 self.dataDict["base_PsfFlux_instFluxErr"] = np.full(self.nRecords, 10)
180 parq = self.simulateMultiParquet(self.dataDict)
181 # Change one dataset filter combinations value.
182 parq._df[("meas", "HSC-G", "base_PsfFlux_instFlux")] -= 1
184 fluxName = 'base_PsfFlux'
186 # Check that things work when you provide dataset explicitly
187 for dataset in ['forced_src', 'meas']:
188 psfMag_G = self._funcVal(Mag(fluxName, dataset=dataset,
189 filt='HSC-G'),
190 parq)
191 psfMag_R = self._funcVal(Mag(fluxName, dataset=dataset,
192 filt='HSC-R'),
193 parq)
195 psfColor_GR = self._funcVal(Color(fluxName, 'HSC-G', 'HSC-R',
196 dataset=dataset),
197 parq)
199 self.assertTrue(np.allclose((psfMag_G - psfMag_R).dropna(), psfColor_GR, rtol=0, atol=1e-13))
201 # Check that behavior as expected when dataset not provided;
202 # that is, that the color comes from forced and default Mag is meas
203 psfMag_G = self._funcVal(Mag(fluxName, filt='HSC-G'), parq)
204 psfMag_R = self._funcVal(Mag(fluxName, filt='HSC-R'), parq)
206 psfColor_GR = self._funcVal(Color(fluxName, 'HSC-G', 'HSC-R'), parq)
208 # These should *not* be equal.
209 self.assertFalse(np.allclose((psfMag_G - psfMag_R).dropna(), psfColor_GR))
211 def testMagDiff(self):
212 self.columns.extend(["base_PsfFlux_instFlux", "base_PsfFlux_instFluxErr",
213 "modelfit_CModel_instFlux", "modelfit_CModel_instFluxErr"])
214 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 1000)
215 self.dataDict["base_PsfFlux_instFluxErr"] = np.full(self.nRecords, 10)
216 self.dataDict["modelfit_CModel_instFlux"] = np.full(self.nRecords, 1000)
217 self.dataDict["modelfit_CModel_instFluxErr"] = np.full(self.nRecords, 10)
218 parq = self.simulateMultiParquet(self.dataDict)
220 for filt in self.filters:
221 filt = 'HSC-G'
222 val = self._funcVal(MagDiff('base_PsfFlux', 'modelfit_CModel', filt=filt), parq)
224 mag1 = self._funcVal(Mag('modelfit_CModel', filt=filt), parq)
225 mag2 = self._funcVal(Mag('base_PsfFlux', filt=filt), parq)
226 self.assertTrue(np.allclose((mag2 - mag1).dropna(), val, rtol=0, atol=1e-13))
228 def testDifference(self):
229 """Test .difference method using MagDiff as the example.
230 """
231 self.columns.extend(["base_PsfFlux_instFlux", "base_PsfFlux_instFluxErr",
232 "modelfit_CModel_instFlux", "modelfit_CModel_instFluxErr"])
234 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 1000)
235 self.dataDict["modelfit_CModel_instFlux"] = np.full(self.nRecords, 1000)
236 parq1 = self.simulateMultiParquet(self.dataDict)
238 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 999)
239 self.dataDict["modelfit_CModel_instFlux"] = np.full(self.nRecords, 999)
240 parq2 = self.simulateMultiParquet(self.dataDict)
242 magDiff = MagDiff('base_PsfFlux', 'modelfit_CModel', filt='HSC-G')
244 # Asserts that differences computed properly
245 self._differenceVal(magDiff, parq1, parq2)
247 def testLabeller(self):
248 # Covering the code is better than nothing
249 self.columns.append("base_ClassificationExtendedness_value")
250 self.dataDict["base_ClassificationExtendedness_value"] = np.full(self.nRecords, 1)
251 parq = self.simulateMultiParquet(self.dataDict)
252 labels = self._funcVal(StarGalaxyLabeller(), parq) # noqa
254 def testPixelScale(self):
255 # Test that the pixel scale and pix->arcsec calculations perform as
256 # expected.
257 pass
259 def testOther(self):
260 self.columns.extend(["ext_shapeHSM_HsmSourceMoments_xx", "ext_shapeHSM_HsmSourceMoments_yy",
261 "base_SdssShape_xx", "base_SdssShape_yy",
262 "ext_shapeHSM_HsmPsfMoments_xx", "ext_shapeHSM_HsmPsfMoments_yy",
263 "base_SdssShape_psf_xx", "base_SdssShape_psf_yy"])
264 self.dataDict["ext_shapeHSM_HsmSourceMoments_xx"] = np.full(self.nRecords, 1 / np.sqrt(2))
265 self.dataDict["ext_shapeHSM_HsmSourceMoments_yy"] = np.full(self.nRecords, 1 / np.sqrt(2))
266 self.dataDict["base_SdssShape_xx"] = np.full(self.nRecords, 1 / np.sqrt(2))
267 self.dataDict["base_SdssShape_yy"] = np.full(self.nRecords, 1 / np.sqrt(2))
268 self.dataDict["ext_shapeHSM_HsmPsfMoments_xx"] = np.full(self.nRecords, 1 / np.sqrt(2))
269 self.dataDict["ext_shapeHSM_HsmPsfMoments_yy"] = np.full(self.nRecords, 1 / np.sqrt(2))
270 self.dataDict["base_SdssShape_psf_xx"] = np.full(self.nRecords, 1)
271 self.dataDict["base_SdssShape_psf_yy"] = np.full(self.nRecords, 1)
272 parq = self.simulateMultiParquet(self.dataDict)
273 # Covering the code is better than nothing
274 for filt in self.filters:
275 for Func in [DeconvolvedMoments,
276 SdssTraceSize,
277 PsfSdssTraceSizeDiff,
278 HsmTraceSize, PsfHsmTraceSizeDiff, HsmFwhm]:
279 val = self._funcVal(Func(filt=filt), parq) # noqa
281 def _compositeFuncVal(self, functor, parq):
282 self.assertIsInstance(functor, CompositeFunctor)
284 handle = self.getDatasetHandle(parq)
286 df = functor(parq)
287 df2 = functor(handle)
288 self.assertTrue(df.equals(df2))
290 self.assertIsInstance(df, pd.DataFrame)
291 self.assertTrue(np.all([k in df.columns for k in functor.funcDict.keys()]))
293 df = functor(parq, dropna=True)
294 df2 = functor(handle, dropna=True)
295 self.assertTrue(df.equals(df2))
297 # Check that there are no nulls
298 self.assertFalse(df.isnull().any(axis=None))
300 return df
302 def _compositeDifferenceVal(self, functor, parq1, parq2):
303 self.assertIsInstance(functor, CompositeFunctor)
305 handle1 = self.getDatasetHandle(parq1)
306 handle2 = self.getDatasetHandle(parq2)
308 df = functor.difference(parq1, parq2)
309 df2 = functor.difference(handle1, handle2)
310 self.assertTrue(df.equals(df2))
312 self.assertIsInstance(df, pd.DataFrame)
313 self.assertTrue(np.all([k in df.columns for k in functor.funcDict.keys()]))
315 df = functor.difference(parq1, parq2, dropna=True)
316 df2 = functor.difference(handle1, handle2, dropna=True)
317 self.assertTrue(df.equals(df2))
319 # Check that there are no nulls
320 self.assertFalse(df.isnull().any(axis=None))
322 df1 = functor(parq1)
323 df2 = functor(parq2)
325 self.assertTrue(np.allclose(df.values, df1.values - df2.values))
327 return df
329 def testComposite(self):
330 self.columns.extend(["modelfit_CModel_instFlux", "base_PsfFlux_instFlux"])
331 self.dataDict["modelfit_CModel_instFlux"] = np.full(self.nRecords, 1)
332 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 1)
333 parq = self.simulateMultiParquet(self.dataDict)
334 # Modify r band value slightly.
335 parq._df[("meas", "HSC-R", "base_PsfFlux_instFlux")] -= 0.1
337 filt = 'HSC-G'
338 funcDict = {'psfMag_ref': Mag('base_PsfFlux', dataset='ref'),
339 'ra': RAColumn(),
340 'dec': DecColumn(),
341 'psfMag': Mag('base_PsfFlux', filt=filt),
342 'cmodel_magDiff': MagDiff('base_PsfFlux',
343 'modelfit_CModel', filt=filt)}
344 func = CompositeFunctor(funcDict)
345 df = self._compositeFuncVal(func, parq)
347 # Repeat same, but define filter globally instead of individually
348 funcDict2 = {'psfMag_ref': Mag('base_PsfFlux', dataset='ref'),
349 'ra': RAColumn(),
350 'dec': DecColumn(),
351 'psfMag': Mag('base_PsfFlux'),
352 'cmodel_magDiff': MagDiff('base_PsfFlux',
353 'modelfit_CModel')}
355 func2 = CompositeFunctor(funcDict2, filt=filt)
356 df2 = self._compositeFuncVal(func2, parq)
357 self.assertTrue(df.equals(df2))
359 func2.filt = 'HSC-R'
360 df3 = self._compositeFuncVal(func2, parq)
361 # Because we modified the R filter this should fail.
362 self.assertFalse(df2.equals(df3))
364 # Make sure things work with passing list instead of dict
365 funcs = [Mag('base_PsfFlux', dataset='ref'),
366 RAColumn(),
367 DecColumn(),
368 Mag('base_PsfFlux', filt=filt),
369 MagDiff('base_PsfFlux', 'modelfit_CModel', filt=filt)]
371 df = self._compositeFuncVal(CompositeFunctor(funcs), parq)
373 def testCompositeColor(self):
374 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 1000)
375 self.dataDict["base_PsfFlux_instFluxErr"] = np.full(self.nRecords, 10)
376 parq = self.simulateMultiParquet(self.dataDict)
377 funcDict = {'a': Mag('base_PsfFlux', dataset='meas', filt='HSC-G'),
378 'b': Mag('base_PsfFlux', dataset='forced_src', filt='HSC-G'),
379 'c': Color('base_PsfFlux', 'HSC-G', 'HSC-R')}
380 # Covering the code is better than nothing
381 df = self._compositeFuncVal(CompositeFunctor(funcDict), parq) # noqa
383 def testCompositeDifference(self):
384 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 1000)
385 self.dataDict["base_PsfFlux_instFluxErr"] = np.full(self.nRecords, 10)
386 parq1 = self.simulateMultiParquet(self.dataDict)
388 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 999)
389 self.dataDict["base_PsfFlux_instFluxErr"] = np.full(self.nRecords, 9)
390 parq2 = self.simulateMultiParquet(self.dataDict)
392 funcDict = {'a': Mag('base_PsfFlux', dataset='meas', filt='HSC-G'),
393 'b': Mag('base_PsfFlux', dataset='forced_src', filt='HSC-G'),
394 'c': Color('base_PsfFlux', 'HSC-G', 'HSC-R')}
395 # Covering the code is better than nothing
396 df = self._compositeDifferenceVal(CompositeFunctor(funcDict), parq1, parq2) # noqa
398 def testCompositeFail(self):
399 """Test a composite functor where one of the functors should be junk.
400 """
401 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, 1000)
402 parq = self.simulateMultiParquet(self.dataDict)
404 funcDict = {'good': Column("base_PsfFlux_instFlux"),
405 'bad': Column('not_a_column')}
407 df = self._compositeFuncVal(CompositeFunctor(funcDict), parq) # noqa
409 def testLocalPhotometry(self):
410 """Test the local photometry functors.
411 """
412 flux = 1000
413 fluxErr = 10
414 calib = 10
415 calibErr = 1
416 self.dataDict["base_PsfFlux_instFlux"] = np.full(self.nRecords, flux)
417 self.dataDict["base_PsfFlux_instFluxErr"] = np.full(self.nRecords,
418 fluxErr)
419 self.dataDict["base_LocalPhotoCalib"] = np.full(self.nRecords, calib)
420 self.dataDict["base_LocalPhotoCalibErr"] = np.full(self.nRecords,
421 calibErr)
422 parq = self.simulateMultiParquet(self.dataDict)
423 func = LocalPhotometry("base_PsfFlux_instFlux",
424 "base_PsfFlux_instFluxErr",
425 "base_LocalPhotoCalib",
426 "base_LocalPhotoCalibErr")
427 df = parq.toDataFrame(columns={"dataset": "meas",
428 "filter": "HSC-G",
429 "columns": ["base_PsfFlux_instFlux",
430 "base_PsfFlux_instFluxErr",
431 "base_LocalPhotoCalib",
432 "base_LocalPhotoCalibErr"]})
433 nanoJansky = func.instFluxToNanojansky(
434 df[("meas", "HSC-G", "base_PsfFlux_instFlux")],
435 df[("meas", "HSC-G", "base_LocalPhotoCalib")])
436 mag = func.instFluxToMagnitude(
437 df[("meas", "HSC-G", "base_PsfFlux_instFlux")],
438 df[("meas", "HSC-G", "base_LocalPhotoCalib")])
439 nanoJanskyErr = func.instFluxErrToNanojanskyErr(
440 df[("meas", "HSC-G", "base_PsfFlux_instFlux")],
441 df[("meas", "HSC-G", "base_PsfFlux_instFluxErr")],
442 df[("meas", "HSC-G", "base_LocalPhotoCalib")],
443 df[("meas", "HSC-G", "base_LocalPhotoCalibErr")])
444 magErr = func.instFluxErrToMagnitudeErr(
445 df[("meas", "HSC-G", "base_PsfFlux_instFlux")],
446 df[("meas", "HSC-G", "base_PsfFlux_instFluxErr")],
447 df[("meas", "HSC-G", "base_LocalPhotoCalib")],
448 df[("meas", "HSC-G", "base_LocalPhotoCalibErr")])
450 self.assertTrue(np.allclose(nanoJansky.values,
451 flux * calib,
452 atol=1e-13,
453 rtol=0))
454 self.assertTrue(np.allclose(mag.values,
455 (flux * calib * u.nJy).to_value(u.ABmag),
456 atol=1e-13,
457 rtol=0))
458 self.assertTrue(np.allclose(nanoJanskyErr.values,
459 np.hypot(fluxErr * calib, flux * calibErr),
460 atol=1e-13,
461 rtol=0))
462 self.assertTrue(np.allclose(
463 magErr.values,
464 2.5 / np.log(10) * nanoJanskyErr.values / nanoJansky.values,
465 atol=1e-13,
466 rtol=0))
468 # Test functors against the values computed above.
469 self._testLocalPhotometryFunctors(LocalNanojansky,
470 parq,
471 nanoJansky)
472 self._testLocalPhotometryFunctors(LocalNanojanskyErr,
473 parq,
474 nanoJanskyErr)
475 self._testLocalPhotometryFunctors(LocalMagnitude,
476 parq,
477 mag)
478 self._testLocalPhotometryFunctors(LocalMagnitudeErr,
479 parq,
480 magErr)
482 def _testLocalPhotometryFunctors(self, functor, parq, testValues):
483 func = functor("base_PsfFlux_instFlux",
484 "base_PsfFlux_instFluxErr",
485 "base_LocalPhotoCalib",
486 "base_LocalPhotoCalibErr")
487 val = self._funcVal(func, parq)
488 self.assertTrue(np.allclose(testValues.values,
489 val.values,
490 atol=1e-13,
491 rtol=0))
493 def testConvertPixelToArcseconds(self):
494 """Test calculations of the pixel scale and conversions of pixel to
495 arcseconds.
496 """
497 dipoleSep = 10
498 np.random.seed(1234)
499 testPixelDeltas = np.random.uniform(-100, 100, size=(self.nRecords, 2))
500 import lsst.afw.table as afwTable
501 localWcsPlugin = measBase.EvaluateLocalWcsPlugin(
502 None,
503 "base_LocalWcs",
504 afwTable.SourceTable.makeMinimalSchema(),
505 None)
506 for dec in np.linspace(-90, 90, 10):
507 for x, y in zip(np.random.uniform(2 * 1109.99981456774, size=10),
508 np.random.uniform(2 * 560.018167811613, size=10)):
510 center = geom.Point2D(x, y)
511 wcs = self._makeWcs(dec)
512 skyOrigin = wcs.pixelToSky(center)
514 linAffMatrix = localWcsPlugin.makeLocalTransformMatrix(wcs,
515 center)
516 self.dataDict["dipoleSep"] = np.full(self.nRecords, dipoleSep)
517 self.dataDict["slot_Centroid_x"] = np.full(self.nRecords, x)
518 self.dataDict["slot_Centroid_y"] = np.full(self.nRecords, y)
519 self.dataDict["someCentroid_x"] = x + testPixelDeltas[:, 0]
520 self.dataDict["someCentroid_y"] = y + testPixelDeltas[:, 1]
521 self.dataDict["base_LocalWcs_CDMatrix_1_1"] = np.full(self.nRecords,
522 linAffMatrix[0, 0])
523 self.dataDict["base_LocalWcs_CDMatrix_1_2"] = np.full(self.nRecords,
524 linAffMatrix[0, 1])
525 self.dataDict["base_LocalWcs_CDMatrix_2_1"] = np.full(self.nRecords,
526 linAffMatrix[1, 0])
527 self.dataDict["base_LocalWcs_CDMatrix_2_2"] = np.full(self.nRecords,
528 linAffMatrix[1, 1])
529 parq = self.simulateMultiParquet(self.dataDict)
530 func = LocalWcs("base_LocalWcs_CDMatrix_1_1",
531 "base_LocalWcs_CDMatrix_1_2",
532 "base_LocalWcs_CDMatrix_2_1",
533 "base_LocalWcs_CDMatrix_2_2")
534 df = parq.toDataFrame(columns={"dataset": "meas",
535 "filter": "HSC-G",
536 "columns": ["dipoleSep",
537 "slot_Centroid_x",
538 "slot_Centroid_y",
539 "someCentroid_x",
540 "someCentroid_y",
541 "base_LocalWcs_CDMatrix_1_1",
542 "base_LocalWcs_CDMatrix_1_2",
543 "base_LocalWcs_CDMatrix_2_1",
544 "base_LocalWcs_CDMatrix_2_2"]})
546 # Exercise the full set of functions in LocalWcs.
547 sepRadians = func.getSkySeperationFromPixel(
548 df[("meas", "HSC-G", "someCentroid_x")] - df[("meas", "HSC-G", "slot_Centroid_x")],
549 df[("meas", "HSC-G", "someCentroid_y")] - df[("meas", "HSC-G", "slot_Centroid_y")],
550 0.0,
551 0.0,
552 df[("meas", "HSC-G", "base_LocalWcs_CDMatrix_1_1")],
553 df[("meas", "HSC-G", "base_LocalWcs_CDMatrix_1_2")],
554 df[("meas", "HSC-G", "base_LocalWcs_CDMatrix_2_1")],
555 df[("meas", "HSC-G", "base_LocalWcs_CDMatrix_2_2")])
557 # Test functor values against afw SkyWcs computations.
558 for centX, centY, sep in zip(testPixelDeltas[:, 0],
559 testPixelDeltas[:, 1],
560 sepRadians.values):
561 afwSepRadians = skyOrigin.separation(
562 wcs.pixelToSky(x + centX, y + centY)).asRadians()
563 self.assertAlmostEqual(1 - sep / afwSepRadians, 0, places=6)
565 # Test the pixel scale computation.
566 func = ComputePixelScale("base_LocalWcs_CDMatrix_1_1",
567 "base_LocalWcs_CDMatrix_1_2",
568 "base_LocalWcs_CDMatrix_2_1",
569 "base_LocalWcs_CDMatrix_2_2")
570 pixelScale = self._funcVal(func, parq)
571 self.assertTrue(np.allclose(
572 wcs.getPixelScale(center).asArcseconds(),
573 pixelScale.values,
574 rtol=1e-8,
575 atol=0))
577 func = ConvertPixelToArcseconds("dipoleSep",
578 "base_LocalWcs_CDMatrix_1_1",
579 "base_LocalWcs_CDMatrix_1_2",
580 "base_LocalWcs_CDMatrix_2_1",
581 "base_LocalWcs_CDMatrix_2_2")
582 val = self._funcVal(func, parq)
583 self.assertTrue(np.allclose(pixelScale.values * dipoleSep,
584 val.values,
585 atol=1e-16,
586 rtol=1e-16))
588 def _makeWcs(self, dec=53.1595451514076):
589 """Create a wcs from real CFHT values.
591 Returns
592 -------
593 wcs : `lsst.afw.geom`
594 Created wcs.
595 """
596 metadata = dafBase.PropertySet()
598 metadata.set("SIMPLE", "T")
599 metadata.set("BITPIX", -32)
600 metadata.set("NAXIS", 2)
601 metadata.set("NAXIS1", 1024)
602 metadata.set("NAXIS2", 1153)
603 metadata.set("RADECSYS", 'FK5')
604 metadata.set("EQUINOX", 2000.)
606 metadata.setDouble("CRVAL1", 215.604025685476)
607 metadata.setDouble("CRVAL2", dec)
608 metadata.setDouble("CRPIX1", 1109.99981456774)
609 metadata.setDouble("CRPIX2", 560.018167811613)
610 metadata.set("CTYPE1", 'RA---SIN')
611 metadata.set("CTYPE2", 'DEC--SIN')
613 metadata.setDouble("CD1_1", 5.10808596133527E-05)
614 metadata.setDouble("CD1_2", 1.85579539217196E-07)
615 metadata.setDouble("CD2_2", -5.10281493481982E-05)
616 metadata.setDouble("CD2_1", -8.27440751733828E-07)
618 return afwGeom.makeSkyWcs(metadata)
621class MyMemoryTestCase(lsst.utils.tests.MemoryTestCase):
622 pass
625def setup_module(module):
626 lsst.utils.tests.init()
629if __name__ == "__main__": 629 ↛ 630line 629 didn't jump to line 630, because the condition on line 629 was never true
630 lsst.utils.tests.init()
631 unittest.main()