Exemplo n.º 1
0
def test_hgs_hgc_sunspice():
    # Compare our HGS->HGC transformation against SunSPICE
    # "HEQ" is another name for HEEQ, which is equivalent to Heliographic Stonyhurst
    # "Carrington" does not include light travel time to the observer, which our HGC includes
    #
    # IDL> coord = [1.d, 0.d, 10.d]
    # IDL> convert_sunspice_lonlat, '2019-06-01', coord, 'HEQ', 'Carrington', /au, /degrees
    # IDL> print, coord
    #        1.0000000       16.688242       10.000000

    old = SkyCoord(0 * u.deg,
                   10 * u.deg,
                   1 * u.AU,
                   frame=HeliographicStonyhurst(obstime='2019-06-01'))
    new = old.transform_to(HeliographicCarrington(observer='earth'))

    # Calculate the difference in longitude due to light travel time from the Sun to the Earth
    delta_lon = sidereal_rotation_rate * (sun.earth_distance(old.obstime) -
                                          _RSUN) / speed_of_light

    assert_quantity_allclose(new.lon,
                             16.688242 * u.deg + delta_lon,
                             atol=1e-2 * u.arcsec,
                             rtol=0)
    assert_quantity_allclose(new.lat, old.lat)
    assert_quantity_allclose(new.radius, old.radius)
Exemplo n.º 2
0
def test_hgc_self_observer():
    # Test specifying observer='self' for HGC
    obstime = Time('2001-01-01')
    hgc = HeliographicCarrington(10 * u.deg,
                                 20 * u.deg,
                                 3 * u.AU,
                                 observer='self',
                                 obstime=obstime)

    # Transform to HGS (i.e., observer='self' in the source frame)
    hgs = hgc.transform_to(HeliographicStonyhurst(obstime=obstime))

    # Manually calculate the post-transformation longitude
    lon = sun.L0(obstime,
                 light_travel_time_correction=False,
                 nearest_point=False,
                 aberration_correction=False)
    lon += (hgc.radius - _RSUN) / speed_of_light * sidereal_rotation_rate

    assert_quantity_allclose(Longitude(hgs.lon + lon), hgc.lon)
    assert_quantity_allclose(hgs.lat, hgc.lat)
    assert_quantity_allclose(hgs.radius, hgc.radius)

    # Transform back to HGC (i.e., observer='self' in the destination frame)
    hgc_loop = hgs.transform_to(hgc.replicate_without_data())

    assert_quantity_allclose(hgc_loop.lon, hgc.lon)
    assert_quantity_allclose(hgc_loop.lat, hgc.lat)
    assert_quantity_allclose(hgc_loop.radius, hgc.radius)
Exemplo n.º 3
0
def test_transform_with_sun_center():
    sun_center = SkyCoord(0 * u.deg,
                          0 * u.deg,
                          0 * u.AU,
                          frame=HeliographicStonyhurst(obstime="2001-01-01"))

    with transform_with_sun_center():
        result1 = sun_center.transform_to(
            HeliographicStonyhurst(obstime="2001-02-01"))

    # The coordinate should stay pointing at Sun center
    assert_quantity_allclose(result1.lon, sun_center.lon)
    assert_quantity_allclose(result1.lat, sun_center.lat)
    assert_quantity_allclose(result1.radius, sun_center.radius)

    other = SkyCoord(10 * u.deg,
                     20 * u.deg,
                     1 * u.AU,
                     frame=HeliographicStonyhurst(obstime="2001-01-01"))

    with transform_with_sun_center():
        result2 = other.transform_to(
            HeliographicCarrington(observer='earth', obstime="2001-02-01"))

    # The coordinate should stay at the same latitude and the same distance from Sun center
    assert_quantity_allclose(result2.lat, other.lat)
    assert_quantity_allclose(result2.radius, other.radius)
Exemplo n.º 4
0
def test_hgs_cartesian_rep_to_hgc():
    # This test checks transformation HGS->HCC when the coordinate is in a Cartesian
    # representation and that it is the same as a transformation from an HGS frame with a
    # spherical representation

    obstime = "2011-01-01"
    hgscoord_cart = SkyCoord(x=1*u.km, y=0.*u.km, z=0.*u.km,
                             frame=HeliographicStonyhurst(obstime=obstime),
                             representation_type='cartesian')
    hgscoord_sph = hgscoord_cart.copy()
    hgscoord_sph.representation_type = 'spherical'
    # HGC
    hgccoord_cart = hgscoord_cart.transform_to(HeliographicCarrington(obstime=obstime))
    hgccoord_sph = hgscoord_sph.transform_to(HeliographicCarrington(obstime=obstime))
    assert_quantity_allclose(hgccoord_cart.lat, hgccoord_sph.lat)
    assert_quantity_allclose(hgccoord_cart.lon, hgccoord_sph.lon)
    assert_quantity_allclose(hgccoord_cart.radius, hgccoord_sph.radius)
Exemplo n.º 5
0
def test_hgc_hgc():
    # Test HGC loopback transformation
    obstime = Time('2001-01-01')
    old = SkyCoord(90 * u.deg,
                   10 * u.deg,
                   1 * u.AU,
                   frame=HeliographicCarrington(observer='earth',
                                                obstime=obstime))
    new = old.transform_to(
        HeliographicCarrington(observer='earth', obstime=obstime + 1 * u.day))

    assert_quantity_allclose(new.lon, 75.815607 * u.deg,
                             atol=1e-7 * u.deg)  # solar rotation
    # These are not equal to the old values, because the coordinates stay fixed
    # in inertial space, whilst the frame (fixed to the center of the Sun)
    # moves slightly.
    assert_quantity_allclose(new.lat, 9.999963 * u.deg, atol=1e-7 * u.deg)
    assert_quantity_allclose(new.radius, 1.000009 * u.AU, atol=1e-7 * u.AU)
Exemplo n.º 6
0
def test_hgc_hgc_different_observers():
    obstime = Time('2001-01-01')
    hgc_earth = HeliographicCarrington(observer='earth', obstime=obstime)
    hgc_mars = HeliographicCarrington(observer='mars', obstime=obstime)
    hgc_sun = HeliographicCarrington(observer='sun', obstime=obstime)

    sc = SkyCoord(10*u.deg, 20*u.deg, 1*u.AU, frame=HeliographicStonyhurst(obstime=obstime))
    sc_hgc_earth = sc.transform_to(hgc_earth)

    sc_hgc_mars = sc_hgc_earth.transform_to(hgc_mars)

    sc_hgc_sun = sc_hgc_mars.transform_to(hgc_sun)

    ltt_earth = hgc_earth.observer.radius / speed_of_light
    assert_quantity_allclose(sc_hgc_earth.lon - sc_hgc_sun.lon, ltt_earth * sidereal_rotation_rate)

    ltt_mars = hgc_mars.observer.radius / speed_of_light
    assert_quantity_allclose(sc_hgc_mars.lon - sc_hgc_sun.lon, ltt_mars * sidereal_rotation_rate)
Exemplo n.º 7
0
def test_hgc_loopback_self_observer():
    # Test the HGC loopback where only one end has observer='self'
    obstime = Time('2001-01-01')
    coord = HeliographicCarrington(10 * u.deg,
                                   20 * u.deg,
                                   3 * u.AU,
                                   observer='self',
                                   obstime=obstime)

    new_observer = HeliographicStonyhurst(40 * u.deg, 50 * u.deg, 6 * u.AU)
    new_frame = HeliographicCarrington(observer=new_observer, obstime=obstime)

    new_coord = coord.transform_to(new_frame)

    # Manually calculate the longitude shift due to the difference in Sun-observer distance
    lon = (6 * u.AU - 3 * u.AU) / speed_of_light * sidereal_rotation_rate

    assert_quantity_allclose(new_coord.lon, coord.lon + lon)
    assert_quantity_allclose(new_coord.lat, coord.lat)
    assert_quantity_allclose(new_coord.radius, coord.radius)
Exemplo n.º 8
0
def test_hgs_hgc_roundtrip():
    obstime = "2011-01-01"

    hgsin = HeliographicStonyhurst(lat=10*u.deg, lon=20*u.deg, obstime=obstime)
    hgcout = hgsin.transform_to(HeliographicCarrington(obstime=obstime))

    assert_quantity_allclose(hgsin.lat, hgcout.lat)
    assert_quantity_allclose(hgsin.lon + sun.L0(obstime), hgcout.lon)

    hgsout = hgcout.transform_to(HeliographicStonyhurst(obstime=obstime))

    assert_quantity_allclose(hgsout.lat, hgsin.lat)
    assert_quantity_allclose(hgsout.lon, hgsin.lon)
Exemplo n.º 9
0
def test_rsun_preservation():
    # Check that rsun is preserved when transforming between any two frames with that attribute
    args_in = {'obstime': '2001-01-01', 'rsun': 690*u.Mm}
    args_out = {'obstime': '2001-02-01', 'rsun': 700*u.Mm}

    coords_in = [Helioprojective(0*u.deg, 0*u.deg, 1*u.AU, observer='earth', **args_in),
                 HeliographicStonyhurst(0*u.deg, 0*u.deg, 1*u.AU, **args_in),
                 HeliographicCarrington(0*u.deg, 0*u.deg, 1*u.AU, observer='earth', **args_in)]

    for coord in coords_in:
        for frame in coords_in:
            out_coord = coord.transform_to(frame.replicate(**args_out))
            assert_quantity_allclose(out_coord.rsun, args_out['rsun'])
Exemplo n.º 10
0
def test_velocity_hgs_hgc():
    # Construct a simple HGS coordinate with zero velocity
    obstime = Time(['2019-01-01', '2019-04-01', '2019-07-01', '2019-10-01'])
    pos = CartesianRepresentation(1, 0, 0)*u.AU
    vel = CartesianDifferential(0, 0, 0)*u.km/u.s
    loc = (pos.with_differentials(vel))._apply('repeat', obstime.size)
    coord = SkyCoord(HeliographicStonyhurst(loc, obstime=obstime))

    # The induced velocity in HGC should be entirely longitudinal, and approximately equal to one
    # full rotation every mean synodic period (27.2753 days)
    hgc_frame = HeliographicCarrington(observer='earth', obstime=obstime)
    new = coord.transform_to(hgc_frame)
    new_vel = new.data.differentials['s'].represent_as(SphericalDifferential, new.data)
    assert_quantity_allclose(new_vel.d_lon, -360*u.deg / (27.27253*u.day), rtol=1e-2)
    assert_quantity_allclose(new_vel.d_lat, 0*u.deg/u.s)
    assert_quantity_allclose(new_vel.d_distance, 0*u.km/u.s, atol=1e-7*u.km/u.s)
Exemplo n.º 11
0
def prime_meridian(axes, *, rsun: u.m = R_sun, resolution=500, **kwargs):
    """
    Draws the solar prime meridian (zero Carrington longitude) as seen by the
    axes observer. Hidden parts are drawn as a dotted line.

    Parameters
    ----------
    axes : `matplotlib.axes.Axes`
        The axes to plot the prime meridian on, or "None" to use current axes.
    rsun : `~astropy.units.Quantity`
        Solar radius (in physical length units) at which to draw the solar
        prime meridian. Defaults to the standard photospheric radius.
    resolution : `int`
        The number of points used to represent the prime meridian.

    Returns
    -------
    visible : `~matplotlib.patches.Polygon`
        The patch added to the axes for the visible part of the solar equator.
    hidden : `~matplotlib.patches.Polygon`
        The patch added to the axes for the hidden part of the solar equator.
    """
    if not wcsaxes_compat.is_wcsaxes(axes):
        raise ValueError('axes must be a WCSAxes')
    axes_frame = wcsapi_to_celestial_frame(axes.wcs)

    if not hasattr(axes_frame, 'observer'):
        raise ValueError(
            'the coordinate frame of the WCSAxes does not have an observer, '
            'so zero Carrington longitude cannot be determined.')
    observer = axes_frame.observer

    lon = 0 * u.deg
    lon0 = SkyCoord(np.ones(resolution) * lon,
                    np.linspace(-90, 90, resolution) * u.deg,
                    radius=rsun,
                    frame=HeliographicCarrington(observer=observer,
                                                 obstime=axes_frame.obstime))
    visible, hidden = _plot_vertices(lon0,
                                     axes,
                                     axes_frame,
                                     rsun,
                                     close_path=False,
                                     **kwargs)
    return visible, hidden
Exemplo n.º 12
0
def from_pfsspack(pfss_fieldlines):
    """
    Convert fieldline coordinates output from the SSW package `pfss <http://www.lmsal.com/~derosa/pfsspack/>`_ 
    into `~astropy.coordinates.SkyCoord` objects.

    Parameters
    ----------
    pfss_fieldlines : `~numpy.recarray`
        Structure produced by reading pfss output with `~scipy.io.readsav`

    Returns
    -------
    fieldlines : `list`
        Each entry is a `tuple` containing a `~astropy.coordinates.SkyCoord` object and a
        `~astropy.units.Quantity` object listing the coordinates and field strength along the loop.
    """
    # Fieldline coordinates
    num_fieldlines = pfss_fieldlines['ptr'].shape[0]
    fieldlines = []
    for i in range(num_fieldlines):
        # NOTE: For an unknown reason, there are a number of invalid points for each line output
        # by pfss
        n_valid = pfss_fieldlines['nstep'][i]
        lon = (pfss_fieldlines['ptph'][i, :] * u.radian).to(u.deg)[:n_valid]
        lat = 90 * u.deg - (pfss_fieldlines['ptth'][i, :] * u.radian).to(
            u.deg)[:n_valid]
        radius = ((pfss_fieldlines['ptr'][i, :]) *
                  const.R_sun.to(u.cm))[:n_valid]
        coord = SkyCoord(
            lon=lon,
            lat=lat,
            radius=radius,
            frame=HeliographicCarrington(obstime=sunpy.time.parse_time(
                pfss_fieldlines['now'].decode('utf-8'))))
        fieldlines.append(coord)

    # Magnetic field strengths
    lon_grid = (pfss_fieldlines['phi'] * u.radian - np.pi * u.radian).to(
        u.deg).value
    lat_grid = (np.pi / 2. * u.radian -
                pfss_fieldlines['theta'] * u.radian).to(u.deg).value
    radius_grid = pfss_fieldlines['rix'] * const.R_sun.to(u.cm).value
    B_radius = pfss_fieldlines['br']
    B_lat = pfss_fieldlines['bth']
    B_lon = pfss_fieldlines['bph']
    # Create interpolators
    B_radius_interpolator = RegularGridInterpolator(
        (radius_grid, lat_grid, lon_grid),
        B_radius,
        bounds_error=False,
        fill_value=None)
    B_lat_interpolator = RegularGridInterpolator(
        (radius_grid, lat_grid, lon_grid),
        B_lat,
        bounds_error=False,
        fill_value=None)
    B_lon_interpolator = RegularGridInterpolator(
        (radius_grid, lat_grid, lon_grid),
        B_lon,
        bounds_error=False,
        fill_value=None)
    # Interpolate values through each line
    field_strengths = []
    for f in fieldlines:
        points = np.stack([
            f.spherical.distance.to(u.cm).value,
            f.spherical.lat.to(u.deg).value,
            f.spherical.lon.to(u.deg).value
        ],
                          axis=1)
        b_r = B_radius_interpolator(points)
        b_lat = B_lat_interpolator(points)
        b_lon = B_lon_interpolator(points)
        field_strengths.append(np.sqrt(b_r**2 + b_lat**2 + b_lon**2) * u.Gauss)

    return [(l, b) for l, b in zip(fieldlines, field_strengths)]
Exemplo n.º 13
0
###############################################################################
# Next we will reproject both maps on to a Carrington frame of reference.
# To do this we start by creating a FITS world coordinat system (WCS) header
# corresponding to the output coordinate frame.

# This is set deliberately low, and (at the cost of memory and processing time)
# can be increased to increase the output resolution
shape_out = (360, 720)
ref_coord_observer = HeliographicStonyhurst(0 * u.deg,
                                            0 * u.deg,
                                            sunpy.sun.constants.radius,
                                            obstime=eui_map.date)
ref_coord = HeliographicCarrington(0 * u.deg,
                                   0 * u.deg,
                                   sunpy.sun.constants.radius,
                                   obstime=eui_map.date,
                                   observer=ref_coord_observer)

header = sunpy.map.make_fitswcs_header(
    shape_out,
    ref_coord,
    scale=[180 / shape_out[0], 360 / shape_out[1]] * u.deg / u.pix,
    projection_code="CAR")
out_wcs = WCS(header)

###############################################################################
# Next we reproject and add together the two maps
array, footprint = reproject_and_coadd([eui_map, aia_map],
                                       out_wcs,
                                       shape_out,
Exemplo n.º 14
0
def wcsaxes_heliographic_overlay(axes,
                                 grid_spacing: u.deg = 10 * u.deg,
                                 annotate=True,
                                 obstime=None,
                                 rsun=None,
                                 observer=None,
                                 system='stonyhurst',
                                 **kwargs):
    """
    Create a heliographic overlay using
    `~astropy.visualization.wcsaxes.WCSAxes`.

    Will draw a grid and label the top axes.

    Parameters
    ----------
    axes : `~astropy.visualization.wcsaxes.WCSAxes`
        The `~astropy.visualization.wcsaxes.WCSAxes` object to create the overlay on.
    grid_spacing: `~astropy.units.Quantity`
        Spacing for longitude and latitude grid in degrees.
    annotate : `bool`
        Passing `False` disables the axes labels and the ticks on the top and right axes.
    obstime : `~astropy.time.Time`
        The ``obstime`` to use for the grid coordinate frame.
    rsun : `~astropy.units.Quantity`
        The ``rsun`` to use for the grid coordinate frame.
    observer : `~astropy.coordinates.SkyCoord`
        The ``observer`` to use for the grid coordinate frame. Only used for
        Carrington coordinates.
    system : str
        Coordinate system for the grid. Must be 'stonyhurst' or 'carrington'.
        If 'carrington', the ``observer`` keyword argument must be specified.
    kwargs :
        Additional keyword arguments are passed to
        :meth:`astropy.visualization.wcsaxes.CoordinateHelper.grid`.

    Returns
    -------
    `~astropy.visualization.wcsaxes.WCSAxes`
        The overlay object.

    Notes
    -----
    Keywords are passed to `~astropy.visualization.wcsaxes.coordinates_map.CoordinatesMap.grid`.
    """
    # Unpack spacing
    if isinstance(grid_spacing, u.Quantity) and grid_spacing.size == 1:
        lon_space = lat_space = grid_spacing
    elif grid_spacing.size == 2:
        lon_space, lat_space = grid_spacing
    else:
        raise ValueError(
            "grid_spacing must be a Quantity of length one or two.")

    if system == 'stonyhurst':
        overlay = axes.get_coords_overlay(
            HeliographicStonyhurst(obstime=obstime, rsun=rsun))
    elif system == 'carrington':
        overlay = axes.get_coords_overlay(
            HeliographicCarrington(obstime=obstime,
                                   observer=observer,
                                   rsun=rsun))
    else:
        raise ValueError(
            f"system must be 'stonyhurst' or 'carrington' (got '{system}')")

    # Set the native coordinates to be bottom and left only so they don't share
    # axes with the overlay.
    c1, c2 = axes.coords
    c1.set_ticks_position('bl')
    c2.set_ticks_position('bl')

    lon = overlay[0]
    lat = overlay[1]

    lon.coord_wrap = 180
    lon.set_major_formatter('dd')

    if annotate:
        lon.set_axislabel(f'{system.capitalize()} Longitude', minpad=0.8)
        lat.set_axislabel(f'{system.capitalize()} Latitude', minpad=0.9)
        lon.set_ticks_position('tr')
        lat.set_ticks_position('tr')
    else:
        lat.set_ticks_visible(False)
        lon.set_ticks_visible(False)
        lat.set_ticklabel_visible(False)
        lon.set_ticklabel_visible(False)

    grid_kw = {'color': 'white', 'zorder': 100, 'alpha': 0.5}
    grid_kw.update(kwargs)

    # Don't plot white ticks by default (only if explicitly asked)
    tick_color = grid_kw['color'] if 'color' in kwargs else 'k'
    lon.set_ticks(spacing=lon_space, color=tick_color)
    lat.set_ticks(spacing=lat_space, color=tick_color)

    overlay.grid(**grid_kw)

    if axes.title:
        x, y = axes.title.get_position()
        axes.title.set_position([x, y + 0.08])

    return overlay