Exemplo n.º 1
0
def _load_itm_library(library_file):
    """Load ITM FITS file

    Parameters
    ----------
    library_path : str
        Path pointing to the location of the PSF library

    Returns
    -------
    library : photutils.griddedPSFModel
        Object containing PSF library
    """
    data = fits.getdata(library_file)
    hdr = fits.getheader(library_file)
    if data.shape == (2048, 2048):
        # Normalize the data
        data /= np.sum(data)

        # Add PSF location and oversampling keywords
        hdr['DET_YX0'] = ('(1023, 1023)',
                          "The #0 PSF's (y,x) detector pixel position")
        hdr['OVERSAMP'] = (1, 'Oversampling factor for FFTs in computation')

        # Convert to HDUList and create library
        phdu = fits.PrimaryHDU(data, hdr)
        hdulist = fits.HDUList(phdu)
        library = to_griddedpsfmodel(hdulist)

        return library
    else:
        raise ValueError(
            'Expecting ITM data of size (2048, 2048), not {}'.format(
                data.shape))
Exemplo n.º 2
0
def get_gridded_segment_psf_library_list(instrument,
                                         detector,
                                         filtername,
                                         library_path,
                                         pupilname="CLEAR"):
    """Find the filenames for the appropriate gridded segment PSF libraries and
    read them into griddedPSFModel objects

    Parameters
    ----------
    instrument : str
        Name of instrument the PSFs are from

    detector : str
        Name of the detector within ```instrument```

    filtername : str
        Name of filter used for PSF library creation

    library_path : str
        Path pointing to the location of the PSF library

    pupilname : str, optional
        Name of pupil wheel element used for PSF library creation. Default is "CLEAR".

    Returns:
    --------
    libraries : list of photutils.griddedPSFModel
        List of object containing segment PSF libraries

    """
    logger = logging.getLogger(
        'mirage.psf.segment_psfs.get_gridded_segment_psf_library_list')

    library_list = get_segment_library_list(instrument,
                                            detector,
                                            filtername,
                                            library_path,
                                            pupil=pupilname)

    logger.info("Segment PSFs will be generated using:")
    for filename in library_list:
        logger.info(os.path.basename(filename))

    libraries = []
    for filename in library_list:
        with fits.open(filename) as hdulist:
            #     hdr = hdulist[0].header
            #     d = hdulist[0].data
            #
            # data = d[0][0]
            # phdu = fits.PrimaryHDU(data, header=hdr)
            # hdulist = fits.HDUList(phdu)

            lib_model = to_griddedpsfmodel(hdulist)
            libraries.append(lib_model)

    return libraries
Exemplo n.º 3
0
def test_to_gridded_psfmodel(test_library_file):
    """Test that the example library file can be correctly loaded as a
    GriddedPSFModel using the webbpsf.utils.to_griddedpsfmodel function.

    Note that this is more a test of webbpsf than of MIRaGe, but it is
    required for MIRaGe to work!
    """
    with fits.open(test_library_file) as hdulist:
        lib_model = to_griddedpsfmodel(hdulist)

    assert isinstance(lib_model, photutils.psf.models.GriddedPSFModel), \
        'Segment PSF library not created correctly'
    assert lib_model.grid_xypos == [(1023.5, 1023.5)], \
        'Segment PSF library not created correctly'
    assert lib_model.oversampling == 1, \
        'Segment PSF library not created correctly'
    for k in ['segid', 'segname', 'xtilt', 'ytilt']:
        assert k in list(lib_model.meta.keys()), \
            'Segment PSF library not created correctly'
    assert lib_model.meta['segid'][0] == 12, \
        'Segment PSF library not created correctly'
    assert lib_model.data.shape == (1, 1024, 1024), \
        'Segment PSF library not created correctly'
Exemplo n.º 4
0
def get_gridded_psf_library(instrument, detector, filtername, pupilname,
                            wavefront_error, wavefront_error_group,
                            library_path):
    """Find the filename for the appropriate gridded PSF library and
    read it in to a griddedPSFModel

    Parameters
    ----------
    instrument : str
        Name of instrument the PSFs are from

    detector : str
        Name of the detector within ```instrument```

    filtername : str
        Name of filter used for PSF library creation

    pupilname : str
        Name of pupil wheel element used for PSF library creation

    wavefront_error : str
        Wavefront error. Can be 'predicted' or 'requirements'

    wavefront_error_group : int
        Wavefront error realization group. Must be an integer from 0 - 9.

    library_path : str
        Path pointing to the location of the PSF library

    Returns:
    --------
    library : photutils.griddedPSFModel
        Object containing PSF library

    """
    logger = logging.getLogger(
        'mirage.psf.psf_selection.get_gridded_psf_library')

    # First, as a way to save time, let's assume a file naming convention
    # and search for the appropriate file that way. If we find a match,
    # confirm the properties of the file via the header. This way we don't
    # need to open and examine every file in the gridded library, which
    # saves at least a handful of seconds.
    if instrument.lower() == 'fgs':
        default_file_pattern = '{}_{}_fovp*_samp*_npsf*_{}_realization{}.fits'.format(
            instrument.lower(), detector.lower(), wavefront_error.lower(),
            wavefront_error_group)
    else:
        # NIRISS gridded library names don't follow standard filter/pupil rules.
        # The filenames are all <filter>_<clear>, where <clear> is clear if it
        # is in the filter wheel and clearp if in the pupil wheel.
        if instrument.lower() == 'niriss':
            if filtername.lower() == 'clear':
                filename_filter = pupilname
                filename_pupil = filtername
            elif pupilname.lower() == 'clearp':
                filename_filter = filtername
                filename_pupil = pupilname
            # filter=clear, pupil=nrm is currently not allowed
            if pupilname.lower() == 'nrm':
                filename_filter = filtername
                filename_pupil = 'mask_nrm'
        elif instrument.lower() == 'nircam':
            filename_filter = filtername
            filename_pupil = pupilname if 'GDHS' not in pupilname else 'clear'  # for WFSC team practice purposes we don't produce DHS "PSFs"

        default_file_pattern = '{}_{}_{}_{}_fovp*_samp*_npsf*_{}_realization{}.fits'.format(
            instrument.lower(), detector.lower(), filename_filter.lower(),
            filename_pupil.lower(), wavefront_error.lower(),
            wavefront_error_group)
    default_matches = glob(os.path.join(library_path, default_file_pattern))
    library_file = None
    if len(default_matches) == 1:
        library_file = confirm_gridded_properties(
            default_matches[0], instrument, detector, filtername, pupilname,
            wavefront_error, wavefront_error_group, library_path)

    # If the above search found no matching files, or multiple matching
    # files (based only on filename), or if the matching file's gridded
    # PSF model properties don't match what's expected, then resort to
    # opening and examining all files in the library.
    if library_file is None:
        library_file = get_library_file(instrument, detector, filtername,
                                        pupilname, wavefront_error,
                                        wavefront_error_group, library_path)

    logger.info("PSFs will be generated using: {}".format(
        os.path.abspath(library_file)))

    lib_head = fits.getheader(library_file)
    itm_sim = lib_head.get('ORIGIN', '') == 'ITM'

    if not itm_sim:
        try:
            library = to_griddedpsfmodel(library_file)
        except OSError:
            logger.error("OSError: Unable to open {}.".format(library_file))
    else:
        # Handle input ITM images
        library = _load_itm_library(library_file)

    # Check that the gridded PSF library is normalized as expected
    correct_norm, reason = check_normalization(library)
    if correct_norm:
        return library
    else:
        raise ValueError(
            ("Gridded PSF library in {} appears to be improperly normalized."
             "The total signal in a PSF is {}".format(library_file, reason)))
Exemplo n.º 5
0
def get_gridded_psf_library(instrument, detector, filtername, pupilname,
                            wavefront_error, wavefront_error_group,
                            library_path):
    """Find the filename for the appropriate gridded PSF library and
    read it in to a griddedPSFModel

    Parameters
    ----------
    instrument : str
        Name of instrument the PSFs are from

    detector : str
        Name of the detector within ```instrument```

    filtername : str
        Name of filter used for PSF library creation

    pupilname : str
        Name of pupil wheel element used for PSF library creation

    wavefront_error : str
        Wavefront error. Can be 'predicted' or 'requirements'

    wavefront_error_group : int
        Wavefront error realization group. Must be an integer from 0 - 9.

    library_path : str
        Path pointing to the location of the PSF library

    Returns:
    --------
    library : photutils.griddedPSFModel
        Object containing PSF library

    """
    # First, as a way to save time, let's assume a file naming convention
    # and search for the appropriate file that way. If we find a match,
    # confirm the properties of the file via the header. This way we don't
    # need to open and examine every file in the gridded library, which
    # saves at least a handful of seconds.
    if instrument.lower() == 'fgs':
        default_file_pattern = '{}_{}_fovp*_samp*_npsf*_{}_realization{}.fits'.format(
            instrument.lower(), detector.lower(), wavefront_error.lower(),
            wavefront_error_group)
    else:
        default_file_pattern = '{}_{}_{}_{}_fovp*_samp*_npsf*_{}_realization{}.fits'.format(
            instrument.lower(), detector.lower(), filtername.lower(),
            pupilname.lower(), wavefront_error.lower(), wavefront_error_group)
    default_matches = glob(os.path.join(library_path, default_file_pattern))

    library_file = None
    if len(default_matches) == 1:
        library_file = confirm_gridded_properties(
            default_matches[0], instrument, detector, filtername, pupilname,
            wavefront_error, wavefront_error_group, library_path)

    # If the above search found no matching files, or multiple matching
    # files (based only on filename), or if the matching file's gridded
    # PSF model properties don't match what's expected, then resort to
    # opening and examining all files in the library.
    if library_file is None:
        library_file = get_library_file(instrument, detector, filtername,
                                        pupilname, wavefront_error,
                                        wavefront_error_group, library_path)

    print("PSFs will be generated using: {}".format(
        os.path.abspath(library_file)))

    try:
        library = to_griddedpsfmodel(library_file)
    except KeyError:
        # Handle input ITM images
        itm_sim = fits.getval(library_file, 'ORIGIN')
        if itm_sim:
            library = _load_itm_library(library_file)

    except OSError:
        print("OSError: Unable to open {}.".format(library_file))
    return library
Exemplo n.º 6
0
def get_gridded_psf_library(instrument, detector, filtername, pupilname,
                            wavefront_error, wavefront_error_group,
                            library_path):
    """Find the filename for the appropriate gridded PSF library and
    read it in to a griddedPSFModel

    Parameters
    ----------
    instrument : str
        Name of instrument the PSFs are from

    detector : str
        Name of the detector within ```instrument```

    filtername : str
        Name of filter used for PSF library creation

    pupilname : str
        Name of pupil wheel element used for PSF library creation

    wavefront_error : str
        Wavefront error. Can be 'predicted' or 'requirements'

    wavefront_error_group : int
        Wavefront error realization group. Must be an integer from 0 - 9.

    library_path : str
        Path pointing to the location of the PSF library

    Returns:
    --------
    library : photutils.griddedPSFModel
        Object containing PSF library

    """
    logger = logging.getLogger(
        'mirage.psf.psf_selection.get_gridded_psf_library')

    # In the default case, we expect the (total PSF signal)/ (oversample factor**2)
    # to be close to 1.0. In certain cases for NIRISS, this expectation is lower by
    # some factor. Here we set the defaul factor to lower expectations to 1.0
    # (i.e. don't lower expectations).
    grid_min_factor = 1.0

    # First, as a way to save time, let's assume a file naming convention
    # and search for the appropriate file that way. If we find a match,
    # confirm the properties of the file via the header. This way we don't
    # need to open and examine every file in the gridded library, which
    # saves at least a handful of seconds.
    if instrument.lower() == 'fgs':
        default_file_pattern = '{}_{}_fovp*_samp*_npsf*_{}_realization{}.fits'.format(
            instrument.lower(), detector.lower(), wavefront_error.lower(),
            wavefront_error_group)
    else:
        # NIRISS gridded library names don't follow standard filter/pupil rules.
        # The filenames are all <filter>_<clear>, where <clear> is clear if it
        # is in the filter wheel and clearp if in the pupil wheel.
        if instrument.lower() == 'niriss':
            if filtername.lower() == 'clear':
                filename_filter = pupilname
                filename_pupil = filtername
            elif pupilname.lower() == 'clearp':
                # If CLEARP is used, we need to alert the normalization check
                # below to expect PSFs with a total signal/oversamp**2 lower
                # than otherwise expected by a factor of ~0.84
                filename_filter = filtername
                filename_pupil = pupilname
                grid_min_factor = NIRISS_CLEARP_PSF_THROUGHPUT_REDUCTION
            # filter=clear, pupil=nrm is currently not allowed
            if pupilname.lower() == 'nrm':
                # In NRM mode, the ~0.15 throughput factor associated with the
                # NRM mask is baked into the PSFs from Webbpsf, so we need to
                # adjust the expectations of the normalization check below.
                filename_filter = filtername
                filename_pupil = 'mask_nrm'
                grid_min_factor = NIRISS_NRM_PSF_THROUGHPUT_REDUCTION
        elif instrument.lower() == 'nircam':
            # In the case of a WLP4+WLP8 observation, the gridded PSF library field
            # of view is small enough (and the PSF is large enough) that a significant
            # fraction of the flux is outside the field of view (of the PSF "core" library.
            # In this case, we need to loosen then requirement for the minimum normalized
            # flux in the array.
            if ((filtername.lower() == 'wlp4') &
                (pupilname.lower() == 'wlp8')):
                grid_min_factor = NIRCAM_WLP12_PSF_THROUGHPUT_REDUCTION
            filename_filter = filtername
            filename_pupil = pupilname if 'GDHS' not in pupilname else 'clear'  # for WFSC team practice purposes we don't produce DHS "PSFs"

        default_file_pattern = '{}_{}_{}_{}_fovp*_samp*_npsf*_{}_realization{}.fits'.format(
            instrument.lower(), detector.lower(), filename_filter.lower(),
            filename_pupil.lower(), wavefront_error.lower(),
            wavefront_error_group)
    default_matches = glob(os.path.join(library_path, default_file_pattern))
    library_file = None
    if len(default_matches) == 1:
        library_file = confirm_gridded_properties(
            default_matches[0], instrument, detector, filtername, pupilname,
            wavefront_error, wavefront_error_group, library_path)

    # If the above search found no matching files, or multiple matching
    # files (based only on filename), or if the matching file's gridded
    # PSF model properties don't match what's expected, then resort to
    # opening and examining all files in the library.
    if library_file is None:
        logger.info((
            "No matching gridded PSF library file found based on filename pattern. Checking "
            "library files' metadata. This will be slower."))
        library_file = get_library_file(instrument, detector, filtername,
                                        pupilname, wavefront_error,
                                        wavefront_error_group, library_path)

    logger.info("PSFs will be generated using: {}".format(
        os.path.abspath(library_file)))

    lib_head = fits.getheader(library_file)
    itm_sim = lib_head.get('ORIGIN', '') == 'ITM'

    if not itm_sim:
        try:
            library = to_griddedpsfmodel(library_file)
        except OSError:
            logger.error("OSError: Unable to open {}.".format(library_file))
    else:
        # Handle input ITM images
        library = _load_itm_library(library_file)

    # Check that the gridded PSF library is normalized as expected
    check_max = PSF_NORM_MAX * grid_min_factor
    check_min = PSF_NORM_MIN * grid_min_factor
    correct_norm, reason = check_normalization(library,
                                               lower_limit=check_min,
                                               upper_limit=check_max,
                                               renorm_psfs_above_1=True)
    if correct_norm:
        return library
    else:
        raise ValueError(
            ("Gridded PSF library in {} appears to be improperly normalized."
             "The total signal in a PSF is {}".format(library_file, reason)))