FieldDistortion.py 4.25 KB
Newer Older
Fang Yuedong's avatar
Fang Yuedong committed
1
2
3
4
5
import galsim
import numpy as np

class FieldDistortion(object):

Fang Yuedong's avatar
Fang Yuedong committed
6
    def __init__(self, chip, fdModel=None, fdModel_path=None):
Fang Yuedong's avatar
Fang Yuedong committed
7
        if fdModel is None:
Fang Yuedong's avatar
Fang Yuedong committed
8
9
10
11
            if hasattr(chip, 'fdModel'):
                self.fdModel = chip.fdModel
            elif fdModel_path is not None:
                import pickle
Fang Yuedong's avatar
Fang Yuedong committed
12
13
14
                with open(fdModel_path, "rb") as f:
                    self.fdModel = pickle.load(f)
            else:
Fang Yuedong's avatar
Fang Yuedong committed
15
                raise ValueError("Error: no field distortion model has been specified!")
Fang Yuedong's avatar
Fang Yuedong committed
16
17
        else:
            self.fdModel = fdModel
Fang Yuedong's avatar
Fang Yuedong committed
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
        self.ifdModel = self.fdModel["wave1"]
        self.ixfdModel = self.ifdModel["xImagePos"]
        self.iyfdModel = self.ifdModel["yImagePos"]
        # first-order derivatives of the global field distortion model
        self.ifx_dx    = self.ixfdModel.partial_derivative(1,0)
        self.ifx_dy    = self.ixfdModel.partial_derivative(0,1)
        self.ify_dx    = self.iyfdModel.partial_derivative(1,0)
        self.ify_dy    = self.iyfdModel.partial_derivative(0,1)
        if "residual" in self.fdModel["wave1"]:
            self.irsModel = self.fdModel["wave1"]["residual"]["ccd" + chip.getChipLabel(chipID=chip.chipID)]
            self.ixrsModel = self.irsModel["xResidual"]
            self.iyrsModel = self.irsModel["yResidual"]
            # first-order derivatives of the residual field distortion model
            self.irx_dx    = self.ixrsModel.partial_derivative(1,0)
            self.irx_dy    = self.ixrsModel.partial_derivative(0,1)
            self.iry_dx    = self.iyrsModel.partial_derivative(1,0)
            self.iry_dy    = self.iyrsModel.partial_derivative(0,1)
        else:
            self.irsModel = None
Fang Yuedong's avatar
Fang Yuedong committed
37
38

    def isContainObj_FD(self, chip, pos_img):
Fang Yuedong's avatar
Fang Yuedong committed
39
        xLowI, xUpI, yLowI, yUpI = self.ifdModel["interpLimit"]
Fang Yuedong's avatar
Fang Yuedong committed
40
        x, y = pos_img.x, pos_img.y
Fang Yuedong's avatar
Fang Yuedong committed
41
        if (xLowI - x) * (xUpI - x) > 0 or (yLowI - y) * (yUpI - y) > 0:
Fang Yuedong's avatar
Fang Yuedong committed
42
43
44
            return False
        return True

Fang Yuedong's avatar
Fang Yuedong committed
45
    def get_distorted(self, chip, pos_img, bandpass=None):
Fang Yuedong's avatar
Fang Yuedong committed
46
47
48
49
50
51
52
53
54
55
56
57
58
59
        """ Get the distored position for an undistorted image position

        Parameters:
            chip:       A 'Chip' object representing the
                        chip we want to extract PSF from.
            pos_img:    A 'galsim.Position' object representing
                        the image position.
            bandpass:   A 'galsim.Bandpass' object representing
                        the wavelength range.
        Returns:
            pos_distorted:      A 'galsim.Position' object representing
                                the distored position.
        """
        if not self.isContainObj_FD(chip=chip, pos_img=pos_img):
Fang Yuedong's avatar
Fang Yuedong committed
60
            return galsim.PositionD(-1, -1), None
Fang Yuedong's avatar
Fang Yuedong committed
61
        x, y = pos_img.x, pos_img.y
Fang Yuedong's avatar
Fang Yuedong committed
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
        x = self.ixfdModel(x, y)[0][0]
        y = self.iyfdModel(x, y)[0][0]
        ix_dx = self.ifx_dx(x, y)
        ix_dy = self.ifx_dy(x, y)
        iy_dx = self.ify_dx(x, y)
        iy_dy = self.ify_dy(x, y)
        if self.irsModel is not None:
            # x1LowI, x1UpI, y1LowI, y1UpI = self.irsModel["interpLimit"]
            # if (x1LowI-x)*(x1UpI-x) <=0 and (y1LowI-y)*(y1UpI-y)<=0:
            #     dx = self.ixrsModel(x, y)[0][0]
            #     dy = self.iyrsModel(x, y)[0][0]
            #     x += dx
            #     y += dy
            #     # field distortion induced ellipticity
            #     ix_dx = self.ifx_dx(x, y) + self.irx_dx(x, y)
            #     ix_dy = self.ifx_dy(x, y) + self.irx_dy(x, y)
            #     iy_dx = self.ify_dx(x, y) + self.iry_dx(x, y)
            #     iy_dy = self.ify_dy(x, y) + self.iry_dy(x, y)
            # else:
            #     return galsim.PositionD(-1, -1), None
            dx = self.ixrsModel(x, y)[0][0]
            dy = self.iyrsModel(x, y)[0][0]
84
85
            x += dx
            y += dy
Fang Yuedong's avatar
Fang Yuedong committed
86
87
88
89
90
91
92
93
94
95
            # field distortion induced ellipticity
            ix_dx = self.ifx_dx(x, y) + self.irx_dx(x, y)
            ix_dy = self.ifx_dy(x, y) + self.irx_dy(x, y)
            iy_dx = self.ify_dx(x, y) + self.iry_dx(x, y)
            iy_dy = self.ify_dy(x, y) + self.iry_dy(x, y)
        g1k_fd   = 0.0 + (iy_dy - ix_dx) / (iy_dy + ix_dx)
        g2k_fd   = 0.0 - (iy_dx + ix_dy) / (iy_dy + ix_dx)
        fd_shear = galsim.Shear(g1=g1k_fd, g2=g2k_fd)
        return galsim.PositionD(x, y), fd_shear