Skip to content
FieldDistortion.py 4.72 KiB
Newer Older
Fang Yuedong's avatar
Fang Yuedong committed
import galsim
import numpy as np
Fang Yuedong's avatar
Fang Yuedong committed

class FieldDistortion(object):

    def __init__(self, chip, fdModel=None, fdModel_path=None, img_rot=0.):
Fang Yuedong's avatar
Fang Yuedong committed
        if fdModel is None:
Fang Yuedong's avatar
Fang Yuedong committed
            if hasattr(chip, 'fdModel'):
                self.fdModel = chip.fdModel
            elif fdModel_path is not None:
                import pickle
Fang Yuedong's avatar
Fang Yuedong committed
                with open(fdModel_path, "rb") as f:
                    self.fdModel = pickle.load(f)
            else:
Fang Yuedong's avatar
Fang Yuedong committed
                raise ValueError("Error: no field distortion model has been specified!")
Fang Yuedong's avatar
Fang Yuedong committed
        else:
            self.fdModel = fdModel
        self.img_rot = img_rot
Fang Yuedong's avatar
Fang Yuedong committed
        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

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

    def get_distorted(self, chip, pos_img, bandpass=None, img_rot=None):
Fang Yuedong's avatar
Fang Yuedong committed
        """ 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
            return galsim.PositionD(-1, -1), None
        if not img_rot:
            img_rot = np.radians(self.img_rot)
        else:
            img_rot = np.radians(img_rot)
Fang Yuedong's avatar
Fang Yuedong committed
        x, y = pos_img.x, pos_img.y
Fang Yuedong's avatar
Fang Yuedong committed
        x = self.ixfdModel(x, y)[0][0]
        y = self.iyfdModel(x, y)[0][0]
Fang Yuedong's avatar
Fang Yuedong committed
            # 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]
Fang Yuedong's avatar
Fang Yuedong committed
            # 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:
            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)
Fang Yuedong's avatar
Fang Yuedong committed
        g1k_fd   = 0.0 + (iy_dy - ix_dx) / (iy_dy + ix_dx)
        g2k_fd   = 0.0 - (iy_dx + ix_dy) / (iy_dy + ix_dx)

        # [TODO] [TESTING] Rotate the shear:
        g_abs = np.sqrt(g1k_fd**2 + g2k_fd**2)
        phi = cmath.phase(complex(g1k_fd, g2k_fd))
        # g_abs = 0.7
        g1k_fd = g_abs * np.cos(phi + 2*img_rot)
        g2k_fd = g_abs * np.sin(phi + 2*img_rot)
Fang Yuedong's avatar
Fang Yuedong committed
        fd_shear = galsim.Shear(g1=g1k_fd, g2=g2k_fd)
        return galsim.PositionD(x, y), fd_shear