Exemplo n.º 1
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
Exemplo n.º 2
0
    def setUp(self):
    
        # setup parameters for simulation
        verbose = 1
        overwrite = 1

        monochromatic_wavelength_m = np.array([(1.0, 4.3e-6),])
        mask = 'MASK_NRM'
        filter = 'F430M'
        pixelscale_arcsec = 0.0656 
        filter_name = 'Monochromatic '+np.str(monochromatic_wavelength_m)

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

        out_dir = data_dir

        name_seed = 'PSF_NIRISS_%s_%s'%(mask,filter)

        psf_image_name = name_seed + '_reference.fits'
        psf_image = os.path.join(data_dir,psf_image_name)
        psf_image_without_oversampling = os.path.join(data_dir,psf_image_name.replace('.fits','_without_oversampling.fits'))

        if (not os.path.isfile(psf_image_without_oversampling)) | (overwrite): 
            from nrm_analysis.fringefitting.LG_Model import NRM_Model
            jw = NRM_Model(mask='jwst',holeshape="hex")
            jw.set_pixelscale(pixelscale_arcsec*arcsec2rad)
            jw.simulate(fov=n_image, 
                bandpass=monochromatic_wavelength_m, 
                over=oversample)
            print("FringeFittingTestCase.SetUp: simulation oversampling is", oversample)
            
            # optional writing of oversampled image
            if 0:
                fits.writeto(psf_image,jw.psf_over, clobber=True)
                header = fits.getheader(psf_image)
                header['PIXELSCL'] = pixelscale_arcsec/oversample
                header['FILTER'] = filter_name
                header['PUPIL'] = mask 
                fits.update(psf_image,jw.psf_over/10000./28., header=header)

            # PSF without oversampling
            fits.writeto(psf_image_without_oversampling,jw.psf, clobber=True)
            header = fits.getheader(psf_image_without_oversampling)
            header['PIXELSCL'] = pixelscale_arcsec
            header['FILTER'] = filter_name
            header['PUPIL'] = mask 
            fits.update(psf_image_without_oversampling,jw.psf, header=header)
    
    
        # list of files produced for target
        file_list = glob.glob(os.path.join(data_dir,'*%s*.fits' % 'without_oversampling' ));
            
        self.simulated_image = file_list[0]
        self.psf_image_without_oversampling = psf_image_without_oversampling
Exemplo n.º 3
0
class Affine2dTestCase(unittest.TestCase):

    def setUp(self):

        # directory containing the test data
        data_dir = os.path.join(os.path.dirname(__file__),'test_data/affine2d_rot_psf')
        self.data_dir = data_dir
        print(data_dir)
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        self.fnfmt = data_dir+'/psf_nrm_{2:.1f}_{0}_{1}_{3:.0f}.fits' # expects strings of  %(imsize,hole)

        self.fmt = "    ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})"
        self.pixel = 0.0656 *  u.arcsec.to(u.rad)
        self.npix = 87
        self.wave = np.array([(1.0, 4.3e-6),]) # m
        self.over = 1

        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")

        for rot in (0,5,10,15,20,25,30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95):
            """
            print("           rot degrees pre", rot, end='')
            diagnostic = rot/15.0 - int(rot/15.0)
            print("  diagnostic", diagnostic, end='')
            rot = avoidhexsingularity(rot) # in utils
            print("   rot degrees post", rot)
            """
            rot = avoidhexsingularity(rot) # in utils
            affine_rot = Affine2d(rotradccw=np.pi*rot/180.0, name="{0:.0f}".format(rot)) # in utils
            aff = affine_rot

            # hexonly g7s6 jwst
            self.jw = NRM_Model(mask='jwst', holeshape="hexonly", affine2d=aff)
            self.jw.set_pixelscale(self.pixel*arcsec2rad)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, rot)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            del aff
            del affine_rot


    def test_psf(self):
        """ Read in PSFs with 0, 90 degree affines, 5 and 95 degree affines, 
            Rotate one set and subtract from the smaller rot PSF - should be zero if
            everything is correctly calculated.  If we nudge the PSF centers to avoid the 
            line singularity that hextransformEE will encounter if the psf is centrally 
            placed in a pixel.
            The file names are hand-edited to reflect the oversampling and rotations,
            so this is more a sanity check and code development tool than a routine test.
        """
        psf0  = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 0))
        psf90 = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 90))
        psf90r0 = np.rot90(psf90)
        psfdiff = psf0 - psf90r0
        fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir+"/diff_90_0_off08_ov1.fits", overwrite=True)
        psf0  = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 5))
        psf90 = fits.getdata(self.fnfmt.format(self.npix, 'hexonly', self.wave[:,1][0]/um, 95))
        psf90r0 = np.rot90(psf90)
        psfdiff = psf0 - psf90r0
        fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir+"/diff_95_5_off08_ov1.fits", overwrite=True)
        self.assertTrue(0.0 < 1e-15,  'error: test_affine2d failed')
Exemplo n.º 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")
Exemplo n.º 5
0
    def setUp(self):

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

        self.pixel = 0.0656 * u.arcsec.to(u.rad)
        self.npix = 87
        self.wave = 4.3e-6  # m
        self.over = 1
        """
        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")
        """
        invert = False  # greyscale inversion (true/false)

        holeshape = "hex"
        pixel_as = 0.0656 / 1.3  # slightly finer-than-actual-detector sampling, for clearer images
        print(
            "\n\t*** Watch out *** if comparing to real data: slightly finer-than-actual-detector sampling used for clearer images\n"
        )
        fov = 101  # 'detpix' but at finer sampling than actual
        over = 1
        wav_m = 4.3e-6
        filt = 'F430M'
        band = 'Monochromatic ' + np.str(wav_m)

        psf_offsets = (
            (0, 0),
            (1.0, 0),
        )
        psf_offsets = ((0, 0), )
        psf_offsets = ((0, 0), (1.0, 0), (0, 1.0), (1.0, 1.0))
        print((enumerate(psf_offsets)))
        psfs = np.zeros(
            (len(psf_offsets), fov, fov))  # for easy to understand movie
        print(('psfs.shape', psfs.shape))
        fncube3 = data_dir + "/cube.fits"

        # Loop over psf_offsets
        for noff, psfo in enumerate(psf_offsets):
            jw3 = NRM_Model(mask='jwst',
                            holeshape=holeshape,
                            pixscale=arcsec2rad * pixel_as,
                            datapath="",
                            refdir="./refdir")
            #chooseholes=None)

            jw3.simulate(fov=fov, bandpass=wav_m, over=over, psf_offset=psfo)

            mnem = "imctr_%.1f_%.1f" % psfo
            fn3 = data_dir + "/" + mnem + '.fits'
            name_seed = mnem
            # PSF
            fits.writeto(fn3, jw3.psf, overwrite=True)
            header = fits.getheader(fn3)
            header['SEGNAMES'] = "asbuilt"
            header['PIXELSCL'] = pixel_as
            header['over'] = over
            header['FILTER'] = wav_m
            header['hole'] = holeshape
            header['PUPIL'] = 'asbuilt'
            header['psfoff0'] = (psfo[0], "ds9X / detector pixels")
            header['psfoff1'] = (psfo[1], "ds9Y / detector pixels")
            header['SRC'] = ("test_psf_offset.py", "generating code")
            header['author'] = ("*****@*****.**", "responsible person?")
            fits.update(fn3, jw3.psf, header=header)
            psfs[noff, :, :] = jw3.psf
            """ calls tkinter, needs $DISPLAY environment variable, breaks travis testing
            figname = UC.make_standard_image(
                                           fn3,
                                           image_title=name_seed,
                                           save_plot=1, 
                                           plot_dir=data_dir, 
                                           name_seed=name_seed, 
                                           stretch='linear', 
                                           x_axis_label=None, 
                                           y_axis_label=None,
                                           invert=invert,
                                           add_grid=True)
            print(figname + " written to " + data_dir)
            """

            del jw3

        fits.PrimaryHDU(data=psfs).writeto(fncube3,
                                           overwrite=True)  # good for movie
        """
def find_scale(
        imagedata,
        affine_best,  # best current guess at data geometry cf analytical ideal
        scales,  # scales are near-unity
        pixel,
        npix,
        bandpass,
        over,
        holeshape,
        outdir=None):  # for nrm_model
    """  Preserve incoming "pixel" value, put the scale correction into the Affine2d object
         Is that kosher???  Should we change the pixel scale and leave affine2d the same?
         Affine2d can also incorporate unequal x and y scales, shears...
         For now place scale corrections into the Affine2d object     
         
         Note - placing isotropic scale change into Affine2d is equivalent to changing
         the effective image distance in the optical train while insisting that the
         mask physical geometry does not change, and the wavelength is perfectly knowm


         AS 2018 10  """

    affine_best.show("\tfind_scale")
    vprint("\tBefore Loop: ", scales)

    #Extend this name to include multi-paramater searches?
    psffmt = 'psf_nrm_{0:d}_{1:s}_{2:.3f}um_scl{3:.3f}.fits'
    # expect (npix, holeshape, bandpass/um, scl)

    if hasattr(scales, '__iter__') is False:
        scales = (scales, )

    affine2d_list = create_afflist_scales(scales, affine_best.mx,
                                          affine_best.my, affine_best.sx,
                                          affine_best.sy, affine_best.xo,
                                          affine_best.yo)
    crosscorrs = []

    for (scl, aff) in zip(scales, affine2d_list):

        vprint(aff.name + "...")
        jw = NRM_Model(mask='jwst',
                       holeshape=holeshape,
                       over=over,
                       affine2d=aff)
        jw.set_pixelscale(pixel)
        jw.simulate(fov=npix, bandpass=bandpass, over=over)
        psffn = psffmt.format(npix, holeshape, bandpass / um, scl)
        if outdir:
            fits.PrimaryHDU(data=jw.psf).writeto(outdir + "/" + psffn,
                                                 overwrite=True)
            fits.writeto(psffn, jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            utils.affinepars2header(header, aff)
            fits.update(psffn, jw.psf, header=header)

        crosscorrs.append(utils.rcrosscorrelate(imagedata, jw.psf).max())
        del jw

    vprint("\t*******************")
    vprint("\tDebug: crosscorrelations", crosscorrs)
    vprint("\tDebug:            scales", scales)
    scl_measured, max_cor = utils.findpeak_1d(crosscorrs, scales)
    vprint("\tScale factor measured {0:.5f}  Max correlation {1:.3e}".format(
        scl_measured, max_cor))
    vprint("\tpixel pitch from header  {0:.3f} mas".format(pixel * rad2mas))
    vprint("\tpixel pitch  {0:.3f} mas (implemented using affine2d)".format(
        scl_measured * pixel * rad2mas))

    # return convenient affine2d
    return utils.Affine2d(affine_best.mx * scl_measured,
                          affine_best.my * scl_measured,
                          affine_best.sx * scl_measured,
                          affine_best.sy * scl_measured,
                          affine_best.xo * scl_measured,
                          affine_best.yo * scl_measured,
                          name="scale_{0:.4f}".format(scl))
    def setUp(self):

        # directory containing the test data
        data_dir = os.path.join(os.path.dirname(__file__),
                                'test_data/affine2d_xyscale_psf')
        self.data_dir = data_dir
        print(data_dir)
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        self.fnfmt = data_dir + '/psf_nrm_{0:d}_{1:s}_{2:.3f}um_{3:s}.fits'
        # expects e.g. self.fnfmt.format(self.npix, 'hex', self.wave/um, aff.name)

        self.pixel = 0.0656 * u.arcsec.to(u.rad)
        self.npix = 87
        self.wave = 4.3e-6  # m
        self.over = 1

        ################
        self.pointsfmt = "    ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})"
        self.numtestfmt = "    min: {0:+.1e},  max: {1:+.1e},  avg: {2:+.1e},  sig: {3:+.1e}"  # min max avg stddev
        self.testpoints = (np.array((0, 0)), np.array((1, 0)), np.array(
            (0, 1)), np.array((1, 1)))

        xo, yo = 0.0, 0.0  # always set these for PSFs...

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

        mx, my = -1.0, 1.0
        sx, sy = 0.0, 0.0
        self.affine_xrev = Affine2d(mx=mx,
                                    my=my,
                                    sx=sx,
                                    sy=sy,
                                    xo=xo,
                                    yo=yo,
                                    name="Xreverse")

        mx, my = 2.0, 1.0
        sx, sy = 0.0, 0.0
        self.affine_xmag = Affine2d(mx=mx,
                                    my=my,
                                    sx=sx,
                                    sy=sy,
                                    xo=xo,
                                    yo=yo,
                                    name="Xmag")

        mx, my = 1.0, 1.0
        sx, sy = 0.5, 0.0
        self.affine_sigx = Affine2d(mx=mx,
                                    my=my,
                                    sx=sx,
                                    sy=sy,
                                    xo=xo,
                                    yo=yo,
                                    name="Xshear")

        for aff in (self.affine_ideal, self.affine_xrev, self.affine_xmag,
                    self.affine_sigx):

            # circ g7s6 jwst created for info only
            self.jw = NRM_Model(mask='jwst', holeshape="circ", affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'circ', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # circonly g7s6 jwst created for info only
            self.jw = NRM_Model(mask='jwst',
                                holeshape="circonly",
                                affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'circonly', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # hex g7s6 jwst
            self.jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'hex', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # hexonly g7s6 jwst
            self.jw = NRM_Model(mask='jwst', holeshape="hexonly", affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'hexonly', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # fringeonly g7s6 jwst
            self.jw = NRM_Model(mask='jwst',
                                holeshape="fringeonly",
                                affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'fringeonly', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            del aff

        self.hextest = self.eval_psf_hex()
        self.fringeonlytest = self.eval_psf_fringeonly()
        self.hexonlytest = self.eval_psf_hexonly()
        self.evals = [self.hextest, self.fringeonlytest, self.hexonlytest]
        self.sigsum = self.hextest + self.fringeonlytest + self.hexonlytest
class Affine2dTestCase(unittest.TestCase):
    def setUp(self):

        # directory containing the test data
        data_dir = os.path.join(os.path.dirname(__file__),
                                'test_data/affine2d_xyscale_psf')
        self.data_dir = data_dir
        print(data_dir)
        if not os.path.exists(data_dir):
            os.makedirs(data_dir)
        self.fnfmt = data_dir + '/psf_nrm_{0:d}_{1:s}_{2:.3f}um_{3:s}.fits'
        # expects e.g. self.fnfmt.format(self.npix, 'hex', self.wave/um, aff.name)

        self.pixel = 0.0656 * u.arcsec.to(u.rad)
        self.npix = 87
        self.wave = 4.3e-6  # m
        self.over = 1

        ################
        self.pointsfmt = "    ({0:+.3f}, {1:+.3f}) -> ({2:+.3f}, {3:+.3f})"
        self.numtestfmt = "    min: {0:+.1e},  max: {1:+.1e},  avg: {2:+.1e},  sig: {3:+.1e}"  # min max avg stddev
        self.testpoints = (np.array((0, 0)), np.array((1, 0)), np.array(
            (0, 1)), np.array((1, 1)))

        xo, yo = 0.0, 0.0  # always set these for PSFs...

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

        mx, my = -1.0, 1.0
        sx, sy = 0.0, 0.0
        self.affine_xrev = Affine2d(mx=mx,
                                    my=my,
                                    sx=sx,
                                    sy=sy,
                                    xo=xo,
                                    yo=yo,
                                    name="Xreverse")

        mx, my = 2.0, 1.0
        sx, sy = 0.0, 0.0
        self.affine_xmag = Affine2d(mx=mx,
                                    my=my,
                                    sx=sx,
                                    sy=sy,
                                    xo=xo,
                                    yo=yo,
                                    name="Xmag")

        mx, my = 1.0, 1.0
        sx, sy = 0.5, 0.0
        self.affine_sigx = Affine2d(mx=mx,
                                    my=my,
                                    sx=sx,
                                    sy=sy,
                                    xo=xo,
                                    yo=yo,
                                    name="Xshear")

        for aff in (self.affine_ideal, self.affine_xrev, self.affine_xmag,
                    self.affine_sigx):

            # circ g7s6 jwst created for info only
            self.jw = NRM_Model(mask='jwst', holeshape="circ", affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'circ', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # circonly g7s6 jwst created for info only
            self.jw = NRM_Model(mask='jwst',
                                holeshape="circonly",
                                affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'circonly', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # hex g7s6 jwst
            self.jw = NRM_Model(mask='jwst', holeshape="hex", affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'hex', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # hexonly g7s6 jwst
            self.jw = NRM_Model(mask='jwst', holeshape="hexonly", affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'hexonly', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            # fringeonly g7s6 jwst
            self.jw = NRM_Model(mask='jwst',
                                holeshape="fringeonly",
                                affine2d=aff)
            self.jw.set_pixelscale(self.pixel)
            self.jw.simulate(fov=self.npix, bandpass=self.wave, over=self.over)
            psffn = self.fnfmt.format(self.npix, 'fringeonly', self.wave / um,
                                      aff.name)
            fits.writeto(psffn, self.jw.psf, overwrite=True)
            header = fits.getheader(psffn)
            header = affinepars2header(header, aff)
            fits.update(psffn, self.jw.psf, header=header)
            del self.jw

            del aff

        self.hextest = self.eval_psf_hex()
        self.fringeonlytest = self.eval_psf_fringeonly()
        self.hexonlytest = self.eval_psf_hexonly()
        self.evals = [self.hextest, self.fringeonlytest, self.hexonlytest]
        self.sigsum = self.hextest + self.fringeonlytest + self.hexonlytest

    """  Ideal and Xreverse_xflipped should be machine zero or close """

    def eval_psf_hex(self):
        psfIdeal = fits.getdata(
            self.fnfmt.format(self.npix, 'hex', self.wave / um, "Ideal"))
        psfXrev = fits.getdata(
            self.fnfmt.format(self.npix, 'hex', self.wave / um, "Xreverse"))
        psfdiff = psfIdeal - psfXrev[::-1, :]
        print("    Numerical Summary:         hex  psf: " +\
              self.numtestfmt.format(psfIdeal.min(), psfIdeal.max(), psfIdeal.mean(), psfIdeal.std()))
        print("    Numerical Summary:         hex test: " +\
              self.numtestfmt.format(psfdiff.min(), psfdiff.max(), psfdiff.mean(), psfdiff.std()))
        fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir + "/diff_hex.fits",
                                              overwrite=True)
        return psfdiff.std()

    def eval_psf_fringeonly(self):
        psfIdeal = fits.getdata(
            self.fnfmt.format(self.npix, 'fringeonly', self.wave / um,
                              "Ideal"))
        psfXrev = fits.getdata(
            self.fnfmt.format(self.npix, 'fringeonly', self.wave / um,
                              "Xreverse"))
        psfdiff = psfIdeal - psfXrev[::-1, :]
        print("    Numerical Summary:  fringeonly  psf: " +\
              self.numtestfmt.format(psfIdeal.min(), psfIdeal.max(), psfIdeal.mean(), psfIdeal.std()))
        print("    Numerical Summary:  fringeonly test: " +\
              self.numtestfmt.format(psfdiff.min(), psfdiff.max(), psfdiff.mean(), psfdiff.std()))
        fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir +
                                              "/diff_fringeonly.fits",
                                              overwrite=True)
        return psfdiff.std()

    def eval_psf_hexonly(self):
        psfIdeal = fits.getdata(
            self.fnfmt.format(self.npix, 'hexonly', self.wave / um, "Ideal"))
        psfXrev = fits.getdata(
            self.fnfmt.format(self.npix, 'hexonly', self.wave / um,
                              "Xreverse"))
        psfdiff = psfIdeal - psfXrev[::-1, :]
        print("    Numerical Summary:     hexonly  psf: " +\
              self.numtestfmt.format(psfIdeal.min(), psfIdeal.max(), psfIdeal.mean(), psfIdeal.std()))
        print("    Numerical Summary:     hexonly test: " +\
              self.numtestfmt.format(psfdiff.min(), psfdiff.max(), psfdiff.mean(), psfdiff.std()))
        fits.PrimaryHDU(data=psfdiff).writeto(self.data_dir +
                                              "/diff_hexonly.fits",
                                              overwrite=True)
        return psfdiff.std()

    def test_psfs(self):
        print("Standard deviations of all three tests:", self.evals)
        self.assertTrue(self.sigsum < 1e-7,
                        'error: test_affine2d_xyscale_psf failed')
Exemplo n.º 9
0
    def setUp(self):

        # setup parameters for simulation, most are passed on to driver_scene
        verbose = 0
        overwrite = 1

        apply_dither = 0
        apply_jitter = 0
        include_detection_noise = 0
        uniform_flatfield = 1

        OVERSAMPLE = 11
        monochromatic_wavelength_m = 4.3e-6

        create_calibrator = 0
        random_seed = 124
        flip = False
        mask = 'MASK_NRM'
        filter = 'F430M'
        n_image = 77

        filter_name = 'Monochromatic ' + np.str(monochromatic_wavelength_m)

        # directory containing the static test data
        data_dir = os.path.join(os.path.dirname(__file__), 'test_data')

        # define output directory for dynamically generated data
        out_dir = os.path.join(os.path.dirname(__file__), 'tmp_data')
        if not os.path.exists(out_dir):
            os.makedirs(out_dir)

        name_seed = 'PSF_NIRISS_%s_%s' % (mask, filter)
        point_source_image_name = 'point_source_image.fits'
        point_source_image = os.path.join(out_dir, point_source_image_name)

        psf_image_name = name_seed + '_reference.fits'
        psf_image = os.path.join(data_dir, psf_image_name)
        psf_image_without_oversampling = os.path.join(
            data_dir,
            psf_image_name.replace('.fits', '_without_oversampling.fits'))

        # generate delta-function like image to feed as point-source into scene_sim
        n_image2 = n_image * OVERSAMPLE
        data = np.zeros((n_image2, n_image2))
        bright_pixel_index = (np.int(np.floor(n_image2 / 2.)),
                              np.int(np.floor(n_image2 / 2.)))
        data[bright_pixel_index] = 1.
        fits.writeto(point_source_image, data, clobber=True)

        # following code can be used to regenerate reference PSF file, but it depends on nrm_analysis
        if 0:
            from nrm_analysis.fringefitting.LG_Model import NRM_Model
            jw = NRM_Model(mask='jwst', holeshape="hex", flip=flip)
            jw.simulate(fov=n_image,
                        bandpass=monochromatic_wavelength_m,
                        over=OVERSAMPLE,
                        pixel=mas2rad(PIXELSCL_arcsec * 1000))
            fits.writeto(psf_image, jw.psf_over, clobber=True)
            header = fits.getheader(psf_image)
            header['PIXELSCL'] = PIXELSCL_arcsec / OVERSAMPLE
            header['FILTER'] = filter_name
            header['PUPIL'] = mask
            fits.update(psf_image, jw.psf_over / 10000. / 28., header=header)

            # PSF without oversampling
            fits.writeto(psf_image_without_oversampling, jw.psf, clobber=True)
            header = fits.getheader(psf_image_without_oversampling)
            header['PIXELSCL'] = PIXELSCL_arcsec
            header['FILTER'] = filter_name
            header['PUPIL'] = mask
            fits.update(psf_image_without_oversampling, jw.psf, header=header)

        NGROUP = 1
        NINT = 1
        COUNTRATE = 5e8

        #     run driver_scene to generate target and calibrator images
        driver_scene.main(['--output_absolute_path','%s'%out_dir,\
                           '--overwrite','%d'%overwrite,'-utr','0', '-f','%s'%filter,'-v','%d'%verbose,'--apply_dither','%d'%apply_dither,'--apply_jitter','%d'%apply_jitter,\
                           '-p',psf_image,'-s','%s'%point_source_image,'-os','%d'%OVERSAMPLE,'-cr','%e'%COUNTRATE,'--include_detection_noise','%d'%include_detection_noise,\
                           '-tag',('%3.2e_NGROUP%d'%(COUNTRATE,NGROUP)).replace('.','p'),'--uniform_flatfield','%d'%uniform_flatfield,'--random_seed','%d'%random_seed,\
                           '--create_calibrator','%d'%create_calibrator,'--nint','%d'%NINT,'--ngroups','%d'%NGROUP])

        # directory where simulated data was written
        filter_dir = os.path.join(out_dir, filter)
        self.filter_dir = filter_dir

        # list of files produced for target
        file_list = glob.glob(os.path.join(filter_dir, '%s*.fits' % 't_'))

        self.simulated_image = file_list[0]
        self.psf_image_without_oversampling = psf_image_without_oversampling