def test_offset_residuals():
    """
    Use same affine object for simulation and analysis
    """
    pixelscale_as = 0.0656
    arcsec2rad = u.arcsec.to(u.rad)

    #psf_offsets = ((0,0), (1.0,0), )

    #psf_offsets = ((0,0), (1.0,0), (0, 1.0), (1.0,1.0))

    bandpass = np.array([
        (1.0, 4.3e-6),
    ])
    # Loop over psf_offsets

    jw = NRM_Model(mask='jwst', holeshape='hex')
    jw.set_pixelscale(pixelscale_as * arcsec2rad)

    jw.simulate(fov=35,
                bandpass=bandpass,
                over=oversample,
                psf_offset=psf_offsets)
    fits.writeto(fitsimdir + "offset_data.fits", jw.psf, overwrite=True)

    jw.make_model(fov=35,
                  bandpass=bandpass,
                  over=oversample,
                  psf_offset=psf_offsets)

    jw.fit_image(jw.psf, modelin=jw.model)
    fits.writeto(fitsimdir + "residual_offset.fits",
                 jw.residual,
                 overwrite=True)
Example #2
0
class Affine2dMakeModelRotTestCase(unittest.TestCase):
    def setUp(self):

        allholes = ('b4', 'c2', 'b5', 'b2', 'c1', 'b6', 'c6')
        b4, c2, b5, b2, c1, b6, c6 = allholes
        self.hc = (b2, b6, b5)  # holechoices
        self.hstr = holes2string(self.hc)
        self.holeshape = "hex"

        # directory containing the test data
        data_dir = os.path.join(os.path.dirname(__file__),
                                'test_data/affine2d_makemodel_rot')
        self.data_dir = data_dir
        print(data_dir)
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)

    # expects strings of  % (self.npix, self.holeshape, self.wave/um, rot, self.hstr)
        self.fnfmt = data_dir + '/psf_nrm_{2:.1f}_{0}_{1}_{3:.0f}_{4:s}.fits'

        self.fmt = "    ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})"
        self.pixel = 0.0656
        self.npix = 87
        self.wave = 4.3e-6  # m
        self.over = 11

        mx, my = 1.0, 1.0
        sx, sy = 0.0, 0.0
        xo, yo = 0.0, 0.0
        affine_ideal = Affine2d(mx=mx,
                                my=my,
                                sx=sx,
                                sy=sy,
                                xo=xo,
                                yo=yo,
                                name="Ideal")

        rots = (0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75,
                80, 85, 90, 95)
        rots = (
            0.000,
            10.000,
        )
        for rot in rots:

            rot = avoidhexsingularity(rot)  # in utils
            affine_rot = Affine2d(rotradccw=np.pi * rot / 180.0,
                                  name="{0:.0f}".format(rot))  # in utils
            aff = affine_rot

            # holeshape is hex or circ g7s6 jwst
            # because model_array requires
            # a primary beam for one slice of the model
            self.jw = NRM_Model(
                mask='jwst',
                holeshape=self.holeshape,
                #chooseholes=self.hc,
                affine2d=aff)
            self.jw.set_pixelscale(self.pixel * arcsec2rad)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            # write psf
            psffn = self.fnfmt.format(self.npix, self.holeshape,
                                      self.wave / um, rot, self.hstr)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            print("test:  psf shape", self.jw.psf.shape)

            modelslices = self.jw.make_model(fov=self.npix,
                                             bandpass=self.wave,
                                             over=self.over)
            print("test:  modelslices type", type(modelslices))
            print("test:  modelslices shape", modelslices.shape)
            modelfn = psffn.replace("psf_nrm", "model")

            # write model
            model_for_fitsfile = np.zeros(
                (modelslices.shape[2], modelslices.shape[0],
                 modelslices.shape[1]))
            for sl in range(modelslices.shape[2]):
                model_for_fitsfile[sl, :, :] = modelslices[:, :, sl]
            print("test:  model_for_fitsfile type", type(model_for_fitsfile))
            print("test:  model_for_fitsfile shape", model_for_fitsfile.shape)
            fits.writeto(modelfn, model_for_fitsfile[6, :, :], overwrite=True)
            header = fits.getheader(modelfn)
            header = affinepars2header(header, aff)
            fits.update(modelfn, model_for_fitsfile[6, :, :], header=header)

            del self.jw

            del aff
            del affine_rot

    def test_psf(self):
        """ 
            sanity check and code development tool than a routine test.
        """
        self.assertTrue(0.0 < 1e-15, 'error: test_affine2d failed')
Example #3
0
def fit_fringes_single_integration(args):
    self = args["object"]
    slc = args["slc"]  # indexes each slice of 3D stack of images
    id_tag = args["slc"]
    nrm = NRM_Model(mask=self.instrument_data.mask,
                    pixscale=self.instrument_data.pscale_rad,
                    holeshape=self.instrument_data.holeshape,
                    affine2d=self.instrument_data.affine2d,
                    over=self.oversample)

    # for image data from single filter, this is the filter bandpass.
    # otherwise it's the IFU wavelength slice.
    nrm.bandpass = self.instrument_data.wls[slc]

    if self.npix == 'default':
        self.npix = self.scidata[slc, :, :].shape[0]

    # New or modified in LG++
    # center the image on its peak pixel:
    # AS subtract 1 from "r" below  for testing >1/2 pixel offsets
    # AG 03-2019 -- is above comment still relevant?

    # Where appropriate, the slice under consideration is centered, and processed
    if self.instrument_data.arrname == "jwst_g7s6c":
        # get the cropped image and identically-cropped bad pixel data:
        self.ctrd, self.dqslice = utils.center_imagepeak(
            self.scidata[slc, :, :], dqm=self.dqmask[slc, :, :])
    else:
        self.ctrd = utils.center_imagepeak(self.scidata[slc, :, :])

    # store the 2D cropped image centered on the brightest pixel,
    # bad pixels smoothed over

    if self.psf_offset_ff is None:
        # returned values have offsets x-y flipped:
        # Finding centroids the Fourier way assumes no bad pixels case
        #   - Fourier domain mean slope

        # offsets from brightest pixel ctr
        centroid = utils.find_centroid(self.ctrd,
                                       self.instrument_data.threshold)
        # use flipped centroids to update centroid of image for JWST
        # pixel coordinates: - note the flip of [0] and [1] to match DS9 view
        image_center = utils.centerpoint(self.ctrd.shape) + \
                            np.array((centroid[1], centroid[0])) # info only, unused
        nrm.xpos = centroid[1]  # flip 0 and 1 to convert
        nrm.ypos = centroid[0]  # flip 0 and 1
        nrm.psf_offset = nrm.xpos, nrm.ypos  # renamed .bestcenter to .psf_offset
        if self.debug:
            print(
                "nrm.core.fit_fringes_single_integration: utils.find_centroid() -> nrm.psf_offset"
            )
    else:
        # user-provided psf_offset python-style offsets from array center are here.
        nrm.psf_offset = self.psf_offset_ff

    nrm.make_model(fov=self.ctrd.shape[0],
                   bandpass=nrm.bandpass,
                   over=self.oversample,
                   psf_offset=nrm.psf_offset,
                   pixscale=nrm.pixel)

    # again, fit just one slice...
    if self.instrument_data.arrname == "jwst_g7s6c":
        nrm.fit_image(self.ctrd,
                      modelin=nrm.model,
                      psf_offset=nrm.psf_offset,
                      dqm=self.dqslice,
                      weighted=self.weighted)
    else:
        nrm.fit_image(self.ctrd,
                      modelin=nrm.model,
                      psf_offset=nrm.psf_offset,
                      weighted=self.weighted)
    """
    Attributes now stored in nrm object:

    -----------------------------------------------------------------------------
    soln            --- resulting sin/cos coefficients from least squares fitting
    fringephase     --- baseline phases in radians
    fringeamp       --- baseline amplitudes (flux normalized)
    redundant_cps   --- closure phases in radians
    redundant_cas   --- closure amplitudes
    residual        --- fit residuals [data - model solution]
    cond            --- matrix condition for inversion
    fringepistons   --- zero-mean piston opd in radians on each hole (eigenphases)
    -----------------------------------------------------------------------------
    For jwst_g7s6 cropped-to-match-data bad pixel array 'ctrb' is also stored
    """

    self.save_output(slc, nrm)  # Please elucidate what this is for
    self.nrm = nrm  # store  extracted values here
    return None
Example #4
0
def verify_pistons(arg):
    """
    Create simulated data with pistons,
    1. analyze the data by calling fit_image
    Do not use fringefitter since the data is perfecrly centered (the if loop).
    Check if input and output pistons match.
    
    2. analyze the data by calling fit_image via fringefitter
    Fringefitter finds the bestcenter and makes model with bestcenter.
    Since the data is perfecrly centered fringefitter should not affect output pistons.
    Check if input and output pistons match.
    """

    jw = NRM_Model(mask='jwst', holeshape="hex")
    pixelscale_as = 0.0656
    arcsec2rad = u.arcsec.to(u.rad)

    jw.set_pixelscale(pixelscale_as * arcsec2rad)

    np.random.seed(100)

    #lambda/14 ~ 80% strehl ratio
    phi = np.random.normal(0, 1.0, 7) / 14.0  # waves
    print("phi", phi, "varphi", phi.var(), "waves")
    phi = phi - phi.mean()

    print("phi_nb stdev/w", phi.std())
    print("phi_nb stdev/r", phi.std() * 2 * np.pi)
    print("phi_nb mean/r", phi.mean() * 2 * np.pi)
    pistons = phi * 4.3e-6  #OR

    print("/=====input pistons/m=======/\n", pistons)
    print("/=====input pistons/r=======/\n", pistons * (2 * np.pi) / 4.3e-6)

    jw.set_pistons(pistons)
    jw.simulate(fov=81, bandpass=4.3e-6, over=oversample)
    fits.PrimaryHDU(data=jw.psf).writeto(
        "implaneia_tests/perfect_wpistons.fits", overwrite=True)

    if arg == ("no_fringefitter"):

        jw.make_model(fov=81, bandpass=4.3e-6, over=oversample)
        jw.fit_image(jw.psf, modelin=jw.model)

        pos = np.get_printoptions()
        np.set_printoptions(precision=4,
                            formatter={'float': lambda x: '{:+.4e}'.format(x)},
                            linewidth=80)
        print("Residual/psfpeak array center:", jw.psf.shape)
        print((jw.residual / jw.psf.max())[36:-36, 36:-36])
        np.set_printoptions(pos)

        fits.PrimaryHDU(data=jw.residual).writeto(
            "residual_pistons_no_ff.fits", overwrite=True)
        #return jw
        #print("output pistons/r",jw.fringepistons)
        #print("output pistons/w",jw.fringepistons/(2*np.pi))
        #print("output pistons/m",jw.fringepistons*4.3e-6/(2*np.pi))
        #print("input pistons/m ",jw.phi)

    elif arg == ("use_fringefitter"):

        fits.PrimaryHDU(data=jw.psf).writeto(datadir +
                                             "/perfect_wpistons.fits",
                                             overwrite=True)

        amisim2mirage(datadir, ("perfect_wpistons", ), mirexample, filt)

        niriss = InstrumentData.NIRISS(filt)
        ff_t = nrm_core.FringeFitter(niriss,
                                     datadir=datadir,
                                     savedir=datadir,
                                     oversample=oversample,
                                     interactive=False)
        print(test_tar)
        ff_t.fit_fringes(test_tar)

        print("Residual:")
        #print(ff_t.nrm.residual)
        print("Residual/psfpeak array center:", ff_t.nrm.reference.shape)
        pos = np.get_printoptions()
        np.set_printoptions(precision=3,
                            formatter={'float': lambda x: '{:+.3e}'.format(x)},
                            linewidth=80)
        print((ff_t.nrm.residual / jw.psf.max())[36:-36, 36:-36])
        np.set_printoptions(pos)

        fits.PrimaryHDU(data=ff_t.nrm.residual).writeto(datadir+\
                        "/residual_pistons_with_ff.fits",overwrite=True)

        utils.compare_pistons(jw.phi * 2 * np.pi / 4.3e-6,
                              ff_t.nrm.fringepistons,
                              str="ff_t")