def test_ShiftCoeffs(verbose=False):
    """ Test accuracy of shift_coefficients method"""

    # First invent a plausible polynomial
    order = 5
    a = makeup_polynomial()

    if verbose:
        print('A')
        polynomial.print_triangle(a)

    # Shift by a random step
    np.random.seed(seed=1)
    [xshift, yshift] = 1024.0 * np.random.rand(2) - 512.0

    ashift = polynomial.shift_coefficients(a, xshift, yshift, verbose)
    if verbose:
        print('AS')
        polynomial.print_triangle(ashift)

    # Choose a random point
    [x, y] = 2048 * np.random.rand(2) - 1024.0
    u1 = polynomial.poly(a, x, y, order)
    u2 = polynomial.poly(ashift, x - xshift, y - yshift, order)

    if verbose:
        print('XY', x, y)
        print('Shift', xshift, yshift)
        print('U values', u1, u2, u1 - u2)

    assert abs(u1 - u2) < 1.0e-12, 'Inaccurate shift transformation'

    return None
Exemple #2
0
            detector_layout_index = detector_layout['AperName'].tolist().index(
                master_aperture_name)
            for attribute in 'DetSciYAngle DetSciParity VIdlParity'.split():
                setattr(aperture, attribute,
                        detector_layout[attribute][detector_layout_index])

            # this is the name given to the pseudo-aperture in the Calc worksheet
            csv_aperture_name = 'DET_DMF'

        aperture.Sci2IdlDeg = polynomial_degree

        dx = aperture.XDetRef - csv_data[csv_aperture_name]['dx']
        dy = aperture.YDetRef - csv_data[csv_aperture_name]['dy']

        csv_data[csv_aperture_name][
            'A_shifted'] = polynomial.shift_coefficients(
                csv_data[csv_aperture_name]['A'], dx, dy, verbose=False)
        csv_data[csv_aperture_name][
            'B_shifted'] = polynomial.shift_coefficients(
                csv_data[csv_aperture_name]['B'], dx, dy, verbose=False)

        # apply polynomial to get reference location in ideal plane
        dxIdl = polynomial.poly(csv_data[csv_aperture_name]['A'],
                                dx,
                                dy,
                                order=polynomial_degree)
        dyIdl = polynomial.poly(csv_data[csv_aperture_name]['B'],
                                dx,
                                dy,
                                order=polynomial_degree)

        csv_data[csv_aperture_name][
Exemple #3
0
def get_mirim_coefficients(distortion_file, verbose=False):
    """Read delivered FITS file for MIRI imager and return data to be ingested in SIAF.

    Parameters
    ----------
    distortion_file : str
        Name of distortion file.
    verbose : bool
        verbosity

    Returns
    -------
    csv_data : dict
        Dictionary containing the data

    """
    miri = fits.open(os.path.join(source_data_dir, distortion_file))

    T = miri['T matrix'].data
    TI = miri['TI matrix'].data

    # CDP7 T matrices transform from/to v2,v3 in arcsec
    # set VtoAN and ANtoV to unit matrix
    VtoAN = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])
    ANtoV = np.array([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 0.0, 1.0]])

    TV = np.dot(T, VtoAN)
    VT = np.dot(ANtoV, TI)
    prod = np.dot(VT, TV)
    TT = np.dot(T, TI)

    if verbose:
        print('T\n', T)
        print('TI\n', TI)
        print('VtoAN\n', VtoAN)
        print('\n TV V2V3 to XY Entrance')
        print(TV)
        print(1.0 / TV[1, 1], 'arcsec/mm')
        print('\nANtoV\n', ANtoV)
        print('\n VTXY entrance to V2V3')
        print('VT\n', VT)
        print()
        print('VT comparison\n', prod)
        print('T comparison\n', TT)

    # Get linear coefficient layout
    A = miri['AI matrix'].data
    B = miri['BI matrix'].data
    C = miri['A matrix'].data
    D = miri['B matrix'].data
    AL = untangle(A)
    BL = untangle(B)
    CL = untangle(C)
    DL = untangle(D)
    if verbose:
        print('Initial AL\n', AL)
        print('Initial BL\n', BL)
        print('CL\n', CL)
        print('DL\n', DL)

    # scale factor corresponding to 25 mum pixel size, i.e. 40 pixels/mm
    order = 4
    k = 0
    for i in range(order + 1):
        factor = 0.025**i
        for j in range(i + 1):
            AL[k] = AL[k] * factor
            BL[k] = BL[k] * factor
            k += 1

    AF = VT[0, 0] * AL + VT[0, 1] * BL
    AF[0] = AF[0] + VT[0, 2]
    BF = VT[1, 0] * AL + VT[1, 1] * BL
    BF[0] = BF[0] + VT[1, 2]

    if verbose:
        polynomial.print_triangle(AF)
        polynomial.print_triangle(BF)

        print('AL scaled\n', AL)
        print('\n A FINAL')
        print('\n B FINAL')

    ## print('INVERSE TRANSFORMATIONS')
    # Combine TV with polynomial using polynomial.two_step
    # combination of several polynomial coefficients
    a = np.array([TV[0, 2], TV[0, 0], TV[0, 1]])
    b = np.array([TV[1, 2], TV[1, 0], TV[1, 1]])
    (C2, D2) = polynomial.two_step(CL, DL, a, b)
    CF = 40 * C2
    DF = 40 * D2
    if verbose:
        polynomial.print_triangle(CF)
        polynomial.print_triangle(DF)

        print('a', a)
        print('b', b)
        print('\nC Final')
        print('\nD Final')

        # if verbose:

        # Test two_step
        v2 = -280
        v3 = -430

        xin = TV[0, 0] * v2 + TV[0, 1] * v3 + TV[0, 2]
        yin = TV[1, 0] * v2 + TV[1, 1] * v3 + TV[1, 2]

        xmm = polynomial.poly(CL, xin, yin, 4)
        ymm = polynomial.poly(DL, xin, yin, 4)

        xmm2 = polynomial.poly(C2, v2, v3, 4)
        ymm2 = polynomial.poly(D2, v2, v3, 4)

        # Backwards check
        xp = 0
        yp = 0
        v2 = polynomial.poly(AF, xp, yp, 4)
        v3 = polynomial.poly(BF, xp, yp, 4)
        xpix = polynomial.poly(CF, v2, v3, 4)
        ypix = polynomial.poly(DF, v2, v3, 4)

        print('IN', xin, yin)
        print('MM', xmm, ymm)
        print('MM2', xmm2, ymm2)
        print('V', v2, v3)
        print('Original ', xp, yp)
        print('Recovered', xpix, ypix)
        print('Change   ', xpix - xp, ypix - yp)

        invcheck(AF, BF, CF, DF, 4, -512.0, 512.0)

    CS = polynomial.shift_coefficients(CF, AF[0], BF[0])
    DS = polynomial.shift_coefficients(DF, AF[0], BF[0])
    CS[0] = 0.0
    DS[0] = 0.0

    # extract V2,V3 reference position
    V2cen = AF[0]
    V3cen = BF[0]

    # reset zero order coefficients to zero
    AF[0] = 0.0
    BF[0] = 0.0

    if verbose:
        polynomial.print_triangle(CS)
        polynomial.print_triangle(DS)
        invcheck(AF, BF, CS, DS, 4, -512.0, 512.0)

        print('\nCS')
        print('\nDS')
        print('\nDetector Center')

        # if verbose:
        xscalec = np.hypot(AF[1], BF[1])
        yscalec = np.hypot(AF[2], BF[2])

    # compute angles
    xanglec = np.rad2deg(np.arctan2(AF[1], BF[1]))
    yanglec = np.rad2deg(np.arctan2(AF[2], BF[2]))

    if verbose:
        print('Position', V2cen, V3cen)
        print('Scales %10.6f %10.6f' % (xscalec, yscalec))
        print('Angles %10.6f %10.6f' % (xanglec, yanglec))

        # if verbose:
        xcen = 1033 / 2
        ycen = 1025 / 2
        xref = 693.5 - xcen
        yref = 512.5 - ycen
        V2Ref = polynomial.poly(AF, xref, yref, 4) + V2cen
        V3Ref = polynomial.poly(BF, xref, yref, 4) + V3cen
        dV2dx = polynomial.dpdx(AF, xref, yref)
        dV3dx = polynomial.dpdx(BF, xref, yref)
        dV2dy = polynomial.dpdy(AF, xref, yref)
        dV3dy = polynomial.dpdy(BF, xref, yref)
        xangler = np.arctan2(dV2dx, dV3dx)
        yangler = np.arctan2(dV2dy, dV3dy)
        # if verbose:
        print('Axis angles', np.rad2deg(xangler), np.rad2deg(yangler))

        # if verbose:
        # Illum reference position
        xscaler = np.hypot(dV2dx, dV3dx)
        yscaler = np.hypot(dV2dy, dV3dy)
        xangler = np.rad2deg(np.arctan2(dV2dx, dV3dx))
        yangler = np.rad2deg(np.arctan2(dV2dy, dV3dy))

        # if verbose:
        print('\nIllum reference position')
        print('xref=', xref)
        print('Position', V2Ref, V3Ref)
        print('Scales %10.6f %10.6f' % (xscaler, yscaler))
        print('Angles %10.6f %10.6f %10.6f' %
              (xangler, yangler, yangler - xangler))

        # if verbose:
        # Slit position
        xslit = (326.13)
        yslit = (300.70)
        dxslit = xslit - xcen
        dyslit = yslit - ycen
        V2slit = polynomial.poly(AF, dxslit, dyslit, 4) + V2cen
        V3slit = polynomial.poly(BF, dxslit, dyslit, 4) + V3cen
        dV2dx = polynomial.dpdx(AF, dxslit, yslit)
        dV3dx = polynomial.dpdx(BF, dxslit, dyslit)
        dV2dy = polynomial.dpdy(AF, dxslit, dyslit)
        dV3dy = polynomial.dpdy(BF, dxslit, dyslit)
        xangles = np.arctan2(dV2dx, dV3dx)
        yangles = np.arctan2(dV2dy, dV3dy)

        # if verbose:
        print('\nSlit')
        print('Position', dxslit, dyslit)
        print('V2,V3', V2slit, V3slit)
        print('Slit angles', np.rad2deg(xangles), np.rad2deg(yangles))

        # if verbose:
        # Corners
        xc = np.array([-516.0, 516.0, 516.0, -516.0, -516.0])
        yc = np.array([-512.0, -512.0, 512.0, 512.0, -512.0])
        V2c = polynomial.poly(AF, xc, yc, 4)
        V3c = polynomial.poly(BF, xc, yc, 4)
        V2c = V2c + V2cen
        V3c = V3c + V3cen
        # if verbose:
        print('\nCorners')
        print('V2 %10.4f %10.4f %10.4f %10.4f' %
              (V2c[0], V2c[1], V2c[2], V2c[3]))
        print('V3 %10.4f %10.4f %10.4f %10.4f' %
              (V3c[0], V3c[1], V3c[2], V3c[3]))

        # make figure
        pl.figure(1)
        pl.clf()
        pl.title('MIRI Detector')
        pl.plot(V2cen, V3cen, 'r+')
        pl.plot(V2c, V3c, ':')
        pl.grid(True)
        pl.axis('equal')
        pl.plot(V2Ref, V3Ref, 'b+')
        pl.plot(V2slit, V3slit, 'c+')
        pl.gca().invert_xaxis()
        pl.show()

        ## Rotated versions
        print('Angle', yanglec)
        print('Rotated')

    # incorporate rotation in coefficients
    a = np.deg2rad(yanglec)
    AR = AF * np.cos(a) - BF * np.sin(a)
    BR = AF * np.sin(a) + BF * np.cos(a)

    CR = polynomial.prepend_rotation_to_polynomial(CS, yanglec)
    DR = polynomial.prepend_rotation_to_polynomial(DS, yanglec)

    if verbose:
        print('AR')
        polynomial.print_triangle(AR)
        print('BR')
        polynomial.print_triangle(BF)
        print('\n', AR[2], ' near zero')
        # if verbose:
        invcheck(AR, BR, CR, DR, 4, -512.0, 512.0)

        # Check positions using rotated (Ideal) coefficients
        # if verbose:

        xi = polynomial.poly(AR, xc, yc, 4)
        yi = polynomial.poly(BR, xc, yc, 4)
        v2r = xi * np.cos(a) + yi * np.sin(a) + V2cen
        v3r = -xi * np.sin(a) + yi * np.cos(a) + V3cen
        # if verbose:
        print('V2', v2r)
        print('V3', v3r)
        pl.plot(v2r, v3r, '--')

    CRFl = polynomial.flip_x(CR)
    DRFl = polynomial.flip_x(DR)

    # see TR: "polynomial origin being at the detector center with
    # pixel position (516.5, 512.5). "
    detector_center_pixel_x = 516.5
    detector_center_pixel_y = 512.5

    # dictionary holding data written to csv
    csv_data = {}
    csv_data['DET_OSS'] = {}
    csv_data['DET_OSS']['A'] = AR
    csv_data['DET_OSS']['B'] = BR
    csv_data['DET_OSS']['C'] = CR
    csv_data['DET_OSS']['D'] = DR
    csv_data['DET_OSS']['Xref'] = detector_center_pixel_x
    csv_data['DET_OSS']['Yref'] = detector_center_pixel_y
    csv_data['DET_OSS']['Xref_inv'] = V2cen
    csv_data['DET_OSS']['Yref_inv'] = V3cen
    csv_data['DET_OSS']['xAngle'] = xanglec
    csv_data['DET_OSS']['yAngle'] = yanglec
    csv_data['DET_DMF'] = {}
    csv_data['DET_DMF']['A'] = -AR
    csv_data['DET_DMF']['B'] = BR
    csv_data['DET_DMF']['C'] = CRFl
    csv_data['DET_DMF']['D'] = DRFl
    csv_data['DET_DMF']['Xref'] = detector_center_pixel_x
    csv_data['DET_DMF']['Yref'] = detector_center_pixel_y
    csv_data['DET_DMF']['Xref_inv'] = V2cen
    csv_data['DET_DMF']['Yref_inv'] = V3cen
    csv_data['DET_DMF']['xAngle'] = xanglec
    csv_data['DET_DMF']['yAngle'] = yanglec

    return csv_data
def process_nirspec_aperture(aperture, verbose=False):
    """Set aperture parameters for master apertures and FULLSCA and OSS apertures.

    Parameters
    ----------
    aperture
    verbose

    Returns
    -------

    """

    AperName = aperture.AperName

    index = siaf_aperture_definitions['AperName'].tolist().index(AperName)

    parent_aperture_name = None
    if (siaf_aperture_definitions['parent_apertures'][index] is not None) and (
            siaf_aperture_definitions['dependency_type'][index] == 'default'):
        aperture._parent_apertures = siaf_aperture_definitions[
            'parent_apertures'][index]
        parent_aperture = aperture_dict[aperture._parent_apertures]
        parent_aperture_name = parent_aperture.AperName
        for attribute in 'DetSciYAngle Sci2IdlDeg DetSciParity VIdlParity'.split(
        ):
            setattr(aperture, attribute, getattr(parent_aperture, attribute))

    polynomial_degree = 5
    aperture.Sci2IdlDeg = polynomial_degree

    if (AperName in ['NRS1_FULL', 'NRS1_FULL_OSS']) or (parent_aperture_name
                                                        == 'NRS1_FULL'):
        pcf_name = '491_GWA'
    elif (AperName in ['NRS2_FULL', 'NRS2_FULL_OSS']) or (parent_aperture_name
                                                          == 'NRS2_FULL'):
        pcf_name = '492_GWA'

    if parent_aperture_name is None:
        Xref = aperture.XDetRef
        Yref = aperture.YDetRef
    else:
        Xref = parent_aperture.XDetRef
        Yref = parent_aperture.YDetRef

    for axis in ['A', 'B']:
        # modified is _shifted or _XYflipped, see Calc worksheet Rows 8,9,10
        pcf_data[pcf_name]['{}_modified'.format(
            axis)] = polynomial.shift_coefficients(
                pcf_data[pcf_name]['{}'.format(axis)],
                Xref,
                Yref,
                verbose=False)
        if (AperName in ['NRS2_FULL']) or (parent_aperture_name
                                           == 'NRS2_FULL'):
            # Add an XY flip (The definition of the SCI frame differs from that of the DET frame,
            # therefore the polynomial coefficients are redefined so the net transformation from
            # the DET to GWA plane is the same as is obtained when the NRS2_FULL_OSS row is used.
            # see JWST-STScI-005921.)
            pcf_data[pcf_name]['{}_modified'.format(axis)] = polynomial.FlipXY(
                pcf_data[pcf_name]['{}_modified'.format(axis)])

    if 'MIMF' not in AperName:
        Xoffset = 0
        Yoffset = 0
    else:
        Xoffset = aperture.XSciRef - parent_aperture.XSciRef
        Yoffset = aperture.YSciRef - parent_aperture.YSciRef

    sci2idlx_coefficients = polynomial.shift_coefficients(
        pcf_data[pcf_name]['{}_modified'.format('A')],
        Xoffset,
        Yoffset,
        verbose=False)
    sci2idly_coefficients = polynomial.shift_coefficients(
        pcf_data[pcf_name]['{}_modified'.format('B')],
        Xoffset,
        Yoffset,
        verbose=False)

    # set polynomial coefficients for transformation that goes directly to the GWA pupil plane
    idl2sci_factor = +1
    if (AperName in ['NRS2_FULL']) or ('NRS2_FP' in AperName):
        idl2sci_factor = -1
    k = 0
    for i in range(polynomial_degree + 1):
        for j in np.arange(i + 1):
            setattr(aperture, 'Sci2IdlX{:d}{:d}'.format(i, j),
                    sci2idlx_coefficients[k])
            setattr(aperture, 'Sci2IdlY{:d}{:d}'.format(i, j),
                    sci2idly_coefficients[k])
            setattr(aperture, 'Idl2SciX{:d}{:d}'.format(i, j),
                    idl2sci_factor * pcf_data[pcf_name]['C'][k])
            setattr(aperture, 'Idl2SciY{:d}{:d}'.format(i, j),
                    idl2sci_factor * pcf_data[pcf_name]['D'][k])
            k += 1

    aperture.Idl2SciX00 = aperture.Idl2SciX00 - idl2sci_factor * aperture.XDetRef
    aperture.Idl2SciY00 = aperture.Idl2SciY00 - idl2sci_factor * aperture.YDetRef

    # get offsets from first coefficients
    Xgwa = aperture.Sci2IdlX00
    Ygwa = aperture.Sci2IdlY00

    # see Calc worksheet row 30
    Xgwa_mod = -Xgwa
    Ygwa_mod = -Ygwa

    # apply polynomial transform to XAN,YAN
    XAN = polynomial.poly(pcf_data['CLEAR_GWA_OTE']['A'],
                          Xgwa_mod,
                          Ygwa_mod,
                          order=polynomial_degree)
    YAN = polynomial.poly(pcf_data['CLEAR_GWA_OTE']['B'],
                          Xgwa_mod,
                          Ygwa_mod,
                          order=polynomial_degree)

    # convert from XAN,YAN to V2,V3 and from degree to arcsecond (e.g. Cell F32)
    aperture.V2Ref = +1 * 3600. * XAN
    aperture.V3Ref = -1 * 3600. * (YAN + V3_TO_YAN_OFFSET_DEG)

    if verbose:
        print('Xgwa, Ygwa:', Xgwa, Ygwa)
        print('Xgwa_mod, Ygwa_mod:', Xgwa_mod, Ygwa_mod)
        print('XAN, YAN:', XAN, YAN)
        print('aperture.V2Ref, aperture.V3Ref:', aperture.V2Ref,
              aperture.V3Ref)

    # derivatives
    dXAN_dXgwa = polynomial.shift_coefficients(pcf_data['CLEAR_GWA_OTE']['A'],
                                               Xgwa_mod,
                                               Ygwa_mod,
                                               verbose=False)[1]
    dXAN_dYgwa = polynomial.shift_coefficients(pcf_data['CLEAR_GWA_OTE']['A'],
                                               Xgwa_mod,
                                               Ygwa_mod,
                                               verbose=False)[2]
    dYAN_dXgwa = polynomial.shift_coefficients(pcf_data['CLEAR_GWA_OTE']['B'],
                                               Xgwa_mod,
                                               Ygwa_mod,
                                               verbose=False)[1]
    dYAN_dYgwa = polynomial.shift_coefficients(pcf_data['CLEAR_GWA_OTE']['B'],
                                               Xgwa_mod,
                                               Ygwa_mod,
                                               verbose=False)[2]

    if verbose:
        print('dXAN_dXgwa, dXAN_dYgwa:', dXAN_dXgwa, dXAN_dYgwa)
        print('dYAN_dXgwa, dYAN_dYgwa:', dYAN_dXgwa, dYAN_dYgwa)

    if parent_aperture_name is None:
        dV2_dXSci = -3600. * (dXAN_dXgwa * aperture.Sci2IdlX10 +
                              dXAN_dYgwa * aperture.Sci2IdlY10)
        dV2_dYSci = -3600. * (dXAN_dXgwa * aperture.Sci2IdlX11 +
                              dXAN_dYgwa * aperture.Sci2IdlY11)
        dV3_dXSci = 3600. * (dYAN_dXgwa * aperture.Sci2IdlX10 +
                             dYAN_dYgwa * aperture.Sci2IdlY10)
        dV3_dYSci = 3600. * (dYAN_dXgwa * aperture.Sci2IdlX11 +
                             dYAN_dYgwa * aperture.Sci2IdlY11)
    else:
        dV2_dXSci = -3600. * (dXAN_dXgwa * parent_aperture.Sci2IdlX10 +
                              dXAN_dYgwa * parent_aperture.Sci2IdlY10)
        dV2_dYSci = -3600. * (dXAN_dXgwa * parent_aperture.Sci2IdlX11 +
                              dXAN_dYgwa * parent_aperture.Sci2IdlY11)
        dV3_dXSci = 3600. * (dYAN_dXgwa * parent_aperture.Sci2IdlX10 +
                             dYAN_dYgwa * parent_aperture.Sci2IdlY10)
        dV3_dYSci = 3600. * (dYAN_dXgwa * parent_aperture.Sci2IdlX11 +
                             dYAN_dYgwa * parent_aperture.Sci2IdlY11)

    # approximate scale terms
    aperture.XSciScale = np.sqrt(dV2_dXSci**2 + dV3_dXSci**2)
    aperture.YSciScale = np.sqrt(dV2_dYSci**2 + dV3_dYSci**2)

    # compute the approximate angles
    betaY = np.rad2deg(np.arctan2(dV2_dYSci, dV3_dYSci))
    betaX = np.rad2deg(np.arctan2(dV2_dXSci, dV3_dXSci))
    if verbose:
        print('dV2_dXSci, dV2_dYSci, dV3_dXSci, dV3_dYSci:', dV2_dXSci,
              dV2_dYSci, dV3_dXSci, dV3_dYSci)
        print('betaY:', betaY)

    # set the aperture attributes
    aperture.V3SciXAngle = betaX
    aperture.V3SciYAngle = betaY
    aperture.V3IdlYAngle = aperture.V3SciYAngle

    # The usual SIAF ideal plane is completely bypassed in the target acquisition calculations.
    # In the OSS and FULLSCA rows, an ideal plane is nevertheless defined by choosing a reference
    # point near the center of each detector and using the combined TA transformations to project
    #  the detector reference points and corners onto the sky.

    # Compute aperture corners in different frames: Calc worksheep row 43
    sci_corners_x, sci_corners_y = aperture.corners('sci', rederive=True)

    # offset from reference location
    sci_corners_x -= aperture.XSciRef
    sci_corners_y -= aperture.YSciRef

    # compute GWA plane corners
    # These coefficients are name overloaded and implement the transformation to GWA plane
    gwa_coefficients_x = np.array([
        getattr(aperture, s) for s in DISTORTION_ATTRIBUTES if 'Sci2IdlX' in s
    ])
    gwa_coefficients_y = np.array([
        getattr(aperture, s) for s in DISTORTION_ATTRIBUTES if 'Sci2IdlY' in s
    ])

    gwa_corners_x = np.zeros(len(sci_corners_x))
    gwa_corners_y = np.zeros(len(sci_corners_y))

    # apply transformation to GWA plane
    for j in range(len(gwa_corners_x)):
        gwa_corners_x[j] = polynomial.poly(gwa_coefficients_x,
                                           sci_corners_x[j],
                                           sci_corners_y[j],
                                           order=aperture.Sci2IdlDeg)
        gwa_corners_y[j] = polynomial.poly(gwa_coefficients_y,
                                           sci_corners_x[j],
                                           sci_corners_y[j],
                                           order=aperture.Sci2IdlDeg)

    # compute corners in V2V3/Tel
    gwa_to_ote_coefficients_x = pcf_data['CLEAR_GWA_OTE']['A']
    gwa_to_ote_coefficients_y = pcf_data['CLEAR_GWA_OTE']['B']

    tel_corners_x = np.zeros(len(sci_corners_x))
    tel_corners_y = np.zeros(len(sci_corners_y))
    for j in range(len(gwa_corners_x)):
        tel_corners_x[j] = +3600 * polynomial.poly(gwa_to_ote_coefficients_x,
                                                   -gwa_corners_x[j],
                                                   -gwa_corners_y[j],
                                                   order=aperture.Sci2IdlDeg)
        tel_corners_y[j] = -3600 * (
            polynomial.poly(gwa_to_ote_coefficients_y,
                            -gwa_corners_x[j],
                            -gwa_corners_y[j],
                            order=aperture.Sci2IdlDeg) + V3_TO_YAN_OFFSET_DEG)

    # Ideal corners
    idl_corners_x = np.zeros(len(sci_corners_x))
    idl_corners_y = np.zeros(len(sci_corners_y))
    for j in range(len(gwa_corners_x)):
        idl_corners_x[j] = aperture.VIdlParity * (
            tel_corners_x[j] - aperture.V2Ref) * np.cos(
                np.deg2rad(aperture.V3IdlYAngle)) - aperture.VIdlParity * (
                    tel_corners_y[j] - aperture.V3Ref) * np.sin(
                        np.deg2rad(aperture.V3IdlYAngle))
        idl_corners_y[j] = (tel_corners_x[j] - aperture.V2Ref) * np.sin(
            np.deg2rad(aperture.V3IdlYAngle)) + (
                tel_corners_y[j] - aperture.V3Ref) * np.cos(
                    np.deg2rad(aperture.V3IdlYAngle))
        setattr(aperture, 'XIdlVert{}'.format(j + 1), idl_corners_x[j])
        setattr(aperture, 'YIdlVert{}'.format(j + 1), idl_corners_y[j])

    if verbose:
        print('sci_corners_x, sci_corners_y:', sci_corners_x, sci_corners_y)
        print(gwa_corners_x, gwa_corners_y)
        print(tel_corners_x, tel_corners_y)
        print(idl_corners_x, idl_corners_y)

    return aperture