Example #1
0
def distance_accurate50m_numpy(a_lats,
                               a_lons,
                               b_lats,
                               b_lons,
                               implementation='c'):
    ''' Accurate distance calculation based on a spheroid of rotation.

    Function returns distance in meter between points ``a`` and ``b``,
    coordinates of which must be given in geographical coordinates and in
    degrees.
    The returned distance should be accurate to 50\,m using WGS84.
    Values for the Earth's equator radius and the Earth's oblateness
    (``f_oblate``) are defined in the pyrocko configuration file
    :py:class:`pyrocko.config`.

    From wikipedia (http://de.wikipedia.org/wiki/Orthodrome), based on:

    ``Meeus, J.: Astronomical Algorithms, S 85, Willmann-Bell,
    Richmond 2000 (2nd ed., 2nd printing), ISBN 0-943396-61-1``

    .. math::

        F_i = \\frac{\pi}{180} \
                           \\frac{(a_{lat,i} + a_{lat,i})}{2}, \quad \
        G_i = \\frac{\pi}{180}  \
                           \\frac{(a_{lat,i} - b_{lat,i})}{2}, \quad \
        l_i= \\frac{\pi}{180} \
                            \\frac{(a_{lon,i} - b_{lon,i})}{2} \\\\[0.5cm]
        S_i = \\sin^2(G_i) \\cdot \\cos^2(l_i) + \
              \\cos^2(F_i) \\cdot \\sin^2(l_i), \quad \quad
        C_i = \\cos^2(G_i) \\cdot \\cos^2(l_i) + \
                  \\sin^2(F_i) \\cdot \\sin^2(l_i)

    .. math::

        w_i = \\arctan \\left( \\sqrt{\\frac{S_i}{C_i}} \\right), \quad \
        r_i =  \\sqrt{\\frac{S_i}{C_i} }

    The spherical-earth distance ``D`` between ``a`` and ``b``,
    can be given with:

    .. math::

        D_{\\mathrm{sphere},i} = 2w_i \cdot R_{\\mathrm{equator}}

    The oblateness of the Earth requires some correction with
    correction factors ``h1`` and ``h2``:

     .. math::

        h_{1.i} = \\frac{3r - 1}{2C_i}, \quad \
        h_{2,i} = \\frac{3r +1 }{2S_i}\\\\[0.5cm]

        D_{AB,i} = D_{\\mathrm{sphere},i} \cdot [1 + h_{1,i}
            \,f_{\\mathrm{oblate}} \
            \cdot \\sin^2(F_i) \
            \\cos^2(G_i) - h_{2,i}\, f_{\\mathrm{oblate}} \
            \cdot \\cos^2(F_i) \\sin^2(G_i)]

    :param a_lats: Latitudes (degree) point A
    :param a_lons: Longitudes (degree) point A
    :param b_lats: Latitudes (degree) point B
    :param b_lons: Longitudes (degree) point B
    :type a_lats: :py:class:`numpy.ndarray`, ``(N)``
    :type a_lons: :py:class:`numpy.ndarray`, ``(N)``
    :type b_lats: :py:class:`numpy.ndarray`, ``(N)``
    :type b_lons: :py:class:`numpy.ndarray`, ``(N)``

    :return: Distances in degrees
    :rtype: :py:class:`numpy.ndarray`, ``(N)``
    '''

    a_lats, a_lons, b_lats, b_lons = float_array_broadcast(
        a_lats, a_lons, b_lats, b_lons)

    assert implementation in ('c', 'python')
    if implementation == 'c':
        from pyrocko import orthodrome_ext
        return orthodrome_ext.distance_accurate50m_numpy(
            a_lats, a_lons, b_lats, b_lons)

    eq = num.logical_and(a_lats == b_lats, a_lons == b_lons)
    ii_neq = num.where(num.logical_not(eq))[0]

    if num.all(eq):
        return num.zeros_like(eq, dtype=num.float)

    def extr(x):
        if isinstance(x, num.ndarray) and x.size > 1:
            return x[ii_neq]
        else:
            return x

    a_lats = extr(a_lats)
    a_lons = extr(a_lons)
    b_lats = extr(b_lats)
    b_lons = extr(b_lons)

    f = (a_lats + b_lats) * d2r / 2.
    g = (a_lats - b_lats) * d2r / 2.
    h = (a_lons - b_lons) * d2r / 2.

    s = num.sin(g)**2 * num.cos(h)**2 + num.cos(f)**2 * num.sin(h)**2
    c = num.cos(g)**2 * num.cos(h)**2 + num.sin(f)**2 * num.sin(h)**2

    w = num.arctan(num.sqrt(s / c))

    r = num.sqrt(s * c) / w

    d = 2. * w * earthradius_equator
    h1 = (3. * r - 1.) / (2. * c)
    h2 = (3. * r + 1.) / (2. * s)

    dists = num.zeros(eq.size, dtype=num.float)
    dists[ii_neq] = d * (
        1. + earth_oblateness * h1 * num.sin(f)**2 * num.cos(g)**2 -
        earth_oblateness * h2 * num.cos(f)**2 * num.sin(g)**2)

    return dists
Example #2
0
def distance_accurate50m_numpy(
        a_lats, a_lons, b_lats, b_lons, implementation='c'):

    ''' Accurate distance calculation based on a spheroid of rotation.

    Function returns distance in meter between points ``a`` and ``b``,
    coordinates of which must be given in geographical coordinates and in
    degrees.
    The returned distance should be accurate to 50\,m using WGS84.
    Values for the Earth's equator radius and the Earth's oblateness
    (``f_oblate``) are defined in the pyrocko configuration file
    :py:class:`pyrocko.config`.

    From wikipedia (http://de.wikipedia.org/wiki/Orthodrome), based on:

    ``Meeus, J.: Astronomical Algorithms, S 85, Willmann-Bell,
    Richmond 2000 (2nd ed., 2nd printing), ISBN 0-943396-61-1``

    .. math::

        F_i = \\frac{\pi}{180} \
                           \\frac{(a_{lat,i} + a_{lat,i})}{2}, \quad \
        G_i = \\frac{\pi}{180}  \
                           \\frac{(a_{lat,i} - b_{lat,i})}{2}, \quad \
        l_i= \\frac{\pi}{180} \
                            \\frac{(a_{lon,i} - b_{lon,i})}{2} \\\\[0.5cm]
        S_i = \\sin^2(G_i) \\cdot \\cos^2(l_i) + \
              \\cos^2(F_i) \\cdot \\sin^2(l_i), \quad \quad
        C_i = \\cos^2(G_i) \\cdot \\cos^2(l_i) + \
                  \\sin^2(F_i) \\cdot \\sin^2(l_i)

    .. math::

        w_i = \\arctan \\left( \\sqrt{\\frac{S_i}{C_i}} \\right), \quad \
        r_i =  \\sqrt{\\frac{S_i}{C_i} }

    The spherical-earth distance ``D`` between ``a`` and ``b``,
    can be given with:

    .. math::

        D_{\\mathrm{sphere},i} = 2w_i \cdot R_{\\mathrm{equator}}

    The oblateness of the Earth requires some correction with
    correction factors ``h1`` and ``h2``:

     .. math::

        h_{1.i} = \\frac{3r - 1}{2C_i}, \quad \
        h_{2,i} = \\frac{3r +1 }{2S_i}\\\\[0.5cm]

        D_{AB,i} = D_{\\mathrm{sphere},i} \cdot [1 + h_{1,i}
            \,f_{\\mathrm{oblate}} \
            \cdot \\sin^2(F_i) \
            \\cos^2(G_i) - h_{2,i}\, f_{\\mathrm{oblate}} \
            \cdot \\cos^2(F_i) \\sin^2(G_i)]

    :param a_lats: Latitudes (degree) point A
    :param a_lons: Longitudes (degree) point A
    :param b_lats: Latitudes (degree) point B
    :param b_lons: Longitudes (degree) point B
    :type a_lats: :py:class:`numpy.ndarray`, ``(N)``
    :type a_lons: :py:class:`numpy.ndarray`, ``(N)``
    :type b_lats: :py:class:`numpy.ndarray`, ``(N)``
    :type b_lons: :py:class:`numpy.ndarray`, ``(N)``

    :return: Distances in degrees
    :rtype: :py:class:`numpy.ndarray`, ``(N)``
    '''

    a_lats, a_lons, b_lats, b_lons = float_array_broadcast(
        a_lats, a_lons, b_lats, b_lons)

    assert implementation in ('c', 'python')
    if implementation == 'c':
        from pyrocko import orthodrome_ext
        return orthodrome_ext.distance_accurate50m_numpy(
            a_lats, a_lons, b_lats, b_lons)

    eq = num.logical_and(a_lats == b_lats, a_lons == b_lons)
    ii_neq = num.where(num.logical_not(eq))[0]

    if num.all(eq):
        return num.zeros_like(eq, dtype=num.float)

    def extr(x):
        if isinstance(x, num.ndarray) and x.size > 1:
            return x[ii_neq]
        else:
            return x

    a_lats = extr(a_lats)
    a_lons = extr(a_lons)
    b_lats = extr(b_lats)
    b_lons = extr(b_lons)

    f = (a_lats + b_lats)*d2r / 2.
    g = (a_lats - b_lats)*d2r / 2.
    h = (a_lons - b_lons)*d2r / 2.

    s = num.sin(g)**2 * num.cos(h)**2 + num.cos(f)**2 * num.sin(h)**2
    c = num.cos(g)**2 * num.cos(h)**2 + num.sin(f)**2 * num.sin(h)**2

    w = num.arctan(num.sqrt(s/c))

    r = num.sqrt(s*c)/w

    d = 2.*w*earthradius_equator
    h1 = (3.*r-1.)/(2.*c)
    h2 = (3.*r+1.)/(2.*s)

    dists = num.zeros(eq.size, dtype=num.float)
    dists[ii_neq] = d * (
        1. +
        earth_oblateness * h1 * num.sin(f)**2 * num.cos(g)**2 -
        earth_oblateness * h2 * num.cos(f)**2 * num.sin(g)**2)

    return dists