Source code for mrspoc.sun

"""
Methods for drawing from the sunspot latitude and radius distribution
"""
import numpy as np
import astropy.units as u


__all__ = ['draw_random_sunspot_latitudes', 'draw_random_sunspot_radii']


@u.quantity_input(theta=u.rad, phi=u.rad)
def rtp_to_edge(radius, theta, phi, n_points=1000):
    """
    Use the haversine formula to compute the boundary lat/lon coordinates for a
    circular spot centered on ``(theta, phi)``, with radius ``radius` in units
    of the stellar radius.

    Parameters
    ----------
    radius : float
        Spot radius [R_star]
    theta : `~astropy.units.Quantity`
        Spot theta coord (90 deg - latitude)
    phi : `~astropy.units.Quantity`
        Spot phi coord (longitude)
    n_points : int
        Number of points to include in the circle boundary

    Returns
    -------
    lat : `~astropy.units.Quantity`
        Latitudes of spot boundary
    lon : `~astropy.units.Quantity`
        Longitudes of spot boundary
    """
    lat1 = np.pi/2 - theta.to(u.rad).value
    lon1 = phi.to(u.rad).value
    d = radius

    thetas = np.linspace(0, -2*np.pi, n_points)[:, np.newaxis]

    lat = np.arcsin(np.sin(lat1) * np.cos(d) + np.cos(lat1) *
                    np.sin(d) * np.cos(thetas))
    dlon = np.arctan2(np.sin(thetas) * np.sin(d) * np.cos(lat1),
                      np.cos(d) - np.sin(lat1) * np.sin(lat))
    lon = ((lon1 - dlon + np.pi) % (2*np.pi)) - np.pi
    return lat*u.rad, lon*u.rad


def generate_random_coord(n=1):
    """
    Generate random latitude/longitude pairs, of length ``n``.
    """
    random_longitude = 2*np.pi*np.random.rand(n)
    random_z = 2*np.random.rand(n) - 1
    random_latitude = np.arcsin(random_z)
    result = np.vstack([random_latitude, random_longitude]).T * u.rad

    if result.shape[0] == 1:
        return result[0]
    return result


def sunspot_distribution(latitude, mean_latitude=15):
    """
    Approximate un-normalized probability distribution of sunspots at
    ``latitude`` near activity maximum on the Sun.

    Parameters
    ----------
    latitude : `~numpy.ndarray`
        Latitude

    mean_latitude : float
        Mean active latitude in degrees

    Returns
    -------
    p : `~numpy.ndarray
        Probability (un-normalized)
    """
    return np.exp(-0.5 * (abs(latitude) - mean_latitude)**2 / 6**2)


def sunspot_latitude_inverse_transform(x, mean_latitude=15):
    """
    Use inverse transform sampling to randomly draw spot latitudes from the
    sunspot latitude distribution, for a uniform random variate ``x`` on the
    range [0,1).

    Parameters
    ----------
    x : `~np.ndarray` or float
        Uniform random variate on [0, 1)

    Returns
    -------
    lat : `~astropy.units.Quantity`
        Latitude of a sunspot drawn from the sunspot latitude distribution.
    """
    lats = np.linspace(-88, 88, 1000)
    prob = np.cumsum(sunspot_distribution(lats, mean_latitude=mean_latitude))
    prob /= np.max(prob)
    return np.interp(x, prob, lats) * u.deg


[docs]def draw_random_sunspot_latitudes(n, mean_latitude=15): """ Draw one or more random samples from the sunspot latitude distribution. Parameters ---------- n : int Number of random sunspot latitudes to draw Returns ------- lat : `~astropy.units.Quantity` Latitude of a sunspot drawn from the sunspot latitude distribution. """ return sunspot_latitude_inverse_transform(np.random.rand(n), mean_latitude=mean_latitude)
def sunspot_umbral_area_distribution(log_area_uhem): """ Approximate log-normal distribution of sunspot umbral areas """ return np.exp(-0.5 * (log_area_uhem - 4.1)**2 / 1.0**2) def sunspot_umbral_area_inverse_transform(x): """ Use inverse transform sampling to randomly draw spot areas from the sunspot umbral area distribution, for a uniform random variate ``x`` on the range [0,1). Parameters ---------- x : `~np.ndarray` or float Uniform random variate on [0, 1) Returns ------- umbral_areas : `~numpy.ndarray` Umbral area(s) of sunspot(s) drawn from the sunspot umbral area distribution. """ log_areas_uhem = np.linspace(0, 9, 1000) prob = np.cumsum(sunspot_umbral_area_distribution(log_areas_uhem)) prob /= np.max(prob) return np.interp(x, prob, log_areas_uhem)
[docs]def draw_random_sunspot_radii(n): """ Draw one or more random samples from the sunspot radius distribution. Parameters ---------- n : int Number of random sunspot radii to draw Returns ------- rspot_rstar : `~numpy.ndarray` Radii of a sunspots drawn from the sunspot radius distribution, in units of stellar radii. """ umbral_areas_uhem = sunspot_umbral_area_inverse_transform(np.random.rand(n)) total_to_umbral_area = 5 # ratio of total spot area to area in umbra rspot_rstar = np.sqrt(1e-6 * 2 * total_to_umbral_area * umbral_areas_uhem) return rspot_rstar