Coverage for python / lsst / meas / astrom / fit_sip_approximation.py: 74%

19 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-14 23:59 +0000

1# This file is part of meas_astrom. 

2# 

3# Developed for the LSST Data Management System. 

4# This product includes software developed by the LSST Project 

5# (https://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 <https://www.gnu.org/licenses/>. 

21 

22from __future__ import annotations 

23 

24__all__ = ("FitSipApproximationConfig", "FitSipApproximationTask",) 

25 

26import math 

27 

28 

29from lsst.afw.geom import SipApproximation 

30from lsst.geom import Box2D, Extent2I 

31from lsst.pex.config import Config, Field 

32from lsst.pipe.base import Struct, Task 

33 

34 

35class FitSipApproximationConfig(Config): 

36 grid_spacing = Field[float]( 

37 doc=( 

38 "Spacing (in pixels) between grid points used to evaluate the WCS when fitting the " 

39 "approximation. " 

40 "If the spacing does not divide the detector bounding box evenly, it is decreased slightly." 

41 ), 

42 dtype=float, 

43 default=32.0, 

44 ) 

45 order = Field[int]( 

46 doc="Polynomial order for the SIP approximation.", 

47 dtype=int, 

48 default=5, 

49 ) 

50 

51 

52class FitSipApproximationTask(Task): 

53 """A simple convenience wrapper for `lsst.afw.geom.SipApproximation`. 

54 """ 

55 

56 _DefaultName = "fitSipApproximation" 

57 ConfigClass = FitSipApproximationConfig 

58 

59 def run(self, *, wcs, bbox): 

60 """Re-fit the pointing from the WCSs in a visit. 

61 

62 Parameters 

63 ---------- 

64 wcs : `lsst.afw.geom.SkyWcs` 

65 Target WCS to approximate. 

66 bbox : `lsst.geom.Box2I` 

67 The region where the WCS and its approximation are expected to be 

68 valid. 

69 

70 Returns 

71 ------- 

72 results : `lsst.pipe.base.Struct` 

73 A struct with the following attributes: 

74 

75 - ``wcs`` (`lsst.afw.geom.SkyWcs`): a copy of the input ``wcs`` 

76 with a SIP approximation attached. 

77 - ``delta_sky`` (`lsst.geom.Angle`): maximum separation in 

78 ``pixelToSky`` values on a grid offset from the one used for the 

79 fit. 

80 - ``delta_pixel`` (`float`): maximum separation in ``skyToPixel`` 

81 values on a grid offset from the one used for the fit. 

82 """ 

83 grid_shape = Extent2I( 

84 math.ceil(bbox.width / self.config.grid_spacing) + 1, 

85 math.ceil(bbox.height / self.config.grid_spacing) + 1, 

86 ) 

87 approx = SipApproximation(wcs, Box2D(bbox), grid_shape, self.config.order) 

88 delta_sky, delta_pixel = approx.computeDeltas() 

89 self.log.verbose('Fit TAN-SIP approximation good to %0.2g" and %0.2g pixels.', 

90 delta_sky.asArcseconds(), delta_pixel) 

91 return Struct( 

92 wcs=wcs.copyWithFitsApproximation(approx.getWcs()), 

93 delta_sky=delta_sky, 

94 delta_pixel=delta_pixel, 

95 )