def ifu_slicer2asdf(ifuslicer, outname, ref_kw):
    """
    Create an asdf reference file with the MSA description.

    ifu_slicer2asdf("IFU_slicer.sgd", "ifu_slicer.asdf")

    Parameters
    ----------
    ifuslicer : str
        A fits file with the IFU slicer description
    outname : str
        Name of output ASDF file.
    """
    f = fits.open(ifuslicer)
    tree = ref_kw.copy()
    data = f[1].data
    header = f[1].header
    shiftx = models.Shift(header['XREF'], name='ifu_slicer_xref')
    shifty = models.Shift(header['YREF'], name='ifu_slicer_yref')
    rot = models.Rotation2D(header['ROT'], name='ifu_slicer_rot')
    model = rot | shiftx & shifty
    tree['model'] = model
    tree['data'] = f[1].data
    f.close()
    fasdf = AsdfFile()
    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def ifupost2asdf(ifupost_files, outname, ref_kw):
    """
    Create a reference file of type ``ifupost`` .

    Combines all IDT ``IFU-POST`` reference files in one ASDF file.

    forward direction : MSA to Collimator
    backward_direction: Collimator to MSA

    Parameters
    ----------
    ifupost_files : list
        Names of all ``IFU-POST`` IDT reference files
    outname : str
        Name of output ``ASDF`` file
    """
    fa = AsdfFile()
    fa.tree = ref_kw
    for fifu in ifupost_files:
        n = int((fifu.split('IFU-POST_')[1]).split('.pcf')[0])
        fa.tree[n] = {}
        with open(fifu) as f:
            lines = [l.strip() for l in f.readlines()]
        factors = lines[lines.index('*Factor 2') + 1].split()
        rotation_angle = float(lines[lines.index('*Rotation') + 1])
        input_rot_center = lines[lines.index('*InputRotationCentre 2') + 1].split()
        output_rot_center = lines[lines.index('*OutputRotationCentre 2') + 1].split()
        linear_sky2det = homothetic_sky2det(input_rot_center, rotation_angle, factors, output_rot_center)

        degree = int(lines[lines.index('*FitOrder') + 1])

        xcoeff_index = lines.index('*xForwardCoefficients 21 2')
        xlines = lines[xcoeff_index + 1: xcoeff_index + 22]
        xcoeff_forward = coeffs_from_pcf(degree, xlines)
        x_poly_forward = models.Polynomial2D(degree, name='x_poly_forward', **xcoeff_forward)

        ycoeff_index = lines.index('*yForwardCoefficients 21 2')
        ycoeff_forward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
        y_poly_forward = models.Polynomial2D(degree, name='y_poly_forward', **ycoeff_forward)

        xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
        xcoeff_backward = coeffs_from_pcf(degree, lines[xcoeff_index + 1: xcoeff_index + 22])
        x_poly_backward = models.Polynomial2D(degree, name='x_poly_backward', **xcoeff_backward)

        ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
        ycoeff_backward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
        y_poly_backward = models.Polynomial2D(degree, name='y_poly_backward', **ycoeff_backward)

        output2poly_mapping = Identity(2, name='output_mapping')
        output2poly_mapping.inverse = Mapping([0, 1, 0, 1])
        input2poly_mapping = Mapping([0, 1, 0, 1], name='input_mapping')
        input2poly_mapping.inverse = Identity(2)

        model_poly = input2poly_mapping | (x_poly_forward & y_poly_forward) | output2poly_mapping

        model = linear_sky2det | model_poly
        fa.tree[n]['model'] = model
    fa.add_history_entry("Build 6")
    asdffile = fa.write_to(outname)
    return asdffile
def ifu_slicer2asdf(ifuslicer, outname, ref_kw):
    """
    Create an asdf reference file with the MSA description.

    ifu_slicer2asdf("IFU_slicer.sgd", "ifu_slicer.asdf")

    Parameters
    ----------
    ifuslicer : str
        A fits file with the IFU slicer description
    outname : str
        Name of output ASDF file.
    """
    f = fits.open(ifuslicer)
    tree = ref_kw.copy()
    data = f[1].data
    header = f[1].header
    shiftx = models.Shift(header['XREF'], name='ifu_slicer_xref')
    shifty = models.Shift(header['YREF'], name='ifu_slicer_yref')
    rot = models.Rotation2D(header['ROT'], name='ifu_slicer_rot')
    model = rot | shiftx & shifty
    tree['model'] = model
    tree['data'] = f[1].data
    f.close()
    fasdf = AsdfFile()
    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def ote2asdf(otepcf, outname, ref_kw):
    """
    ref_kw = common_reference_file_keywords('OTE', 'NIRSPEC OTE transform - CDP4')

    ote2asdf('Model/Ref_Files/CoordTransform/OTE.pcf', 'jwst_nirspec_ote_0001.asdf', ref_kw)
    """
    with open(otepcf) as f:
        lines = [l.strip() for l in f.readlines()]

    factors = lines[lines.index('*Factor 2 1') + 1].split()
    # this corresponds to modeling Rotation direction as is
    rotation_angle = float(lines[lines.index('*Rotation') + 1])
    input_rot_center = lines[lines.index('*InputRotationCentre 2 1') + 1].split()
    output_rot_center = lines[lines.index('*OutputRotationCentre 2 1') + 1].split()

    mlinear = homothetic_det2sky(input_rot_center, rotation_angle, factors, output_rot_center)

    degree = int(lines[lines.index('*FitOrder') + 1])

    xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1].split('\t')
    xcoeff_backward = coeffs_from_pcf(degree, xlines)
    x_poly_forward = models.Polynomial2D(degree, name='x_poly_forward', **xcoeff_backward)

    xcoeff_index = lines.index('*xForwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1].split('\t')
    xcoeff_forward = coeffs_from_pcf(degree, xlines)
    x_poly_backward = models.Polynomial2D(degree, name='x_poly_backward', **xcoeff_forward)

    ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
    ylines = lines[ycoeff_index + 1].split('\t')
    ycoeff_backward = coeffs_from_pcf(degree, ylines)
    y_poly_forward = models.Polynomial2D(degree, name='y_poly_forward', **ycoeff_backward)

    ycoeff_index = lines.index('*yForwardCoefficients 21 2')
    ylines = lines[ycoeff_index + 1].split('\t')
    ycoeff_forward = coeffs_from_pcf(degree, ylines)
    y_poly_backward = models.Polynomial2D(degree, name='y_poly_backward', **ycoeff_forward)

    x_poly_forward.inverse = x_poly_backward
    y_poly_forward.inverse = y_poly_backward

    output2poly_mapping = Identity(2, name='output_mapping')
    output2poly_mapping.inverse = Mapping([0, 1, 0, 1])
    input2poly_mapping = Mapping([0, 1, 0, 1], name='input_mapping')
    input2poly_mapping.inverse = Identity(2)

    model_poly = input2poly_mapping | (x_poly_forward & y_poly_forward) | output2poly_mapping

    model = model_poly | mlinear


    f = AsdfFile()
    f.tree = ref_kw.copy()
    f.tree['model'] = model
    f.add_history_entry("Build 6")
    f.write_to(outname)
    return model_poly, mlinear
Beispiel #5
0
def create_regions_file(slices, detector, band, channel, name, author,
                        useafter, description):
    tree = create_reffile_header("REGIONS", detector, band, channel, author,
                                 useafter, description)
    tree['filename'] = name
    f = AsdfFile()
    tree['regions'] = slices
    f.tree = tree
    f.add_history_entry(
        "DOCUMENT: MIRI-TN-00001-ETH; SOFTWARE: polyd2c_CDP5.pro; DATA USED: Data set of: - FM Test Campaign relevant to MRS-OPT-01, MRS-OPT-02, MRS-OPT-04, MRS-OPT-08; - CV1 Test Campaign relevant to MRS-OPT-02; - CV2 Test Campaign relevant to MRS-OPT-02; - Laboratory measurement of SPO; ============ DIFFERENCES: - New file structure: Change of Extention names and Table Column Headers.; - Replaced V2/V3 with XAN/YAN;"
    )
    f.write_to(name)
def wavelength_range(spectral_conf, outname, ref_kw):
    """
    Parameters
    ----------
    spectral_conf : str
        reference file: spectralconfigurations.txt
    outname : str
        output file name
    """
    with open(spectral_conf) as f:
        lines = f.readlines()
    lines = [l.strip() for l in lines][13:]
    lines = [l.split() for l in lines]
    tree = ref_kw.copy()
    filter_grating = {}
    for l in lines:
        f_g = l[0] + '_' + l[1]
        filter_grating[f_g] = {
            'order': int(l[2]),
            'range': [float(l[3]), float(l[4])]
        }
    tree['filter_grating'] = filter_grating
    # values in lamp_grating come from private communication with the INS team
    #lamp_grating = {}
    filter_grating['FLAT1_G140M'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['LINE1_G140M'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['FLAT1_G140H'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['LINE1_G140H'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['FLAT2_G235M'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['LINE2_G235M'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['FLAT2_G235H'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['LINE2_G235H'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['FLAT3_G395M'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['LINE3_G395M'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['FLAT3_G395H'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['LINE3_G395H'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['REF_G140M'] = {'order': -1, 'range': [1.3e-6, 1.7e-6]}
    filter_grating['REF_G140H'] = {'order': -1, 'range': [1.3e-6, 1.7e-6]}
    filter_grating['TEST_MIRROR'] = {'order': -1, 'range': [0.6e-6, 5.3e-6]}
    #for grating in ["G140H", "G140M", "G235H", "G235M", "G395H", "G395M", "MIRROR"]:
    #lamp_grating['FLAT4_{0}'.format(grating)] = {'order': -1, 'range': [0.7e-6, 1.2e-6]}
    #for grating in ["G140H", "G140M", "G235H", "G235M", "G395H", "G395M", "MIRROR"]:
    #lamp_grating['LINE4_{0}'.format(grating)] = {'order': -1, 'range': [0.6e-6, 5.3e-6]}
    #tree['lamp_grating'] = lamp_grating
    fasdf = AsdfFile()

    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def wavelength_range(spectral_conf, outname, ref_kw):
    """
    Parameters
    ----------
    spectral_conf : str
        reference file: spectralconfigurations.txt
    outname : str
        output file name
    """
    with open(spectral_conf) as f:
        lines = f.readlines()
    lines = [l.strip() for l in lines][13 :]
    lines = [l.split() for l in lines]
    tree = ref_kw.copy()
    filter_grating = {}
    for l in lines:
        f_g = l[0] + '_' + l[1]
        filter_grating[f_g] = {'order': int(l[2]), 'range': [float(l[3]), float(l[4])]}
    tree['filter_grating'] = filter_grating
    # values in lamp_grating come from private communication with the INS team
    #lamp_grating = {}
    filter_grating['FLAT1_G140M'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['LINE1_G140M'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['FLAT1_G140H'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['LINE1_G140H'] = {'order': -1, 'range': [1e-6, 1.8e-6]}
    filter_grating['FLAT2_G235M'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['LINE2_G235M'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['FLAT2_G235H'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['LINE2_G235H'] = {'order': -1, 'range': [1.7e-6, 3.1e-6]}
    filter_grating['FLAT3_G395M'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['LINE3_G395M'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['FLAT3_G395H'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['LINE3_G395H'] = {'order': -1, 'range': [2.9e-6, 5.3e-6]}
    filter_grating['REF_G140M'] = {'order': -1, 'range': [1.3e-6, 1.7e-6]}
    filter_grating['REF_G140H'] = {'order': -1, 'range': [1.3e-6, 1.7e-6]}
    filter_grating['TEST_MIRROR'] = {'order': -1, 'range': [0.6e-6, 5.3e-6]}
    #for grating in ["G140H", "G140M", "G235H", "G235M", "G395H", "G395M", "MIRROR"]:
        #lamp_grating['FLAT4_{0}'.format(grating)] = {'order': -1, 'range': [0.7e-6, 1.2e-6]}
    #for grating in ["G140H", "G140M", "G235H", "G235M", "G395H", "G395M", "MIRROR"]:
        #lamp_grating['LINE4_{0}'.format(grating)] = {'order': -1, 'range': [0.6e-6, 5.3e-6]}
    #tree['lamp_grating'] = lamp_grating
    fasdf = AsdfFile()

    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
Beispiel #8
0
def create_wavelengthrange_file(name, detector, author, useafter, description):
    f = AsdfFile()

    # Relaxing the range to match the distortion. The table above
    # comes from the report and is "as designed".
    wavelengthrange = {
        '1SHORT': (4.68, 5.97),
        '1MEDIUM': (5.24, 6.87),
        '1LONG': (6.2, 7.90),
        '2SHORT': (7.27, 9.03),
        '2MEDIUM': (8.43, 10.39),
        '2LONG': (9.76, 11.97),
        '3SHORT': (11.29, 13.75),
        '3MEDIUM': (13.08, 15.86),
        '3LONG': (15.14, 18.29),
        '4SHORT': (17.40, 21.20),
        '4MEDIUM': (20.31, 24.68),
        '4LONG': (23.72, 28.75)
    }
    channels = [
        '1SHORT', '1MEDIUM', '1LONG', '2SHORT', '2MEDIUM', '2LONG', '3SHORT',
        '3MEDIUM', '3LONG', '4SHORT', '4MEDIUM', '4LONG'
    ]

    tree = create_reffile_header("WAVELENGTHRANGE",
                                 detector,
                                 band="N/A",
                                 channel="N/A",
                                 author=author,
                                 useafter=useafter,
                                 description=description)
    tree['filename'] = name
    tree['author'] = 'Nadia Dencheva'
    tree['detector'] = "N/A"
    tree['channels'] = channels

    f.tree = tree
    vr = np.empty((12, 2), dtype=np.float)
    for i, ch in enumerate(channels):
        vr[i] = wavelengthrange[ch]
    f.tree['wavelengthrange'] = vr
    f.add_history_entry(
        "DOCUMENT: MIRI-TN-00001-ETH; SOFTWARE: polyd2c_CDP5.pro; DATA USED: Data set of: - FM Test Campaign relevant to MRS-OPT-01, MRS-OPT-02, MRS-OPT-04, MRS-OPT-08; - CV1 Test Campaign relevant to MRS-OPT-02; - CV2 Test Campaign relevant to MRS-OPT-02; - Laboratory measurement of SPO; ============ DIFFERENCES: - New file structure: Change of Extention names and Table Column Headers.; - Replaced V2/V3 with XAN/YAN;"
    )
    f.write_to(name)
Beispiel #9
0
def create_distortion_file(reftype, detector, band, channel, data, name,
                           author, useafter, description):

    description = 'MIRI MRS Distortion Maps'
    tree = create_reffile_header(reftype, detector, band, channel, author,
                                 useafter, description)
    tree['filename'] = name
    adata, bdata, xdata, ydata, bzero, bdel = data
    tree['alpha_model'] = adata
    tree['beta_model'] = bdata
    tree['x_model'] = xdata
    tree['y_model'] = ydata
    tree['bzero'] = bzero
    tree['bdel'] = bdel

    f = AsdfFile()
    f.tree = tree
    f.add_history_entry(
        "DOCUMENT: MIRI-TN-00001-ETH; SOFTWARE: polyd2c_CDP5.pro; DATA USED: Data set of: - FM Test Campaign relevant to MRS-OPT-01, MRS-OPT-02, MRS-OPT-04, MRS-OPT-08; - CV1 Test Campaign relevant to MRS-OPT-02; - CV2 Test Campaign relevant to MRS-OPT-02; - Laboratory measurement of SPO; ============ DIFFERENCES: - New file structure: Change of Extention names and Table Column Headers.; - Replaced V2/V3 with XAN/YAN;"
    )
    f.write_to(name)
def msa2asdf(msafile, outname, ref_kw):
    """
    Create an asdf reference file with the MSA description.

    mas2asfdf("MSA.msa", "msa.asdf")

    Parameters
    ----------
    msafile : str
        A fits file with MSA description (MSA.msa)
    outname : str
        Name of output ASDF file.
    """
    f = fits.open(msafile)
    tree = ref_kw.copy()
    data = f[5].data  # SLITS and IFU
    header = f[5].header
    shiftx = models.Shift(header['SLITXREF'], name='slit_xref')
    shifty = models.Shift(header['SLITYREF'], name='slit_yref')
    slitrot = models.Rotation2D(header['SLITROT'], name='slit_rot')

    tree[5] = {}
    tree[5]['model'] = slitrot | shiftx & shifty
    tree[5]['data'] = f[5].data
    for i in range(1, 5):
        header = f[i].header
        shiftx = models.Shift(header['QUADXREF'], name='msa_xref')
        shifty = models.Shift(header['QUADYREF'], name='msa_yref')
        slitrot = models.Rotation2D(header['QUADROT'], name='msa_rot')
        tree[i] = {}
        tree[i]['model'] = slitrot | shiftx & shifty
        tree[i]['data'] = f[i].data

    f.close()
    fasdf = AsdfFile()
    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def msa2asdf(msafile, outname, ref_kw):
    """
    Create an asdf reference file with the MSA description.

    mas2asfdf("MSA.msa", "msa.asdf")

    Parameters
    ----------
    msafile : str
        A fits file with MSA description (MSA.msa)
    outname : str
        Name of output ASDF file.
    """
    f = fits.open(msafile)
    tree = ref_kw.copy()
    data = f[5].data # SLITS and IFU
    header = f[5].header
    shiftx = models.Shift(header['SLITXREF'], name='slit_xref')
    shifty = models.Shift(header['SLITYREF'], name='slit_yref')
    slitrot = models.Rotation2D(header['SLITROT'], name='slit_rot')

    tree[5] = {}
    tree[5]['model'] = slitrot | shiftx & shifty
    tree[5]['data'] = f[5].data
    for i in range(1, 5):
        header = f[i].header
        shiftx = models.Shift(header['QUADXREF'], name='msa_xref')
        shifty = models.Shift(header['QUADYREF'], name='msa_yref')
        slitrot = models.Rotation2D(header['QUADROT'], name='msa_rot')
        tree[i] = {}
        tree[i]['model'] = slitrot | shiftx & shifty
        tree[i]['data'] = f[i].data

    f.close()
    fasdf = AsdfFile()
    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
Beispiel #12
0
def create_v23(reftype, detector, band, channels, data, name, author, useafter,
               description):
    """
    Create the transform from MIRI Local to telescope V2/V3 system for all channels.
    """
    channel = "".join([ch[0] for ch in channels])
    tree = create_reffile_header(reftype, detector, band, channel, author,
                                 useafter, description)
    """
    tree = {"detector": detector,
            "instrument" : "MIRI",
            "band": band,
            "channel": channel,
            "exp_type": "MIR_MRS",
            "pedigree": "GROUND",
            "title": "MIRI IFU model - based on CDP-4",
            "reftype": reftype,
            "author": author,
            "useafter": useafter,
            "description": description
            }
    """
    tree['filename'] = name
    ab_v23 = data[0]
    v23_ab = data[1]
    m = {}
    c0_0, c0_1, c1_0, c1_1 = ab_v23[0][1:]
    ch1_v2 = models.Polynomial2D(2,
                                 c0_0=c0_0,
                                 c1_0=c1_0,
                                 c0_1=c0_1,
                                 c1_1=c1_1,
                                 name="ab_v23")
    c0_0, c0_1, c1_0, c1_1 = v23_ab[0][1:]
    ch1_a = models.Polynomial2D(2,
                                c0_0=c0_0,
                                c1_0=c1_0,
                                c0_1=c0_1,
                                c1_1=c1_1,
                                name="v23_ab")

    c0_0, c0_1, c1_0, c1_1 = ab_v23[1][1:]
    ch1_v3 = models.Polynomial2D(2,
                                 c0_0=c0_0,
                                 c1_0=c1_0,
                                 c0_1=c0_1,
                                 c1_1=c1_1,
                                 name="ab_v23")
    c0_0, c0_1, c1_0, c1_1 = v23_ab[1][1:]
    ch1_b = models.Polynomial2D(2,
                                c0_0=c0_0,
                                c1_0=c1_0,
                                c0_1=c0_1,
                                c1_1=c1_1,
                                name="v23_ab")
    c0_0, c0_1, c1_0, c1_1 = ab_v23[2][1:]
    ch2_v2 = models.Polynomial2D(2,
                                 c0_0=c0_0,
                                 c1_0=c1_0,
                                 c0_1=c0_1,
                                 c1_1=c1_1,
                                 name="ab_v23")
    c0_0, c0_1, c1_0, c1_1 = v23_ab[2][1:]
    ch2_a = models.Polynomial2D(2,
                                c0_0=c0_0,
                                c1_0=c1_0,
                                c0_1=c0_1,
                                c1_1=c1_1,
                                name="v23_ab")

    c0_0, c0_1, c1_0, c1_1 = ab_v23[3][1:]
    ch2_v3 = models.Polynomial2D(2,
                                 c0_0=c0_0,
                                 c1_0=c1_0,
                                 c0_1=c0_1,
                                 c1_1=c1_1,
                                 name="ab_v23")
    c0_0, c0_1, c1_0, c1_1 = v23_ab[3][1:]
    ch2_b = models.Polynomial2D(2,
                                c0_0=c0_0,
                                c1_0=c1_0,
                                c0_1=c0_1,
                                c1_1=c1_1,
                                name="v23_ab")
    ch1_for = ch1_v2 & ch1_v3
    ch2_for = ch2_v2 & ch2_v3
    ch1_for.inverse = ch1_a & ch1_b
    ch2_for.inverse = ch2_a & ch2_b
    m[channels[0]] = ch1_for
    m[channels[1]] = ch2_for
    tree['model'] = m

    f = AsdfFile()
    f.tree = tree
    f.add_history_entry(
        "DOCUMENT: MIRI-TN-00001-ETH; SOFTWARE: polyd2c_CDP5.pro; DATA USED: Data set of: - FM Test Campaign relevant to MRS-OPT-01, MRS-OPT-02, MRS-OPT-04, MRS-OPT-08; - CV1 Test Campaign relevant to MRS-OPT-02; - CV2 Test Campaign relevant to MRS-OPT-02; - Laboratory measurement of SPO; ============ DIFFERENCES: - New file structure: Change of Extention names and Table Column Headers.; - Replaced V2/V3 with XAN/YAN;"
    )
    f.write_to(name)
def ote2asdf(otepcf, outname, ref_kw):
    """
    ref_kw = common_reference_file_keywords('OTE', 'NIRSPEC OTE transform - CDP4')

    ote2asdf('Model/Ref_Files/CoordTransform/OTE.pcf', 'jwst_nirspec_ote_0001.asdf', ref_kw)
    """
    with open(otepcf) as f:
        lines = [l.strip() for l in f.readlines()]

    factors = lines[lines.index('*Factor 2 1') + 1].split()
    # this corresponds to modeling Rotation direction as is
    rotation_angle = float(lines[lines.index('*Rotation') + 1])
    input_rot_center = lines[lines.index('*InputRotationCentre 2 1') +
                             1].split()
    output_rot_center = lines[lines.index('*OutputRotationCentre 2 1') +
                              1].split()

    mlinear = homothetic_det2sky(input_rot_center, rotation_angle, factors,
                                 output_rot_center)

    degree = int(lines[lines.index('*FitOrder') + 1])

    xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1].split('\t')
    xcoeff_backward = coeffs_from_pcf(degree, xlines)
    x_poly_forward = models.Polynomial2D(degree,
                                         name='x_poly_forward',
                                         **xcoeff_backward)

    xcoeff_index = lines.index('*xForwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1].split('\t')
    xcoeff_forward = coeffs_from_pcf(degree, xlines)
    x_poly_backward = models.Polynomial2D(degree,
                                          name='x_poly_backward',
                                          **xcoeff_forward)

    ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
    ylines = lines[ycoeff_index + 1].split('\t')
    ycoeff_backward = coeffs_from_pcf(degree, ylines)
    y_poly_forward = models.Polynomial2D(degree,
                                         name='y_poly_forward',
                                         **ycoeff_backward)

    ycoeff_index = lines.index('*yForwardCoefficients 21 2')
    ylines = lines[ycoeff_index + 1].split('\t')
    ycoeff_forward = coeffs_from_pcf(degree, ylines)
    y_poly_backward = models.Polynomial2D(degree,
                                          name='y_poly_backward',
                                          **ycoeff_forward)

    x_poly_forward.inverse = x_poly_backward
    y_poly_forward.inverse = y_poly_backward

    output2poly_mapping = Identity(2, name='output_mapping')
    output2poly_mapping.inverse = Mapping([0, 1, 0, 1])
    input2poly_mapping = Mapping([0, 1, 0, 1], name='input_mapping')
    input2poly_mapping.inverse = Identity(2)

    model_poly = input2poly_mapping | (x_poly_forward
                                       & y_poly_forward) | output2poly_mapping

    model = model_poly | mlinear

    f = AsdfFile()
    f.tree = ref_kw.copy()
    f.tree['model'] = model
    f.add_history_entry("Build 6")
    f.write_to(outname)
    return model_poly, mlinear
def fpa2asdf(fpafile, outname, ref_kw):
    """
    Create an asdf reference file with the FPA description.

    The CDP2 delivery includes a fits file - "FPA.fpa" which is the
    input to this function. This file is converted to asdf and is a
    reference file of type "FPA".

    nirspec_fs_ref_tools.fpa2asdf('Ref_Files/CoordTransform/Description/FPA.fpa', 'fpa.asdf')

    Parameters
    ----------
    fpafile : str
        A fits file with FPA description (FPA.fpa)
    outname : str
        Name of output ASDF file.
    """
    with open(fpafile) as f:
        lines = [l.strip() for l in f.readlines()]

    # NRS1
    ind = lines.index("*SCA491_PitchX")
    nrs1_pitchx = float(lines[ind + 1])
    ind = lines.index("*SCA491_PitchY")
    nrs1_pitchy = float(lines[ind + 1])
    ind = lines.index("*SCA491_RotAngle")
    nrs1_angle = float(lines[ind + 1])
    ind = lines.index("*SCA491_PosX")
    nrs1_posx = float(lines[ind + 1])
    ind = lines.index("*SCA491_PosY")
    nrs1_posy = float(lines[ind + 1])

    # NRS2
    ind = lines.index("*SCA492_PitchX")
    nrs2_pitchx = float(lines[ind + 1])
    ind = lines.index("*SCA492_PitchY")
    nrs2_pitchy = float(lines[ind + 1])
    ind = lines.index("*SCA492_RotAngle")
    nrs2_angle = float(lines[ind + 1])
    ind = lines.index("*SCA492_PosX")
    nrs2_posx = float(lines[ind + 1])
    ind = lines.index("*SCA492_PosY")
    nrs2_posy = float(lines[ind + 1])

    tree = ref_kw.copy()

    # NRS1 Sky to Detector
    scaling = np.array([[1 / nrs1_pitchx, 0], [0, 1 / nrs1_pitchy]])
    rotmat = models.Rotation2D._compute_matrix(-nrs1_angle)
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_sky2detector')
    nrs1_sky2det = models.Shift(-nrs1_posx, name='fpa_shift_x') & \
                 models.Shift(-nrs1_posy, name='fpa_shift_y') | aff

    # NRS1 Detector to Sky
    rotmat = models.Rotation2D._compute_matrix(-nrs1_angle)
    scaling = np.array([[nrs1_pitchx, 0], [0, nrs1_pitchy]])
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_detector2sky')
    nrs1_det2sky = aff | models.Shift(nrs1_posx, name='fpa_shift_x_det2sky') & \
                 models.Shift(nrs1_posy, name='fpa_shift_y_det2sky')

    nrs1_det2sky.inverse = nrs1_sky2det

    # NRS2 Sky to Detector
    scaling = np.array([[-1 / nrs2_pitchx, 0], [0, -1 / nrs2_pitchy]])
    rotmat = models.Rotation2D._compute_matrix(-nrs2_angle)
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_sky2detector')
    nrs2_sky2det = models.Shift(-nrs2_posx, name='fpa_shixft_x') & \
                 models.Shift(-nrs2_posy, name='fpa_shift_y') | aff

    # NRS2 Detector to Sky
    rotmat = models.Rotation2D._compute_matrix(nrs2_angle)
    scaling = np.array([[-nrs2_pitchx, 0], [0, -nrs2_pitchy]])
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_detector2sky')
    nrs2_det2sky = aff | models.Shift(nrs2_posx, name='fpa_shift_x_det2sky') & \
                 models.Shift(nrs2_posy, name='fpa_shift_y_det2sky')

    nrs2_det2sky.inverse = nrs2_sky2det

    tree['NRS1'] = nrs1_det2sky
    tree['NRS2'] = nrs2_det2sky
    fasdf = AsdfFile()
    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def fore2asdf(pcffore, outname, ref_kw):
    """
    forward direction : msa 2 ote
    backward_direction: msa 2 fpa

    """
    with open(pcffore) as f:
        lines = [l.strip() for l in f.readlines()]

    fore_det2sky = linear_from_pcf_det2sky(pcffore)
    fore_linear = fore_det2sky
    fore_linear.inverse = fore_det2sky.inverse & Identity(1)

    # compute the polynomial
    degree = int(lines[lines.index('*FitOrder') + 1])

    xcoeff_index = lines.index('*xForwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1: xcoeff_index + 22]
    xcoeff_forward = coeffs_from_pcf(degree, xlines)
    # Polynomial Correction in x
    x_poly_backward = models.Polynomial2D(degree, name="x_poly_backward", **xcoeff_forward)
    xlines_distortion = lines[xcoeff_index + 22: xcoeff_index + 43]
    xcoeff_forward_distortion = coeffs_from_pcf(degree, xlines_distortion)
    x_poly_backward_distortion = models.Polynomial2D(degree, name="x_backward_distortion",
                                                     **xcoeff_forward_distortion)
    # do chromatic correction
    # the input is Xote, Yote, lam
    model_x_backward = (Mapping((0, 1), n_inputs=3) | x_poly_backward) + \
                     ((Mapping((0,1), n_inputs=3) | x_poly_backward_distortion) * \
                     (Mapping((2,)) | Identity(1)))

    ycoeff_index = lines.index('*yForwardCoefficients 21 2')
    ycoeff_forward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
    y_poly_backward = models.Polynomial2D(degree, name="y_poly_backward",  **ycoeff_forward)

    ylines_distortion = lines[ycoeff_index + 22: ycoeff_index + 43]
    ycoeff_forward_distortion = coeffs_from_pcf(degree, ylines_distortion)
    y_poly_backward_distortion = models.Polynomial2D(degree, name="y_backward_distortion",
                                                     **ycoeff_forward_distortion)

    # do chromatic correction
    # the input is Xote, Yote, lam
    model_y_backward = (Mapping((0,1), n_inputs=3) | y_poly_backward) + \
                     ((Mapping((0, 1), n_inputs=3) | y_poly_backward_distortion) * \
                     (Mapping((2,)) | Identity(1) ))

    xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
    xcoeff_backward = coeffs_from_pcf(degree, lines[xcoeff_index + 1: xcoeff_index + 22])
    x_poly_forward = models.Polynomial2D(degree,name="x_poly_forward", **xcoeff_backward)

    xcoeff_backward_distortion = coeffs_from_pcf(degree, lines[xcoeff_index + 22: xcoeff_index + 43])
    x_poly_forward_distortion = models.Polynomial2D(degree, name="x_forward_distortion", **xcoeff_backward_distortion)

    # the chromatic correction is done here
    # the input is Xmsa, Ymsa, lam
    model_x_forward = (Mapping((0,1), n_inputs=3) | x_poly_forward) + \
                    ((Mapping((0,1), n_inputs=3) | x_poly_forward_distortion) * \
                    (Mapping((2,)) | Identity(1)))

    ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
    ycoeff_backward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
    y_poly_forward = models.Polynomial2D(degree, name="y_poly_forward",**ycoeff_backward)

    ycoeff_backward_distortion = coeffs_from_pcf(degree, lines[ycoeff_index + 22: ycoeff_index + 43])
    y_poly_forward_distortion = models.Polynomial2D(degree, name="y_forward_distortion",
                                                    **ycoeff_backward_distortion)

    # do chromatic correction
    # the input is Xmsa, Ymsa, lam
    model_y_forward = (Mapping((0,1), n_inputs=3) | y_poly_forward) + \
                    ((Mapping((0,1), n_inputs=3) | y_poly_forward_distortion) * \
                    (Mapping((2,)) | Identity(1)))

    #assign inverse transforms
    model_x = model_x_forward.copy()
    model_y = model_y_forward.copy()

    model_x.inverse = model_x_backward
    model_y.inverse = model_y_backward

    output2poly_mapping = Identity(2, name="output_mapping")
    output2poly_mapping.inverse = Mapping([0, 1, 2, 0, 1, 2])
    input2poly_mapping = Mapping([0, 1, 2, 0, 1, 2], name="input_mapping")
    input2poly_mapping.inverse = Identity(2)

    model_poly = input2poly_mapping  | (model_x & model_y) | output2poly_mapping


    model = model_poly | fore_linear

    f = AsdfFile()
    f.tree = ref_kw.copy()
    f.tree['model'] = model
    f.add_history_entry("Build 6")
    asdffile = f.write_to(outname)
    return asdffile
def disperser2asdf(disfile, tiltyfile, tiltxfile, outname, ref_kw):
    """
    Create a NIRSPEC disperser reference file in ASDF format.

    Combine information stored in disperser_G?.dis and disperser_G?_TiltY.gtp
    files delievred by the IDT.

    disperser2asdf("disperser_G140H.dis", "disperser_G140H_TiltY.gtp", "disperserG140H.asdf")

    Parameters
    ----------
    disfile : list or str
        A list of .dis files or a wild card string (*.dis).
    tiltyfile : str
        File with tilt_Y data, e.g. disperser_G395H_TiltY.gtp.
    outname : str
        Name of output ASDF file.

    Returns
    -------
    fasdf : asdf.AsdfFile

    """

    disperser = disfile.split('.dis')[0].split('_')[1]
    with open(disfile) as f:
        lines = [l.strip() for l in f.readlines()]

    try:
        ind = lines.index('*TYPE')
        disperser_type = (lines[ind + 1]).lower()
    except ValueError:
        raise ValueError("Unknown disperser type in {0}".format(disfile))

    if disperser_type == 'gratingdata':
        d = dict.fromkeys(
            ['groove_density', 'theta_z', 'theta_y', 'theta_x', 'tilt_y'])
    elif disperser_type == 'prismdata':
        d = dict.fromkeys([
            'tref', 'pref', 'angle', 'coefformula', 'thermalcoef', 'wbound'
            'theta_z', 'theta_y', 'theta_x', 'tilt_y'
        ])

    d.update(ref_kw)
    try:
        ind = lines.index('*GRATINGNAME')
        grating_name = lines[ind + 1]
    except ValueError:
        grating_name = 'PRISM'

    #for line in lines:
    ind = lines.index('*THETAZ')
    d['theta_z'] = float(lines[ind + 1]) / 3600.  # in degrees
    ind = lines.index('*THETAX')
    d['theta_x'] = float(lines[ind + 1]) / 3600.  # in degrees
    ind = lines.index('*THETAY')
    d['theta_y'] = float(lines[ind + 1]) / 3600.  # in degrees
    ind = lines.index('*TILTY')
    d['tilt_y'] = float(lines[ind + 1])  # in degrees
    try:
        ind = lines.index('*TILTX')
        d['tilt_x'] = float(lines[ind + 1])  # in degrees
    except ValueError:
        d['tilt_x'] = 0.0

    if disperser_type == 'gratingdata':
        ind = lines.index('*GROOVEDENSITY')
        d['groove_density'] = float(lines[ind + 1])
    elif disperser_type == 'prismdata':
        ind = lines.index('*ANGLE')
        d['angle'] = float(lines[ind + 1])  # in degrees

        ind = lines.index('*TREF')
        d['tref'] = float(lines[ind + 1])  # Temperature in K

        ind = lines.index('*PREF')
        d['pref'] = float(lines[ind + 1])  # Pressure in ATM

        ind = lines.index('*COEFFORMULA')
        coefs = np.array(lines[ind:ind + int(l[-1])], dtype=np.float)
        kcoef = coefs[::2]
        lcoef = coefs[1::2]
        d['lcoef'] = lcoef
        d['kcoef'] = kcoef

        # 6 coeffs - D0, D1, D2, E0, E1, lambdak
        ind = lines.index('*THERMALCOEF')
        coefs = lines[ind:ind + int(l[-1])]
        d['tcoef'] = [float(c) for c in coefs]

        ind = lines.index('*WBOUND')
        coefs = lines[ind:ind + 2]
        d['wbound'] = [float(c) for c in coefs]

    assert grating_name in tiltyfile
    assert grating_name in tiltxfile
    tiltyd = disperser_tilt(tiltyfile)
    tiltxd = disperser_tilt(tiltxfile)

    d['gwa_tiltx'] = tiltyd
    d['gwa_tilty'] = tiltxd
    fasdf = AsdfFile()
    fasdf.tree = d
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def fore2asdf(pcffore, outname, ref_kw):
    """
    forward direction : msa 2 ote
    backward_direction: msa 2 fpa

    """
    with open(pcffore) as f:
        lines = [l.strip() for l in f.readlines()]

    fore_det2sky = linear_from_pcf_det2sky(pcffore)
    fore_linear = fore_det2sky
    fore_linear.inverse = fore_det2sky.inverse & Identity(1)

    # compute the polynomial
    degree = int(lines[lines.index('*FitOrder') + 1])

    xcoeff_index = lines.index('*xForwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1:xcoeff_index + 22]
    xcoeff_forward = coeffs_from_pcf(degree, xlines)
    # Polynomial Correction in x
    x_poly_backward = models.Polynomial2D(degree,
                                          name="x_poly_backward",
                                          **xcoeff_forward)
    xlines_distortion = lines[xcoeff_index + 22:xcoeff_index + 43]
    xcoeff_forward_distortion = coeffs_from_pcf(degree, xlines_distortion)
    x_poly_backward_distortion = models.Polynomial2D(
        degree, name="x_backward_distortion", **xcoeff_forward_distortion)
    # do chromatic correction
    # the input is Xote, Yote, lam
    model_x_backward = (Mapping((0, 1), n_inputs=3) | x_poly_backward) + \
                     ((Mapping((0,1), n_inputs=3) | x_poly_backward_distortion) * \
                     (Mapping((2,)) | Identity(1)))

    ycoeff_index = lines.index('*yForwardCoefficients 21 2')
    ycoeff_forward = coeffs_from_pcf(degree,
                                     lines[ycoeff_index + 1:ycoeff_index + 22])
    y_poly_backward = models.Polynomial2D(degree,
                                          name="y_poly_backward",
                                          **ycoeff_forward)

    ylines_distortion = lines[ycoeff_index + 22:ycoeff_index + 43]
    ycoeff_forward_distortion = coeffs_from_pcf(degree, ylines_distortion)
    y_poly_backward_distortion = models.Polynomial2D(
        degree, name="y_backward_distortion", **ycoeff_forward_distortion)

    # do chromatic correction
    # the input is Xote, Yote, lam
    model_y_backward = (Mapping((0,1), n_inputs=3) | y_poly_backward) + \
                     ((Mapping((0, 1), n_inputs=3) | y_poly_backward_distortion) * \
                     (Mapping((2,)) | Identity(1) ))

    xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
    xcoeff_backward = coeffs_from_pcf(
        degree, lines[xcoeff_index + 1:xcoeff_index + 22])
    x_poly_forward = models.Polynomial2D(degree,
                                         name="x_poly_forward",
                                         **xcoeff_backward)

    xcoeff_backward_distortion = coeffs_from_pcf(
        degree, lines[xcoeff_index + 22:xcoeff_index + 43])
    x_poly_forward_distortion = models.Polynomial2D(
        degree, name="x_forward_distortion", **xcoeff_backward_distortion)

    # the chromatic correction is done here
    # the input is Xmsa, Ymsa, lam
    model_x_forward = (Mapping((0,1), n_inputs=3) | x_poly_forward) + \
                    ((Mapping((0,1), n_inputs=3) | x_poly_forward_distortion) * \
                    (Mapping((2,)) | Identity(1)))

    ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
    ycoeff_backward = coeffs_from_pcf(
        degree, lines[ycoeff_index + 1:ycoeff_index + 22])
    y_poly_forward = models.Polynomial2D(degree,
                                         name="y_poly_forward",
                                         **ycoeff_backward)

    ycoeff_backward_distortion = coeffs_from_pcf(
        degree, lines[ycoeff_index + 22:ycoeff_index + 43])
    y_poly_forward_distortion = models.Polynomial2D(
        degree, name="y_forward_distortion", **ycoeff_backward_distortion)

    # do chromatic correction
    # the input is Xmsa, Ymsa, lam
    model_y_forward = (Mapping((0,1), n_inputs=3) | y_poly_forward) + \
                    ((Mapping((0,1), n_inputs=3) | y_poly_forward_distortion) * \
                    (Mapping((2,)) | Identity(1)))

    #assign inverse transforms
    model_x = model_x_forward.copy()
    model_y = model_y_forward.copy()

    model_x.inverse = model_x_backward
    model_y.inverse = model_y_backward

    output2poly_mapping = Identity(2, name="output_mapping")
    output2poly_mapping.inverse = Mapping([0, 1, 2, 0, 1, 2])
    input2poly_mapping = Mapping([0, 1, 2, 0, 1, 2], name="input_mapping")
    input2poly_mapping.inverse = Identity(2)

    model_poly = input2poly_mapping | (model_x & model_y) | output2poly_mapping

    model = model_poly | fore_linear

    f = AsdfFile()
    f.tree = ref_kw.copy()
    f.tree['model'] = model
    f.add_history_entry("Build 6")
    asdffile = f.write_to(outname)
    return asdffile
def pcf2asdf(pcffile, outname, ref_file_kw):
    """
    Create an asdf reference file with the transformation coded in a NIRSPEC
    Camera.pcf or Collimator*.pcf file.

    - forward (team): sky to detector
      - Shift inputs to input_rotation_center
      - Rotate inputs
      - Scale  inputs
      - Shift inputs to output_rot_center
      - Apply polynomial distortion
    - backward_team (team definition) detector to sky
      - Apply polynomial distortion
      - Shift inputs to output_rot_center
      - Scale  inputs
      - Rotate inputs
      - Shift inputs to input_rotation_center

    WCS implementation
    - forward: detector to sky
      - equivalent to backward_team
    - backward: sky to detector
      - equivalent to forward_team

    Parameters
    ----------
    pcffile : str
        one of the NIRSPEC ".pcf" reference files provided by the IDT team.
        "pcf" stands for "polynomial coefficients fit"
    outname : str
        Name of reference file to be wriiten to disk.

    Returns
    -------
    fasdf : AsdfFile
        AsdfFile object

    Examples
    --------
    >>> pcf2asdf("Camera.pcf", "camera.asdf")

    """
    linear_det2sky = linear_from_pcf_det2sky(pcffile)

    with open(pcffile) as f:
        lines = [l.strip() for l in f.readlines()]

    degree = int(lines[lines.index('*FitOrder') + 1])

    xcoeff_index = lines.index('*xForwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1:xcoeff_index + 22]
    xcoeff_forward = coeffs_from_pcf(degree, xlines)
    x_poly_backward = models.Polynomial2D(degree,
                                          name='x_poly_backward',
                                          **xcoeff_forward)

    ycoeff_index = lines.index('*yForwardCoefficients 21 2')
    ycoeff_forward = coeffs_from_pcf(degree,
                                     lines[ycoeff_index + 1:ycoeff_index + 22])
    y_poly_backward = models.Polynomial2D(degree,
                                          name='y_poly_backward',
                                          **ycoeff_forward)

    xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
    xcoeff_backward = coeffs_from_pcf(
        degree, lines[xcoeff_index + 1:xcoeff_index + 22])
    x_poly_forward = models.Polynomial2D(degree,
                                         name='x_poly_forward',
                                         **xcoeff_backward)

    ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
    ycoeff_backward = coeffs_from_pcf(
        degree, lines[ycoeff_index + 1:ycoeff_index + 22])
    y_poly_forward = models.Polynomial2D(degree,
                                         name='y_poly_forward',
                                         **ycoeff_backward)

    x_poly_forward.inverse = x_poly_backward
    y_poly_forward.inverse = y_poly_backward

    output2poly_mapping = Identity(2, name='output_mapping')
    output2poly_mapping.inverse = Mapping([0, 1, 0, 1])
    input2poly_mapping = Mapping([0, 1, 0, 1], name='input_mapping')
    input2poly_mapping.inverse = Identity(2)

    model_poly = input2poly_mapping | (x_poly_forward
                                       & y_poly_forward) | output2poly_mapping

    model = model_poly | linear_det2sky

    f = AsdfFile()
    f.tree = ref_file_kw.copy()
    f.add_history_entry("Build 6")
    f.tree['model'] = model
    f.write_to(outname)
def disperser2asdf(disfile, tiltyfile, tiltxfile, outname, ref_kw):
    """
    Create a NIRSPEC disperser reference file in ASDF format.

    Combine information stored in disperser_G?.dis and disperser_G?_TiltY.gtp
    files delievred by the IDT.

    disperser2asdf("disperser_G140H.dis", "disperser_G140H_TiltY.gtp", "disperserG140H.asdf")

    Parameters
    ----------
    disfile : list or str
        A list of .dis files or a wild card string (*.dis).
    tiltyfile : str
        File with tilt_Y data, e.g. disperser_G395H_TiltY.gtp.
    outname : str
        Name of output ASDF file.

    Returns
    -------
    fasdf : asdf.AsdfFile

    """

    disperser = disfile.split('.dis')[0].split('_')[1]
    with open(disfile) as f:
        lines=[l.strip() for l in f.readlines()]

    try:
        ind = lines.index('*TYPE')
        disperser_type = (lines[ind + 1]).lower()
    except ValueError:
        raise ValueError("Unknown disperser type in {0}".format(disfile))

    if disperser_type == 'gratingdata':
        d = dict.fromkeys(['groove_density', 'theta_z', 'theta_y', 'theta_x', 'tilt_y'])
    elif disperser_type == 'prismdata':
        d = dict.fromkeys(['tref', 'pref', 'angle', 'coefformula', 'thermalcoef', 'wbound'
                           'theta_z', 'theta_y', 'theta_x', 'tilt_y'])

    d.update(ref_kw)
    try:
        ind = lines.index('*GRATINGNAME')
        grating_name = lines[ind + 1]
    except ValueError:
        grating_name = 'PRISM'

    #for line in lines:
    ind = lines.index('*THETAZ')
    d['theta_z'] = float(lines[ind + 1]) / 3600. # in degrees
    ind = lines.index('*THETAX')
    d['theta_x'] = float(lines[ind + 1]) / 3600. # in degrees
    ind = lines.index('*THETAY')
    d['theta_y'] = float(lines[ind + 1]) / 3600. # in degrees
    ind = lines.index('*TILTY')
    d['tilt_y'] = float(lines[ind + 1]) # in degrees
    try:
        ind = lines.index('*TILTX')
        d['tilt_x'] = float(lines[ind + 1]) # in degrees
    except ValueError:
        d['tilt_x'] = 0.0

    if disperser_type == 'gratingdata':
        ind = lines.index('*GROOVEDENSITY')
        d['groove_density'] = float(lines[ind + 1])
    elif disperser_type == 'prismdata':
        ind = lines.index('*ANGLE')
        d['angle'] = float(lines[ind + 1]) # in degrees

        ind = lines.index('*TREF')
        d['tref'] = float(lines[ind + 1]) # Temperature in K

        ind = lines.index('*PREF')
        d['pref'] = float(lines[ind + 1]) # Pressure in ATM

        ind = lines.index('*COEFFORMULA')
        coefs = np.array(lines[ind : ind+int(l[-1])], dtype=np.float)
        kcoef = coefs[::2]
        lcoef = coefs[1::2]
        d['lcoef'] = lcoef
        d['kcoef'] = kcoef

        # 6 coeffs - D0, D1, D2, E0, E1, lambdak
        ind = lines.index('*THERMALCOEF')
        coefs = lines[ind : ind+int(l[-1])]
        d['tcoef'] = [float(c) for c in coefs]

        ind = lines.index('*WBOUND')
        coefs = lines[ind : ind + 2]
        d['wbound'] = [float(c) for c in coefs]

    assert grating_name in tiltyfile
    assert grating_name in tiltxfile
    tiltyd = disperser_tilt(tiltyfile)
    tiltxd = disperser_tilt(tiltxfile)

    d['gwa_tiltx'] = tiltyd
    d['gwa_tilty'] = tiltxd
    fasdf = AsdfFile()
    fasdf.tree = d
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def pcf2asdf(pcffile, outname, ref_file_kw):
    """
    Create an asdf reference file with the transformation coded in a NIRSPEC
    Camera.pcf or Collimator*.pcf file.

    - forward (team): sky to detector
      - Shift inputs to input_rotation_center
      - Rotate inputs
      - Scale  inputs
      - Shift inputs to output_rot_center
      - Apply polynomial distortion
    - backward_team (team definition) detector to sky
      - Apply polynomial distortion
      - Shift inputs to output_rot_center
      - Scale  inputs
      - Rotate inputs
      - Shift inputs to input_rotation_center

    WCS implementation
    - forward: detector to sky
      - equivalent to backward_team
    - backward: sky to detector
      - equivalent to forward_team

    Parameters
    ----------
    pcffile : str
        one of the NIRSPEC ".pcf" reference files provided by the IDT team.
        "pcf" stands for "polynomial coefficients fit"
    outname : str
        Name of reference file to be wriiten to disk.

    Returns
    -------
    fasdf : AsdfFile
        AsdfFile object

    Examples
    --------
    >>> pcf2asdf("Camera.pcf", "camera.asdf")

    """
    linear_det2sky = linear_from_pcf_det2sky(pcffile)

    with open(pcffile) as f:
        lines = [l.strip() for l in f.readlines()]

    degree = int(lines[lines.index('*FitOrder') + 1])

    xcoeff_index = lines.index('*xForwardCoefficients 21 2')
    xlines = lines[xcoeff_index + 1: xcoeff_index + 22]
    xcoeff_forward = coeffs_from_pcf(degree, xlines)
    x_poly_backward = models.Polynomial2D(degree, name='x_poly_backward', **xcoeff_forward)

    ycoeff_index = lines.index('*yForwardCoefficients 21 2')
    ycoeff_forward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
    y_poly_backward = models.Polynomial2D(degree, name='y_poly_backward', **ycoeff_forward)

    xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
    xcoeff_backward = coeffs_from_pcf(degree, lines[xcoeff_index + 1: xcoeff_index + 22])
    x_poly_forward = models.Polynomial2D(degree, name='x_poly_forward', **xcoeff_backward)

    ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
    ycoeff_backward = coeffs_from_pcf(degree, lines[ycoeff_index + 1: ycoeff_index + 22])
    y_poly_forward = models.Polynomial2D(degree, name='y_poly_forward', **ycoeff_backward)

    x_poly_forward.inverse = x_poly_backward
    y_poly_forward.inverse = y_poly_backward

    output2poly_mapping = Identity(2, name='output_mapping')
    output2poly_mapping.inverse = Mapping([0, 1, 0, 1])
    input2poly_mapping = Mapping([0, 1, 0, 1], name='input_mapping')
    input2poly_mapping.inverse = Identity(2)

    model_poly = input2poly_mapping | (x_poly_forward & y_poly_forward) | output2poly_mapping

    model = model_poly | linear_det2sky

    f = AsdfFile()
    f.tree = ref_file_kw.copy()
    f.add_history_entry("Build 6")
    f.tree['model'] = model
    f.write_to(outname)
def ifupost2asdf(ifupost_files, outname, ref_kw):
    """
    Create a reference file of type ``ifupost`` .

    Combines all IDT ``IFU-POST`` reference files in one ASDF file.

    forward direction : MSA to Collimator
    backward_direction: Collimator to MSA

    Parameters
    ----------
    ifupost_files : list
        Names of all ``IFU-POST`` IDT reference files
    outname : str
        Name of output ``ASDF`` file
    """
    fa = AsdfFile()
    fa.tree = ref_kw
    for fifu in ifupost_files:
        n = int((fifu.split('IFU-POST_')[1]).split('.pcf')[0])
        fa.tree[n] = {}
        with open(fifu) as f:
            lines = [l.strip() for l in f.readlines()]
        factors = lines[lines.index('*Factor 2') + 1].split()
        rotation_angle = float(lines[lines.index('*Rotation') + 1])
        input_rot_center = lines[lines.index('*InputRotationCentre 2') +
                                 1].split()
        output_rot_center = lines[lines.index('*OutputRotationCentre 2') +
                                  1].split()
        linear_sky2det = homothetic_sky2det(input_rot_center, rotation_angle,
                                            factors, output_rot_center)

        degree = int(lines[lines.index('*FitOrder') + 1])

        xcoeff_index = lines.index('*xForwardCoefficients 21 2')
        xlines = lines[xcoeff_index + 1:xcoeff_index + 22]
        xcoeff_forward = coeffs_from_pcf(degree, xlines)
        x_poly_forward = models.Polynomial2D(degree,
                                             name='x_poly_forward',
                                             **xcoeff_forward)

        ycoeff_index = lines.index('*yForwardCoefficients 21 2')
        ycoeff_forward = coeffs_from_pcf(
            degree, lines[ycoeff_index + 1:ycoeff_index + 22])
        y_poly_forward = models.Polynomial2D(degree,
                                             name='y_poly_forward',
                                             **ycoeff_forward)

        xcoeff_index = lines.index('*xBackwardCoefficients 21 2')
        xcoeff_backward = coeffs_from_pcf(
            degree, lines[xcoeff_index + 1:xcoeff_index + 22])
        x_poly_backward = models.Polynomial2D(degree,
                                              name='x_poly_backward',
                                              **xcoeff_backward)

        ycoeff_index = lines.index('*yBackwardCoefficients 21 2')
        ycoeff_backward = coeffs_from_pcf(
            degree, lines[ycoeff_index + 1:ycoeff_index + 22])
        y_poly_backward = models.Polynomial2D(degree,
                                              name='y_poly_backward',
                                              **ycoeff_backward)

        output2poly_mapping = Identity(2, name='output_mapping')
        output2poly_mapping.inverse = Mapping([0, 1, 0, 1])
        input2poly_mapping = Mapping([0, 1, 0, 1], name='input_mapping')
        input2poly_mapping.inverse = Identity(2)

        model_poly = input2poly_mapping | (
            x_poly_forward & y_poly_forward) | output2poly_mapping

        model = linear_sky2det | model_poly
        fa.tree[n]['model'] = model
    fa.add_history_entry("Build 6")
    asdffile = fa.write_to(outname)
    return asdffile
def fpa2asdf(fpafile, outname, ref_kw):
    """
    Create an asdf reference file with the FPA description.

    The CDP2 delivery includes a fits file - "FPA.fpa" which is the
    input to this function. This file is converted to asdf and is a
    reference file of type "FPA".

    nirspec_fs_ref_tools.fpa2asdf('Ref_Files/CoordTransform/Description/FPA.fpa', 'fpa.asdf')

    Parameters
    ----------
    fpafile : str
        A fits file with FPA description (FPA.fpa)
    outname : str
        Name of output ASDF file.
    """
    with open(fpafile) as f:
        lines = [l.strip() for l in f.readlines()]

    # NRS1
    ind = lines.index("*SCA491_PitchX")
    nrs1_pitchx = float(lines[ind+1])
    ind = lines.index("*SCA491_PitchY")
    nrs1_pitchy = float(lines[ind+1])
    ind = lines.index("*SCA491_RotAngle")
    nrs1_angle = float(lines[ind+1])
    ind = lines.index("*SCA491_PosX")
    nrs1_posx = float(lines[ind+1])
    ind = lines.index("*SCA491_PosY")
    nrs1_posy = float(lines[ind+1])

    # NRS2
    ind = lines.index("*SCA492_PitchX")
    nrs2_pitchx = float(lines[ind+1])
    ind = lines.index("*SCA492_PitchY")
    nrs2_pitchy = float(lines[ind+1])
    ind = lines.index("*SCA492_RotAngle")
    nrs2_angle = float(lines[ind+1])
    ind = lines.index("*SCA492_PosX")
    nrs2_posx = float(lines[ind+1])
    ind = lines.index("*SCA492_PosY")
    nrs2_posy = float(lines[ind+1])

    tree = ref_kw.copy()

    # NRS1 Sky to Detector
    scaling = np.array([[1/nrs1_pitchx, 0], [0, 1/nrs1_pitchy]])
    rotmat = models.Rotation2D._compute_matrix(-nrs1_angle)
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_sky2detector')
    nrs1_sky2det = models.Shift(-nrs1_posx, name='fpa_shift_x') & \
                 models.Shift(-nrs1_posy, name='fpa_shift_y') | aff

    # NRS1 Detector to Sky
    rotmat = models.Rotation2D._compute_matrix(-nrs1_angle)
    scaling = np.array([[nrs1_pitchx, 0], [0, nrs1_pitchy]])
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_detector2sky')
    nrs1_det2sky = aff | models.Shift(nrs1_posx, name='fpa_shift_x_det2sky') & \
                 models.Shift(nrs1_posy, name='fpa_shift_y_det2sky')

    nrs1_det2sky.inverse = nrs1_sky2det

    # NRS2 Sky to Detector
    scaling = np.array([[-1/nrs2_pitchx, 0], [0, -1/nrs2_pitchy]])
    rotmat = models.Rotation2D._compute_matrix(-nrs2_angle)
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_sky2detector')
    nrs2_sky2det = models.Shift(-nrs2_posx, name='fpa_shixft_x') & \
                 models.Shift(-nrs2_posy, name='fpa_shift_y') | aff

    # NRS2 Detector to Sky
    rotmat = models.Rotation2D._compute_matrix(nrs2_angle)
    scaling = np.array([[-nrs2_pitchx, 0], [0, -nrs2_pitchy]])
    matrix = np.dot(rotmat, scaling)
    aff = models.AffineTransformation2D(matrix, name='fpa_affine_detector2sky')
    nrs2_det2sky = aff | models.Shift(nrs2_posx, name='fpa_shift_x_det2sky') & \
                 models.Shift(nrs2_posy, name='fpa_shift_y_det2sky')

    nrs2_det2sky.inverse = nrs2_sky2det

    tree['NRS1'] = nrs1_det2sky
    tree['NRS2'] = nrs2_det2sky
    fasdf = AsdfFile()
    fasdf.tree = tree
    fasdf.add_history_entry("Build 6")
    fasdf.write_to(outname)
    return fasdf
def create_nircam_distortion(coefffile, detector, aperture, opgsname, outname):
    """
    Create an asdf reference file with all distortion components for the NIRCam imager.

    NOTE: The IDT has not provided any distortion information. The files are constructed
    using ISIM transformations provided/(computed?) by the TEL team which they use to
    create the SIAF file.
    These reference files should be replaced when/if the IDT provides us with distortion.

    Parameters
    ----------
    detector : str
        NRCB1, NRCB2, NRCB3, NRCB4, NRCB5, NRCA1, NRCA2, NRCA3, NRCA4, NRCA5
    aperture : str
        Name of the aperture/subarray. (e.g. FULL, SUB160, SUB320, SUB640, GRISM_F322W2)
    outname : str
        Name of output file.

    Examples
    --------

    """
    numdet = detector[-1]
    module = detector[-2]
    channel = 'SHORT'
    if numdet == '5':
        channel = 'LONG'
        
    full_aperture = detector + '_' + aperture

    #"Forward' transformations. science --> ideal --> V2V3
    sci2idlx, sci2idly, sciunit, idlunit = read_siaf_table.get_siaf_transform(coefffile,full_aperture,'science','ideal', 5)
    idl2v2v3x, idl2v2v3y = read_siaf_table.get_siaf_v2v3_transform(coefffile,full_aperture,from_system='ideal')

    #'Reverse' transformations. V2V3 --> ideal --> science
    v2v32idlx, v2v32idly = read_siaf_table.get_siaf_v2v3_transform(coefffile,full_aperture,to_system='ideal')
    idl2scix, idl2sciy, idlunit, sciunit = read_siaf_table.get_siaf_transform(coefffile,full_aperture,'ideal','science', 5)
    
 
    #Map the models together to make a single transformation
    model =  Mapping([0, 1, 0, 1]) | sci2idlx & sci2idly | Mapping([0, 1, 0, 1]) | idl2v2v3x & idl2v2v3y
    model_inv =  Mapping([0, 1, 0, 1]) | v2v32idlx & v2v32idly | Mapping([0, 1, 0, 1]) | idl2scix & idl2sciy
    model.inverse = model_inv


    #In the reference file headers, we need to switch NRCA5 to NRCALONG, and same
    #for module B.
    if detector[-1] == '5':
        detector = detector[0:4] + 'LONG'
    

    tree = {"TITLE": "NIRCAM Distortion",
            "TELESCOP": "JWST",
            "INSTRUMENT": "NIRCAM",
            "PEDIGREE": "GROUND",
            "REFTYPE" : "DISTORTION",
            "AUTHOR": "B. Hilbert",
            "DETECTOR": detector,
            "MODULE": module,
            "CHANNEL": channel,
            "SUBARRAY": opgsname,
            "DESCRIP": "Distortion model function created from SIAF coefficients",
            "EXP_TYPE": "NRC_IMAGE",
            "USEAFTER": "2014-01-01T00:00:00",
            "model": model
            }

    fasdf = AsdfFile()
    fasdf.tree = tree

    sdict = {'name':'nircam_reftools.py','author':'B.Hilbert','homepage':'https://github.com/spacetelescope/jwreftools','version':'0.7'}
    
    fasdf.add_history_entry("File created from a file of distortion coefficients, NIRCam_SIAF_2016-09-29.csv, provided by Colin Cox in October 2016. Software used: https://github.com/spacetelescope/jwreftools",software=sdict)

    fasdf.write_to(outname)
def create_nircam_distortion(coefffile, detector, aperture, opgsname, outname):
    """
    Create an asdf reference file with all distortion components for the NIRCam imager.

    NOTE: The IDT has not provided any distortion information. The files are constructed
    using ISIM transformations provided/(computed?) by the TEL team which they use to
    create the SIAF file.
    These reference files should be replaced when/if the IDT provides us with distortion.

    Parameters
    ----------
    detector : str
        NRCB1, NRCB2, NRCB3, NRCB4, NRCB5, NRCA1, NRCA2, NRCA3, NRCA4, NRCA5
    aperture : str
        Name of the aperture/subarray. (e.g. FULL, SUB160, SUB320, SUB640, GRISM_F322W2)
    outname : str
        Name of output file.

    Examples
    --------

    """
    numdet = detector[-1]
    module = detector[-2]
    channel = 'SHORT'
    if numdet == '5':
        channel = 'LONG'

    full_aperture = detector + '_' + aperture

    #"Forward' transformations. science --> ideal --> V2V3
    sci2idlx, sci2idly, sciunit, idlunit = read_siaf_table.get_siaf_transform(
        coefffile, full_aperture, 'science', 'ideal', 5)
    idl2v2v3x, idl2v2v3y = read_siaf_table.get_siaf_v2v3_transform(
        coefffile, full_aperture, from_system='ideal')

    #'Reverse' transformations. V2V3 --> ideal --> science
    v2v32idlx, v2v32idly = read_siaf_table.get_siaf_v2v3_transform(
        coefffile, full_aperture, to_system='ideal')
    idl2scix, idl2sciy, idlunit, sciunit = read_siaf_table.get_siaf_transform(
        coefffile, full_aperture, 'ideal', 'science', 5)

    #Map the models together to make a single transformation
    model = Mapping([0, 1, 0, 1]) | sci2idlx & sci2idly | Mapping(
        [0, 1, 0, 1]) | idl2v2v3x & idl2v2v3y
    model_inv = Mapping([0, 1, 0, 1]) | v2v32idlx & v2v32idly | Mapping(
        [0, 1, 0, 1]) | idl2scix & idl2sciy
    model.inverse = model_inv

    #In the reference file headers, we need to switch NRCA5 to NRCALONG, and same
    #for module B.
    if detector[-1] == '5':
        detector = detector[0:4] + 'LONG'

    tree = {
        "TITLE": "NIRCAM Distortion",
        "TELESCOP": "JWST",
        "INSTRUMENT": "NIRCAM",
        "PEDIGREE": "GROUND",
        "REFTYPE": "DISTORTION",
        "AUTHOR": "B. Hilbert",
        "DETECTOR": detector,
        "MODULE": module,
        "CHANNEL": channel,
        "SUBARRAY": opgsname,
        "DESCRIP": "Distortion model function created from SIAF coefficients",
        "EXP_TYPE": "NRC_IMAGE",
        "USEAFTER": "2014-01-01T00:00:00",
        "model": model
    }

    fasdf = AsdfFile()
    fasdf.tree = tree

    sdict = {
        'name': 'nircam_reftools.py',
        'author': 'B.Hilbert',
        'homepage': 'https://github.com/spacetelescope/jwreftools',
        'version': '0.7'
    }

    fasdf.add_history_entry(
        "File created from a file of distortion coefficients, NIRCam_SIAF_2016-09-29.csv, provided by Colin Cox in October 2016. Software used: https://github.com/spacetelescope/jwreftools",
        software=sdict)

    fasdf.write_to(outname)