Пример #1
0
def test_write_with_metadict_header_astropy(tmpdir):
    fits_file = fits.open(AIA_171_IMAGE)
    data, header = fits_file[0].data, fits_file[0].header
    meta_header = MetaDict(OrderedDict(header))
    temp_file = tmpdir / "temp.fits"
    sunpy.io.fits.write(str(temp_file), data, meta_header)
    assert temp_file.exists()
Пример #2
0
def test_write_with_metadict_header_astropy(tmpdir):
    with fits.open(AIA_171_IMAGE) as fits_file:
        data, header = fits_file[0].data, fits_file[0].header
    meta_header = MetaDict(OrderedDict(header))
    temp_file = tmpdir / "temp.fits"
    with pytest.warns(SunpyUserWarning, match='The meta key comment is not valid ascii'):
        sunpy.io.fits.write(str(temp_file), data, meta_header)
    assert temp_file.exists()
Пример #3
0
def test_fitsheader():
    """Test that all test data can be converted back to a FITS header."""
    extensions = ('fts', 'fits')
    for ext in extensions:
        for ffile in Path(testpath).glob(f"*.{ext}*"):
            fits_file = fits.open(ffile)
            fits_file.verify("fix")
            meta_header = MetaDict(OrderedDict(fits_file[0].header))
            sunpy.io.fits.header_to_fits(meta_header)
            fits_file.close()
Пример #4
0
def test_fitsheader():
    """Test that all test data can be converted back to a FITS header."""
    extensions = ('.fts', '.fits')
    for ext in extensions:
        test_files = [f for f in test_data_filenames() if f.suffix == ext]
        for ffile in test_files:
            fits_file = fits.open(ffile)
            fits_file.verify("fix")
            meta_header = MetaDict(OrderedDict(fits_file[0].header))
            _fits.header_to_fits(meta_header)
            fits_file.close()
Пример #5
0
def make_fitswcs_header(data,
                        coordinate,
                        reference_pixel: u.pix = None,
                        scale: u.arcsec / u.pix = None,
                        rotation_angle: u.deg = None,
                        rotation_matrix=None,
                        instrument=None,
                        telescope=None,
                        observatory=None,
                        wavelength: u.angstrom = None,
                        exposure: u.s = None,
                        projection_code="TAN"):
    """
    Function to create a FITS-WCS header from a coordinate object
    (`~astropy.coordinates.SkyCoord`) that is required to
    create a `~sunpy.map.GenericMap`.

    Parameters
    ----------
    data : `~numpy.ndarray` or `tuple`
        Array data of Map for which a header is required, or the shape of the
        data array (in numpy order, i.e. ``(y_size, x_size)``).
    coordinates : `~astropy.coordinates.SkyCoord` or `~astropy.coordinates.BaseFrame`
        Coordinate object to get meta information for map header.
    reference_pixel :`~astropy.units.Quantity` of size 2, optional
        Reference pixel along each axis. These are expected to be Cartestian ordered, i.e
        the first index is the x axis, second index is the y axis. Defaults to
        the center of data array, ``(data.shape[1] - 1)/2., (data.shape[0] - 1)/2.)``,
        this argument is zero indexed (Python convention) not 1 indexed (FITS
        convention).
    scale : `~astropy.units.Quantity` of size 2, optional
        Pixel scaling along x and y axis (i.e. the spatial scale of the pixels (dx, dy)). These are
        expected to be Cartestian ordered, i.e [dx, dy].
        Defaults to ``([1., 1.] arcsec/pixel)``.
    rotation_angle : `~astropy.unit.Quantity`, optional
        Coordinate system rotation angle, will be converted to a rotation
        matrix and stored in the ``PCi_j`` matrix. Can not be specified with
        ``rotation_matrix``.
    rotation_matrix : `~numpy.ndarray` of dimensions 2x2, optional
        Matrix describing the rotation required to align solar North with
        the top of the image in FITS ``PCi_j`` convention. Can not be specified
        with ``rotation_angle``.
    instrument : `~str`, optional
        Name of the instrument of the observation.
    telescope : `~str`, optional
        Name of the telescope of the observation.
    observatory : `~str`, optional
        Name of the observatory of the observation.
    wavelength : `~u.Quantity`, optional
        Wavelength of the observation as an astropy quanitity, e.g. 171*u.angstrom.
        From this keyword, the meta keywords ``wavelnth`` and ``waveunit`` will be populated.
    exposure : `~u.Quantity`, optional
        Exposure time of the observation
    projection_code : `str`, optional
        The FITS standard projection code for the new header.

    Returns
    -------
    `~sunpy.util.MetaDict`
        The header information required for making a `sunpy.map.GenericMap`.

    Examples
    --------
    >>> import sunpy.map
    >>> from sunpy.coordinates import frames
    >>> from astropy.coordinates import SkyCoord
    >>> import astropy.units as u
    >>> import numpy as np

    >>> data = np.random.rand(1024, 1024)
    >>> my_coord = SkyCoord(0*u.arcsec, 0*u.arcsec, obstime="2017-08-01",
    ...                     observer = 'earth', frame=frames.Helioprojective)
    >>> my_header = sunpy.map.make_fitswcs_header(data, my_coord)
    >>> my_map = sunpy.map.Map(data, my_header)
    """

    if not isinstance(coordinate, (SkyCoord, frames.BaseCoordinateFrame)):
        raise ValueError(
            "coordinate needs to be a coordinate frame or an SkyCoord instance."
        )

    if isinstance(coordinate, SkyCoord):
        coordinate = coordinate.frame

    if coordinate.obstime is None:
        raise ValueError(
            "The coordinate needs an observation time, `obstime`.")

    if isinstance(coordinate, frames.Heliocentric):
        raise ValueError(
            "This function does not currently support heliocentric coordinates."
        )

    if hasattr(data, "shape"):
        shape = data.shape
    else:
        shape = data

    meta_wcs = _get_wcs_meta(coordinate, projection_code)

    if hasattr(coordinate, "observer") and isinstance(
            coordinate.observer, frames.BaseCoordinateFrame):
        meta_observer = get_observer_meta(coordinate.observer,
                                          getattr(coordinate, 'rsun', None))
        meta_wcs.update(meta_observer)

    meta_instrument = _get_instrument_meta(instrument, telescope, observatory,
                                           wavelength, exposure)
    meta_wcs.update(meta_instrument)

    if reference_pixel is None:
        reference_pixel = u.Quantity([(shape[1] + 1) / 2. * u.pixel,
                                      (shape[0] + 1) / 2. * u.pixel])
    if scale is None:
        scale = [1., 1.] * (u.arcsec / u.pixel)

    meta_wcs['crval1'], meta_wcs['crval2'] = (
        coordinate.spherical.lon.to_value(meta_wcs['cunit1']),
        coordinate.spherical.lat.to_value(meta_wcs['cunit2']))

    meta_wcs['crpix1'], meta_wcs['crpix2'] = (reference_pixel[0].to_value(
        u.pixel), reference_pixel[1].to_value(u.pixel))

    meta_wcs['cdelt1'], meta_wcs['cdelt2'] = (scale[0].to_value(
        meta_wcs['cunit1'] / u.pixel), scale[1].to_value(meta_wcs['cunit2'] /
                                                         u.pixel))

    if rotation_angle is not None and rotation_matrix is not None:
        raise ValueError(
            "Can not specify both rotation angle and rotation matrix.")

    if rotation_angle is not None:
        lam = meta_wcs['cdelt1'] / meta_wcs['cdelt2']
        p = np.deg2rad(rotation_angle)

        rotation_matrix = np.array([[np.cos(p), -1 * lam * np.sin(p)],
                                    [1 / lam * np.sin(p),
                                     np.cos(p)]])

    if rotation_matrix is not None:
        (meta_wcs['PC1_1'], meta_wcs['PC1_2'], meta_wcs['PC2_1'],
         meta_wcs['PC2_2']) = (rotation_matrix[0, 0], rotation_matrix[0, 1],
                               rotation_matrix[1, 0], rotation_matrix[1, 1])

    meta_dict = MetaDict(meta_wcs)

    return meta_dict
Пример #6
0
def build_meta(wcs, exif_data):
    time = get_image_time(exif_data)
    wcs.wcs.dateobs = time.isoformat()
    header = MetaDict(dict(wcs.to_header()))

    header.update(get_meta_from_exif(exif_data))
    dsun = sunpy.coordinates.sun.earth_distance(time.isoformat())
    lat = header.get('LAT') * u.deg
    lon = header.get('LON') * u.deg
    solar_rotation_angle = get_solar_rotation_angle(lat, lon, time)
    header.update({'crota2': solar_rotation_angle.to('deg').value})
    header.update({'dsun_obs': dsun.to('m').value})
    hgln_obs = 0 * u.deg
    hglt_obs = sunpy.coordinates.sun.B0(time)
    header.update({'hgln_obs': hgln_obs.to('deg').value})
    header.update({'hglt_obs': hglt_obs.to('deg').value})
    header.update({'ctype1': 'HPLN-TAN'})
    header.update({'ctype2': 'HPLT-TAN'})
    header.update({'rsun': dsun.to('m').value})
    header.update({'rsun_obs': np.arctan(sunpy.sun.constants.radius / dsun).to(
        'arcsec').value})
    return header
Пример #7
0
def make_fitswcs_header(data,
                        coordinate,
                        reference_pixel: u.pix = None,
                        scale: u.arcsec / u.pix = None,
                        rotation_angle: u.deg = None,
                        rotation_matrix=None,
                        instrument=None,
                        telescope=None,
                        observatory=None,
                        wavelength: u.angstrom = None,
                        exposure: u.s = None,
                        projection_code="TAN"):
    """
    Function to create a FITS-WCS header from a coordinate object
    (`~astropy.coordinates.SkyCoord`) that is required to
    create a `~sunpy.map.GenericMap`.

    Parameters
    ----------
    data : `~numpy.ndarray` or `tuple`
        Array data of Map for which a header is required, or the shape of the
        data array (in numpy order, i.e. ``(y_size, x_size)``).
    coordinate : `~astropy.coordinates.SkyCoord` or `~astropy.coordinates.BaseCoordinateFrame`
        The coordinate of the reference pixel.
    reference_pixel :`~astropy.units.Quantity` of size 2, optional
        Reference pixel along each axis. These are expected to be Cartestian ordered, i.e
        the first index is the x axis, second index is the y axis. Defaults to
        the center of data array, ``(data.shape[1] - 1)/2., (data.shape[0] - 1)/2.)``,
        this argument is zero indexed (Python convention) not 1 indexed (FITS
        convention).
    scale : `~astropy.units.Quantity` of size 2, optional
        Pixel scaling along x and y axis (i.e. the spatial scale of the pixels (dx, dy)). These are
        expected to be Cartestian ordered, i.e [dx, dy].
        Defaults to ``([1., 1.] arcsec/pixel)``.
    rotation_angle : `~astropy.units.Quantity`, optional
        Coordinate system rotation angle, will be converted to a rotation
        matrix and stored in the ``PCi_j`` matrix. Can not be specified with
        ``rotation_matrix``.
    rotation_matrix : `~numpy.ndarray` of dimensions 2x2, optional
        Matrix describing the rotation required to align solar North with
        the top of the image in FITS ``PCi_j`` convention. Can not be specified
        with ``rotation_angle``.
    instrument : `~str`, optional
        Name of the instrument of the observation.
    telescope : `~str`, optional
        Name of the telescope of the observation.
    observatory : `~str`, optional
        Name of the observatory of the observation.
    wavelength : `~astropy.units.Quantity`, optional
        Wavelength of the observation as an astropy quanitity, e.g. 171*u.angstrom.
        From this keyword, the meta keywords ``wavelnth`` and ``waveunit`` will be populated.
    exposure : `~astropy.units.Quantity`, optional
        Exposure time of the observation
    projection_code : `str`, optional
        The FITS standard projection code for the new header.

    Returns
    -------
    `~sunpy.util.MetaDict`
        The header information required for making a `sunpy.map.GenericMap`.

    Notes
    -----
    The observer coordinate is taken from the observer property of the ``reference_pixel``
    argument.

    Examples
    --------
    >>> import sunpy.map
    >>> from sunpy.coordinates import frames
    >>> from astropy.coordinates import SkyCoord
    >>> import astropy.units as u
    >>> import numpy as np

    >>> data = np.random.rand(1024, 1024)
    >>> my_coord = SkyCoord(0*u.arcsec, 0*u.arcsec, obstime="2017-08-01",
    ...                     observer = 'earth', frame=frames.Helioprojective)
    >>> my_header = sunpy.map.make_fitswcs_header(data, my_coord)
    >>> my_map = sunpy.map.Map(data, my_header)
    """
    coordinate = _validate_coordinate(coordinate)

    if hasattr(data, "shape"):
        shape = data.shape
    else:
        shape = data

    meta_wcs = _get_wcs_meta(coordinate, projection_code)

    meta_wcs = _set_instrument_meta(meta_wcs, instrument, telescope,
                                    observatory, wavelength, exposure)
    meta_wcs = _set_transform_params(meta_wcs, coordinate, reference_pixel,
                                     scale, shape)
    meta_wcs = _set_rotation_params(meta_wcs, rotation_angle, rotation_matrix)

    if getattr(coordinate, 'observer', None) is not None:
        # Have to check for str, as doing == on a SkyCoord and str raises an error
        if isinstance(coordinate.observer,
                      str) and coordinate.observer == 'self':
            dsun_obs = coordinate.radius
        else:
            dsun_obs = coordinate.observer.radius
        meta_wcs['rsun_obs'] = sun._angular_radius(coordinate.rsun,
                                                   dsun_obs).to_value(u.arcsec)

    meta_dict = MetaDict(meta_wcs)
    return meta_dict
Пример #8
0
def make_fitswcs_header(data,
                        coordinate,
                        reference_pixel: u.pix = None,
                        scale: u.arcsec / u.pix = None,
                        **kwargs):
    """
    Function to create a FITS-WCS header from a coordinate object
    (`~astropy.coordinates.SkyCoord`) that is required to
    create a `~sunpy.map.GenericMap`.

    Parameters
    ----------
    data : `~numpy.ndarray`
        Array data of Map for which a header is required.
    coordinates : `~astropy.coordinates.SkyCoord` or `~astropy.coordinates.BaseFrame`
        Coordinate object to get meta information for map header.
    reference_pixel :`~astropy.units.Quantity` of size 2, optional
        Reference pixel along each axis. These are expected to be Cartestian ordered, i.e
        the first index is the x axis, second index is the y axis.
        Defaults to the center of data array, ``(data.shape[1] + 1)/2., (data.shape[0] + 1)/2.)``.
    scale : `~astropy.units.Quantity` of size 2, optional
        Pixel scaling along x and y axis (i.e. the spatial scale of the pixels (dx, dy)). These are
        expected to be Cartestian ordered, i.e [dx, dy].
        Defaults to ``([1., 1.] arcsec/pixel)``.
    **kwargs:
        Additional arguments that will be put into the metadict header if they
        are in the list returned by `~sunpy.map.meta_keywords`. Additional
        keyword arguments for the instrument meta can also be given in the
        following forms which will be translated to fits standard:

        | ``instrument``
        | ``telescope``
        | ``observatory``
        | ``wavelength``
        | ``exposure``

    Returns
    -------
    `~sunpy.util.MetaDict`
        The header information required for making a `sunpy.map.GenericMap`.

    Examples
    --------
    >>> import sunpy.map
    >>> from sunpy.coordinates import frames
    >>> from astropy.coordinates import SkyCoord
    >>> from astropy import units as u
    >>> import numpy as np

    >>> data = np.random.rand(1024, 1024)
    >>> my_coord = SkyCoord(0*u.arcsec, 0*u.arcsec, obstime="2017-08-01",
    ...                     observer = 'earth', frame=frames.Helioprojective)
    >>> my_header = sunpy.map.make_fitswcs_header(data, my_coord)
    >>> my_map = sunpy.map.Map(data, my_header)
    """

    if not isinstance(coordinate, (SkyCoord, frames.BaseCoordinateFrame)):
        raise ValueError(
            "coordinate needs to be a coordinate frame or an SkyCoord instance."
        )

    if isinstance(coordinate, SkyCoord):
        coordinate = coordinate.frame

    if coordinate.obstime is None:
        raise ValueError(
            "The coordinate needs an observation time, `obstime`.")

    if isinstance(coordinate, frames.Heliocentric):
        raise ValueError(
            "This function does not currently support heliocentric coordinates."
        )

    meta_wcs = _get_wcs_meta(coordinate)

    if hasattr(coordinate, "observer") and isinstance(
            coordinate.observer, frames.BaseCoordinateFrame):
        meta_observer = _get_observer_meta(coordinate)
        meta_wcs.update(meta_observer)

    meta_instrument = _get_instrument_meta(**kwargs)
    meta_wcs.update(meta_instrument)

    if reference_pixel is None:
        reference_pixel = u.Quantity([(data.shape[1] + 1) / 2. * u.pixel,
                                      (data.shape[0] + 1) / 2. * u.pixel])
    if scale is None:
        scale = u.Quantity([1.0 * u.arcsec, 1.0 * u.arcsec])

    meta_wcs['crval1'], meta_wcs['crval2'] = (
        coordinate.spherical.lat.to_value(meta_wcs['cunit1']),
        coordinate.spherical.lon.to_value(meta_wcs['cunit2']))

    meta_wcs['crpix1'], meta_wcs['crpix2'] = (reference_pixel[0].to_value(
        u.pixel), reference_pixel[1].to_value(u.pixel))

    meta_wcs['cdelt1'], meta_wcs['cdelt2'] = (scale[0] * meta_wcs['cunit1'] /
                                              u.pixel, scale[1] *
                                              meta_wcs['cunit2'] / u.pixel)

    meta_dict = MetaDict(meta_wcs)

    for key in kwargs:
        if key in _map_meta_keywords:
            meta_dict[key] = kwargs[key]

    return meta_dict