Exemplo n.º 1
0
    def get_ry0_distance(self, mesh):
        """
        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Ry0-distance to.
        :returns:
            Numpy array of distances in km.

        See also :meth:`superclass method <.base.BaseSurface.get_ry0_distance>`
        for spec of input and result values.

        This is version specific to the planar surface doesn't make use of the
        mesh
        """
        dst1 = geodetic.distance_to_arc(self.top_left.longitude,
                                        self.top_left.latitude,
                                        (self.strike + 90.) % 360, mesh.lons,
                                        mesh.lats)

        dst2 = geodetic.distance_to_arc(self.top_right.longitude,
                                        self.top_right.latitude,
                                        (self.strike + 90.) % 360, mesh.lons,
                                        mesh.lats)
        # Find the points on the rupture

        # Get the shortest distance from the two lines
        idx = numpy.sign(dst1) == numpy.sign(dst2)
        dst = numpy.zeros_like(dst1)
        dst[idx] = numpy.fmin(numpy.abs(dst1[idx]), numpy.abs(dst2[idx]))
        return dst
Exemplo n.º 2
0
    def get_ry0_distance(self, mesh):
        """
        Compute the minimum distance between each point of a mesh and the great
        circle arcs perpendicular to the average strike direction of the
        fault trace and passing through the end-points of the trace.

        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Ry0-distance to.
        :returns:
            Numpy array of distances in km.
        """
        # This computes ry0 by using an average strike direction
        top_edge = self.mesh[0:1]
        mean_strike = self.get_strike()

        dst1 = geodetic.distance_to_arc(top_edge.lons[0, 0], top_edge.lats[0,
                                                                           0],
                                        (mean_strike + 90.) % 360, mesh.lons,
                                        mesh.lats)

        dst2 = geodetic.distance_to_arc(top_edge.lons[0,
                                                      -1], top_edge.lats[0,
                                                                         -1],
                                        (mean_strike + 90.) % 360, mesh.lons,
                                        mesh.lats)
        # Find the points on the rupture

        # Get the shortest distance from the two lines
        idx = numpy.sign(dst1) == numpy.sign(dst2)
        dst = numpy.zeros_like(dst1)
        dst[idx] = numpy.fmin(numpy.abs(dst1[idx]), numpy.abs(dst2[idx]))

        return dst
Exemplo n.º 3
0
def calc_ry0_distance(P0, P1, lat, lon, dep):
    """Calculate Ry0 distance.

    Compute the minimum distance between sites (lat, lon, dep) and the great
    circle arcs perpendicular to the average strike direction of the
    fault trace and passing through the end-points of the trace.
    
    :param P0:
      Point object, representing the first top-edge vertex of a fault quadrilateral.
    :param P1:
      Point object, representing the second top-edge vertex of a fault quadrilateral.
    :param lat: 
      Numpy array of latitude. 
    :param lon: 
      Numpy array of longitude. 
    :param dep: 
      Numpy array of depths (km). 
    :returns:
      Array of size lon.shape of distances (in km) from input points to rupture surface.
    """
    
    # Strike
    surfaceP0 = point.Point(P0.longitude, P0.latitude, 0.0)
    surfaceP1 = point.Point(P1.longitude, P1.latitude, 0.0)
    strike = P0.azimuth(P1)
    dst1 = geodetic.distance_to_arc(P0.longitude,P0.latitude,
                                    (strike + 90.) % 360, lon, lat)
    dst2 = geodetic.distance_to_arc(P1.longitude,P1.latitude,
                                    (strike + 90.) % 360, lon, lat)
    # Get the shortest distance from the two lines
    idx = np.sign(dst1) == np.sign(dst2)
    dst = np.zeros_like(dst1)
    dst[idx] = np.fmin(np.abs(dst1[idx]), np.abs(dst2[idx]))
    return dst
Exemplo n.º 4
0
    def get_ry0_distance(self, mesh):
        """
        Compute the minimum distance between each point of a mesh and the great
        circle arcs perpendicular to the average strike direction of the
        fault trace and passing through the end-points of the trace.

        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Ry0-distance to.
        :returns:
            Numpy array of distances in km.
        """
        # This computes ry0 by using an average strike direction
        top_edge = self.mesh[0:1]
        mean_strike = self.get_strike()

        dst1 = geodetic.distance_to_arc(top_edge.lons[0, 0],
                                        top_edge.lats[0, 0],
                                        (mean_strike + 90.) % 360,
                                        mesh.lons, mesh.lats)

        dst2 = geodetic.distance_to_arc(top_edge.lons[0, -1],
                                        top_edge.lats[0, -1],
                                        (mean_strike + 90.) % 360,
                                        mesh.lons, mesh.lats)
        # Find the points on the rupture

        # Get the shortest distance from the two lines
        idx = numpy.sign(dst1) == numpy.sign(dst2)
        dst = numpy.zeros_like(dst1)
        dst[idx] = numpy.fmin(numpy.abs(dst1[idx]), numpy.abs(dst2[idx]))

        return dst
Exemplo n.º 5
0
    def get_ry0_distance(self, mesh):
        """
        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Ry0-distance to.
        :returns:
            Numpy array of distances in km.

        See also :meth:`superclass method <.base.BaseSurface.get_ry0_distance>`
        for spec of input and result values.

        This method uses an average strike direction to compute ry0.
        """
        # This computes ry0 by using an average strike direction
        top_edge = self.get_mesh()[0:1]
        mean_strike = self.get_strike()

        dst1 = geodetic.distance_to_arc(top_edge.lons[0, 0],
                                        top_edge.lats[0, 0],
                                        (mean_strike + 90.) % 360,
                                        mesh.lons, mesh.lats)

        dst2 = geodetic.distance_to_arc(top_edge.lons[0, -1],
                                        top_edge.lats[0, -1],
                                        (mean_strike + 90.) % 360,
                                        mesh.lons, mesh.lats)
        # Find the points on the rupture

        # Get the shortest distance from the two lines
        idx = numpy.sign(dst1) == numpy.sign(dst2)
        dst = numpy.zeros_like(dst1)
        dst[idx] = numpy.fmin(numpy.abs(dst1[idx]), numpy.abs(dst2[idx]))

        return dst
Exemplo n.º 6
0
def calc_ry0_distance(P0, P1, lat, lon, dep):
    """Calculate Ry0 distance.

    Compute the minimum distance between sites (lat, lon, dep) and the great
    circle arcs perpendicular to the average strike direction of the
    fault trace and passing through the end-points of the trace.
    
    :param P0:
      Point object, representing the first top-edge vertex of a fault quadrilateral.
    :param P1:
      Point object, representing the second top-edge vertex of a fault quadrilateral.
    :param lat: 
      Numpy array of latitude. 
    :param lon: 
      Numpy array of longitude. 
    :param dep: 
      Numpy array of depths (km). 
    :returns:
      Array of size lon.shape of distances (in km) from input points to rupture surface.
    """

    # Strike
    surfaceP0 = point.Point(P0.longitude, P0.latitude, 0.0)
    surfaceP1 = point.Point(P1.longitude, P1.latitude, 0.0)
    strike = P0.azimuth(P1)
    dst1 = geodetic.distance_to_arc(P0.longitude, P0.latitude,
                                    (strike + 90.) % 360, lon, lat)
    dst2 = geodetic.distance_to_arc(P1.longitude, P1.latitude,
                                    (strike + 90.) % 360, lon, lat)
    # Get the shortest distance from the two lines
    idx = np.sign(dst1) == np.sign(dst2)
    dst = np.zeros_like(dst1)
    dst[idx] = np.fmin(np.abs(dst1[idx]), np.abs(dst2[idx]))
    return dst
Exemplo n.º 7
0
 def test_one_point(self):
     dist = geodetic.distance_to_arc(12.3, 44.5, 39.4,
                                     plons=13.4, plats=46.9)
     self.assertAlmostEqual(dist, -105.12464364)
     dist = geodetic.distance_to_arc(12.3, 44.5, 39.4,
                                     plons=13.4, plats=44.9)
     self.assertAlmostEqual(dist, 38.34459954)
Exemplo n.º 8
0
 def test_one_point(self):
     dist = geodetic.distance_to_arc(12.3, 44.5, 39.4,
                                     plons=13.4, plats=46.9)
     self.assertAlmostEqual(dist, -105.12464364)
     dist = geodetic.distance_to_arc(12.3, 44.5, 39.4,
                                     plons=13.4, plats=44.9)
     self.assertAlmostEqual(dist, 38.34459954)
Exemplo n.º 9
0
    def get_ry0_distance(self, mesh):
        """
        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Ry0-distance to.
        :returns:
            Numpy array of distances in km.

        See also :meth:`superclass method <.base.BaseSurface.get_ry0_distance>`
        for spec of input and result values.

        This is version specific to the planar surface doesn't make use of the
        mesh
        """
        dst1 = geodetic.distance_to_arc(self.top_left.longitude,
                                        self.top_left.latitude,
                                        (self.strike + 90.) % 360,
                                        mesh.lons, mesh.lats)

        dst2 = geodetic.distance_to_arc(self.top_right.longitude,
                                        self.top_right.latitude,
                                        (self.strike + 90.) % 360,
                                        mesh.lons, mesh.lats)
        # Find the points on the rupture

        # Get the shortest distance from the two lines
        idx = numpy.sign(dst1) == numpy.sign(dst2)
        dst = numpy.zeros_like(dst1)
        dst[idx] = numpy.fmin(numpy.abs(dst1[idx]), numpy.abs(dst2[idx]))
        return dst
Exemplo n.º 10
0
    def get_ry0_distance(self, mesh):
        """
        Compute the minimum distance between each point of a mesh and the great
        circle arcs perpendicular to the average strike direction of the
        fault trace and passing through the end-points of the trace.

        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Ry0-distance to.
        :returns:
            Numpy array of distances in km.
        """

        # This computes ry0 by using an average strike direction
        top_edge = self.mesh[0:1]
        mean_strike = self.get_strike()

        # Manage the case of kite fault surfaces
        ia = 0
        ib = -1
        if (self.__class__.__name__ == 'KiteSurface'):
            idx = numpy.nonzero(numpy.isfinite(top_edge.lons[0, :]))[0]
            ia = min(idx)
            ib = max(idx)

        # Computing the distances between the sites and the two lines
        # perpendicular to the strike passing trough the two extremes
        # of the top of the rupture
        dst1 = geodetic.distance_to_arc(top_edge.lons[0,
                                                      ia], top_edge.lats[0,
                                                                         ia],
                                        (mean_strike + 90.) % 360, mesh.lons,
                                        mesh.lats)

        dst2 = geodetic.distance_to_arc(top_edge.lons[0,
                                                      ib], top_edge.lats[0,
                                                                         ib],
                                        (mean_strike + 90.) % 360, mesh.lons,
                                        mesh.lats)

        # Get the shortest distance from the two lines
        idx = numpy.sign(dst1) == numpy.sign(dst2)
        dst = numpy.zeros_like(dst1)
        dst[idx] = numpy.fmin(numpy.abs(dst1[idx]), numpy.abs(dst2[idx]))

        if numpy.any(numpy.isnan(dst)):
            raise ValueError('NaN in Ry0')

        return dst
Exemplo n.º 11
0
    def get_rx_distance(self, mesh):
        """
        Compute distance between each point of mesh and surface's great circle
        arc.

        Distance is measured perpendicular to the rupture strike, from
        the surface projection of the updip edge of the rupture, with
        the down dip direction being positive (this distance is usually
        called ``Rx``).

        In other words, is the horizontal distance to top edge of rupture
        measured perpendicular to the strike. Values on the hanging wall
        are positive, values on the footwall are negative.

        Base class calls
        :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`.

        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Rx-distance to.
        :returns:
            Numpy array of distances in km.
        """
        top_edge_centroid = self._get_top_edge_centroid()
        return geodetic.distance_to_arc(
            top_edge_centroid.longitude, top_edge_centroid.latitude,
            self.get_strike(), mesh.lons, mesh.lats
        )
Exemplo n.º 12
0
    def get_rx_distance(self, mesh):
        """
        See :meth:`superclass method
        <.base.BaseSurface.get_rx_distance>`
        for spec of input and result values.

        The method extracts the top edge of the surface. For each point in mesh,
        it then computes the Rx distance to each segment the top edge is made
        of. The calculation is done by calling the function
        :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`. The final Rx
        distance matrix is then constructed by taking, for each point in mesh,
        the minimum Rx distance value computed.
        """
        top_edge = self.get_mesh()[0:1]

        dists = []
        for i in range(top_edge.lons.shape[1] - 1):
            p1 = Point(
                top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]
            )
            p2 = Point(
                top_edge.lons[0, i + 1], top_edge.lats[0, i + 1],
                top_edge.depths[0, i + 1]
            )
            azimuth = p1.azimuth(p2)
            dists.append(
                geodetic.distance_to_arc(
                    p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats
                )
            )
        dists = numpy.array(dists)

        return numpy.min(dists, axis=0)
Exemplo n.º 13
0
 def test_one_point(self):
     dist = float(
         geodetic.distance_to_semi_arc(12.3,
                                       44.5,
                                       39.4,
                                       plons=13.4,
                                       plats=46.9))
     self.assertAlmostEqual(dist, -105.12464364)
     dist = float(
         geodetic.distance_to_arc(12.3, 44.5, 219.4, plons=13.4,
                                  plats=46.9))
     self.assertAlmostEqual(dist, +105.12464364)
     dist = float(
         geodetic.distance_to_semi_arc(12.3,
                                       44.5,
                                       39.4,
                                       plons=13.4,
                                       plats=44.9))
     self.assertAlmostEqual(dist, 38.34459954)
     # This tests the distance to a point in the y-negative halfspace in a
     # reference system which uses as the origin the reference point
     # (i.e. (12.3; 44.5)) and the y direction as the direction with
     # azimuth = 39.4)
     dist = float(
         geodetic.distance_to_semi_arc(12.3,
                                       44.5,
                                       39.4,
                                       plons=11.3,
                                       plats=44.5))
     self.assertAlmostEqual(dist, -79.3093368)
Exemplo n.º 14
0
    def get_rx_distance(self, mesh):
        """
        See :meth:`superclass method
        <.base.BaseQuadrilateralSurface.get_rx_distance>`
        for spec of input and result values.

        This is an optimized version specific to planar surface that doesn't
        make use of the mesh.
        """
        return geodetic.distance_to_arc(self.corner_lons[0], self.corner_lats[0], self.strike, mesh.lons, mesh.lats)
Exemplo n.º 15
0
    def get_rx_distance(self, mesh):
        """
        See :meth:`superclass method
        <.base.BaseSurface.get_rx_distance>`
        for spec of input and result values.

        This is an optimized version specific to planar surface that doesn't
        make use of the mesh.
        """
        return geodetic.distance_to_arc(self.corner_lons[0],
                                        self.corner_lats[0], self.strike,
                                        mesh.lons, mesh.lats)
Exemplo n.º 16
0
    def get_rx_distance(self, mesh):
        """
        See :meth:`superclass method
        <.base.BaseSurface.get_rx_distance>`
        for spec of input and result values.

        Base class calls
        :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`.
        """
        top_edge_centroid = self._get_top_edge_centroid()
        return geodetic.distance_to_arc(top_edge_centroid.longitude,
                                        top_edge_centroid.latitude,
                                        self.get_strike(), mesh.lons,
                                        mesh.lats)
Exemplo n.º 17
0
    def get_rx_distance(self, mesh):
        """
        See :meth:`superclass method
        <.base.BaseSurface.get_rx_distance>`
        for spec of input and result values.

        Base class calls
        :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`.
        """
        top_edge_centroid = self._get_top_edge_centroid()
        return geodetic.distance_to_arc(
            top_edge_centroid.longitude, top_edge_centroid.latitude,
            self.get_strike(), mesh.lons, mesh.lats
        )
Exemplo n.º 18
0
 def test_one_point(self):
     dist = float(geodetic.distance_to_semi_arc(
         12.3, 44.5, 39.4, plons=13.4, plats=46.9))
     self.assertAlmostEqual(dist, -105.12464364)
     dist = float(geodetic.distance_to_arc(
         12.3, 44.5, 219.4, plons=13.4, plats=46.9))
     self.assertAlmostEqual(dist, +105.12464364)
     dist = float(geodetic.distance_to_semi_arc(
         12.3, 44.5, 39.4, plons=13.4, plats=44.9))
     self.assertAlmostEqual(dist, 38.34459954)
     # This tests the distance to a point in the y-negative halfspace in a
     # reference system which uses as the origin the reference point
     # (i.e. (12.3; 44.5)) and the y direction as the direction with
     # azimuth = 39.4)
     dist = float(geodetic.distance_to_semi_arc(
         12.3, 44.5, 39.4, plons=11.3, plats=44.5))
     self.assertAlmostEqual(dist, -79.3093368)
Exemplo n.º 19
0
    def get_rx_distance(self, mesh):
        """
        Compute distance between each point of mesh and surface's great circle
        arc.

        Distance is measured perpendicular to the rupture strike, from
        the surface projection of the updip edge of the rupture, with
        the down dip direction being positive (this distance is usually
        called ``Rx``).

        In other words, is the horizontal distance to top edge of rupture
        measured perpendicular to the strike. Values on the hanging wall
        are positive, values on the footwall are negative.

        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Rx-distance to.
        :returns:
            Numpy array of distances in km.
        """
        top_edge = self.mesh[0:1]
        dists = []

        ia = 0
        ib = top_edge.lons.shape[1] - 2
        if (self.__class__.__name__ == 'KiteSurface'):
            idxs = numpy.nonzero(numpy.isfinite(top_edge.lons[0, :]))[0]
            ia = min(idxs)
            ib = sorted(idxs)[-2]

        if top_edge.lons.shape[1] < 3:
            i = 0

            if ((self.__class__.__name__ == 'KiteSurface')
                    and (numpy.isnan(top_edge.lons[0, i])
                         or numpy.isnan(top_edge.lons[0, i + 1]))):
                msg = 'Rx calculation. Top of rupture has less than two points'
                raise ValueError(msg)

            p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i],
                       top_edge.depths[0, i])
            p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1],
                       top_edge.depths[0, i + 1])
            azimuth = p1.azimuth(p2)
            dists.append(
                geodetic.distance_to_arc(p1.longitude, p1.latitude, azimuth,
                                         mesh.lons, mesh.lats))

        else:

            for i in range(top_edge.lons.shape[1] - 1):

                if ((self.__class__.__name__ == 'KiteSurface')
                        and (numpy.isnan(top_edge.lons[0, i])
                             or numpy.isnan(top_edge.lons[0, i + 1]))):
                    continue

                p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i],
                           top_edge.depths[0, i])
                p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1],
                           top_edge.depths[0, i + 1])

                # Swapping
                if i == 0:
                    pt = p1
                    p1 = p2
                    p2 = pt

                # Computing azimuth and distance
                if i == ia or i == ib:
                    azimuth = p1.azimuth(p2)
                    tmp = geodetic.distance_to_semi_arc(
                        p1.longitude, p1.latitude, azimuth, mesh.lons,
                        mesh.lats)
                else:
                    tmp = geodetic.min_distance_to_segment(
                        numpy.array([p1.longitude, p2.longitude]),
                        numpy.array([p1.latitude, p2.latitude]), mesh.lons,
                        mesh.lats)
                # Correcting the sign of the distance
                if i == 0:
                    tmp *= -1
                dists.append(tmp)

        # Computing distances
        dists = numpy.array(dists)
        iii = abs(dists).argmin(axis=0)
        dst = dists[iii, list(range(dists.shape[1]))]

        if numpy.any(numpy.isnan(dst)):
            raise ValueError('NaN in Rx')

        return dst
Exemplo n.º 20
0
    def get_rx_distance(self, mesh):
        """
        Compute distance between each point of mesh and surface's great circle
        arc.

        Distance is measured perpendicular to the rupture strike, from
        the surface projection of the updip edge of the rupture, with
        the down dip direction being positive (this distance is usually
        called ``Rx``).

        In other words, is the horizontal distance to top edge of rupture
        measured perpendicular to the strike. Values on the hanging wall
        are positive, values on the footwall are negative.

        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Rx-distance to.
        :returns:
            Numpy array of distances in km.
        """
        top_edge = self.mesh[0:1]

        dists = []
        if top_edge.lons.shape[1] < 3:

            i = 0
            p1 = Point(
                top_edge.lons[0, i],
                top_edge.lats[0, i],
                top_edge.depths[0, i]
            )
            p2 = Point(
                top_edge.lons[0, i + 1], top_edge.lats[0, i + 1],
                top_edge.depths[0, i + 1]
            )
            azimuth = p1.azimuth(p2)
            dists.append(
                geodetic.distance_to_arc(
                    p1.longitude, p1.latitude, azimuth,
                    mesh.lons, mesh.lats
                )
            )

        else:

            for i in range(top_edge.lons.shape[1] - 1):
                p1 = Point(
                    top_edge.lons[0, i],
                    top_edge.lats[0, i],
                    top_edge.depths[0, i]
                )
                p2 = Point(
                    top_edge.lons[0, i + 1],
                    top_edge.lats[0, i + 1],
                    top_edge.depths[0, i + 1]
                )
                # Swapping
                if i == 0:
                    pt = p1
                    p1 = p2
                    p2 = pt

                # Computing azimuth and distance
                if i == 0 or i == top_edge.lons.shape[1] - 2:
                    azimuth = p1.azimuth(p2)
                    tmp = geodetic.distance_to_semi_arc(p1.longitude,
                                                        p1.latitude,
                                                        azimuth,
                                                        mesh.lons, mesh.lats)
                else:
                    tmp = geodetic.min_distance_to_segment(
                        numpy.array([p1.longitude, p2.longitude]),
                        numpy.array([p1.latitude, p2.latitude]),
                        mesh.lons, mesh.lats)
                # Correcting the sign of the distance
                if i == 0:
                    tmp *= -1
                dists.append(tmp)

        # Computing distances
        dists = numpy.array(dists)
        iii = abs(dists).argmin(axis=0)
        dst = dists[iii, list(range(dists.shape[1]))]

        return dst
Exemplo n.º 21
0
    def get_rx_distance(self, mesh):
        """
        See :meth:`superclass method
        <.base.BaseSurface.get_rx_distance>`
        for spec of input and result values.

        The method extracts the top edge of the surface. For each point in mesh
        it computes the Rx distance to each segment the top edge is made
        of. The calculation is done by calling the function
        :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`. The final Rx
        distance matrix is then constructed by taking, for each point in mesh,
        the minimum Rx distance value computed.
        """
        top_edge = self.get_mesh()[0:1]

        dists = []
        if top_edge.lons.shape[1] < 3:

            i = 0
            p1 = Point(
                top_edge.lons[0, i],
                top_edge.lats[0, i],
                top_edge.depths[0, i]
            )
            p2 = Point(
                top_edge.lons[0, i + 1], top_edge.lats[0, i + 1],
                top_edge.depths[0, i + 1]
            )
            azimuth = p1.azimuth(p2)
            dists.append(
                geodetic.distance_to_arc(
                    p1.longitude, p1.latitude, azimuth,
                    mesh.lons, mesh.lats
                )
            )

        else:

            for i in range(top_edge.lons.shape[1] - 1):
                p1 = Point(
                    top_edge.lons[0, i],
                    top_edge.lats[0, i],
                    top_edge.depths[0, i]
                )
                p2 = Point(
                    top_edge.lons[0, i + 1],
                    top_edge.lats[0, i + 1],
                    top_edge.depths[0, i + 1]
                )
                # Swapping
                if i == 0:
                    pt = p1
                    p1 = p2
                    p2 = pt

                # Computing azimuth and distance
                if i == 0 or i == top_edge.lons.shape[1] - 2:
                    azimuth = p1.azimuth(p2)
                    tmp = geodetic.distance_to_semi_arc(p1.longitude,
                                                        p1.latitude,
                                                        azimuth,
                                                        mesh.lons, mesh.lats)
                else:
                    tmp = geodetic.min_distance_to_segment([p1.longitude,
                                                            p2.longitude],
                                                           [p1.latitude,
                                                            p2.latitude],
                                                           mesh.lons,
                                                           mesh.lats)
                # Correcting the sign of the distance
                if i == 0:
                    tmp *= -1
                dists.append(tmp)

        # Computing distances
        dists = numpy.array(dists)
        iii = abs(dists).argmin(axis=0)
        dst = dists[iii, list(range(dists.shape[1]))]

        return dst
Exemplo n.º 22
0
    def get_joyner_boore_distance(self, mesh):
        """
        See :meth:`superclass' method
        <openquake.hazardlib.geo.surface.base.BaseSurface.get_joyner_boore_distance>`.

        This is an optimized version specific to planar surface that doesn't
        make use of the mesh.
        """
        # we define four great circle arcs that contain four sides
        # of projected planar surface:
        #
        #       ↓     II    ↓
        #    I  ↓           ↓  I
        #       ↓     +     ↓
        #  →→→→→TL→→→→1→→→→TR→→→→→     → azimuth direction →
        #       ↓     -     ↓
        #       ↓           ↓
        # III  -3+   IV    -4+  III             ↓
        #       ↓           ↓            downdip direction
        #       ↓     +     ↓                   ↓
        #  →→→→→BL→→→→2→→→→BR→→→→→
        #       ↓     -     ↓
        #    I  ↓           ↓  I
        #       ↓     II    ↓
        #
        # arcs 1 and 2 are directed from left corners to right ones (the
        # direction has an effect on the sign of the distance to an arc,
        # as it shown on the figure), arcs 3 and 4 are directed from top
        # corners to bottom ones.
        #
        # then we measure distance from each of the points in a mesh
        # to each of those arcs and compare signs of distances in order
        # to find a relative positions of projections of points and
        # projection of a surface.
        #
        # then we consider four special cases (labeled with Roman numerals)
        # and either pick one of distances to arcs or a closest distance
        # to corner.
        #
        # indices 0, 2 and 1 represent corners TL, BL and TR respectively.
        arcs_lons = self.corner_lons.take([0, 2, 0, 1])
        arcs_lats = self.corner_lats.take([0, 2, 0, 1])
        downdip_azimuth = (self.strike + 90) % 360
        arcs_azimuths = [
            self.strike, self.strike, downdip_azimuth, downdip_azimuth
        ]
        mesh_lons = mesh.lons.reshape((-1, 1))
        mesh_lats = mesh.lats.reshape((-1, 1))
        # calculate distances from all the target points to all four arcs
        dists_to_arcs = geodetic.distance_to_arc(arcs_lons, arcs_lats,
                                                 arcs_azimuths, mesh_lons,
                                                 mesh_lats)
        # ... and distances from all the target points to each of surface's
        # corners' projections (we might not need all of those but it's
        # better to do that calculation once for all).
        dists_to_corners = geodetic.min_geodetic_distance(
            (self.corner_lons, self.corner_lats), mesh.xyz)

        # extract from ``dists_to_arcs`` signs (represent relative positions
        # of an arc and a point: +1 means on the left hand side, 0 means
        # on arc and -1 means on the right hand side) and minimum absolute
        # values of distances to each pair of parallel arcs.
        ds1, ds2, ds3, ds4 = numpy.sign(dists_to_arcs).transpose()
        dists_to_arcs = numpy.abs(dists_to_arcs).reshape(-1, 2, 2).min(axis=-1)

        jb_dists = numpy.select(
            # consider four possible relative positions of point and arcs:
            condlist=[
                # signs of distances to both parallel arcs are the same
                # in both pairs, case "I" on a figure above
                (ds1 == ds2) & (ds3 == ds4),
                # sign of distances to two parallels is the same only
                # in one pair, case "II"
                ds1 == ds2,
                # ... or another (case "III")
                ds3 == ds4
                # signs are different in both pairs (this is a "default"),
                # case "IV"
            ],
            choicelist=[
                # case "I": closest distance is the closest distance to corners
                dists_to_corners,
                # case "II": closest distance is distance to arc "1" or "2",
                # whichever is closer
                dists_to_arcs[:, 0],
                # case "III": closest distance is distance to either
                # arc "3" or "4"
                dists_to_arcs[:, 1]
            ],

            # default -- case "IV"
            default=0)

        return jb_dists.reshape(mesh.lons.shape)
Exemplo n.º 23
0
    def get_rx_distance(self, mesh):
        """
        Compute distance between each point of mesh and surface's great circle
        arc.

        Distance is measured perpendicular to the rupture strike, from
        the surface projection of the updip edge of the rupture, with
        the down dip direction being positive (this distance is usually
        called ``Rx``).

        In other words, is the horizontal distance to top edge of rupture
        measured perpendicular to the strike. Values on the hanging wall
        are positive, values on the footwall are negative.

        :param mesh:
            :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate
            Rx-distance to.
        :returns:
            Numpy array of distances in km.
        """
        top_edge = self.mesh[0:1]

        dists = []
        if top_edge.lons.shape[1] < 3:

            i = 0
            p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i],
                       top_edge.depths[0, i])
            p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1],
                       top_edge.depths[0, i + 1])
            azimuth = p1.azimuth(p2)
            dists.append(
                geodetic.distance_to_arc(p1.longitude, p1.latitude, azimuth,
                                         mesh.lons, mesh.lats))

        else:

            for i in range(top_edge.lons.shape[1] - 1):
                p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i],
                           top_edge.depths[0, i])
                p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1],
                           top_edge.depths[0, i + 1])
                # Swapping
                if i == 0:
                    pt = p1
                    p1 = p2
                    p2 = pt

                # Computing azimuth and distance
                if i == 0 or i == top_edge.lons.shape[1] - 2:
                    azimuth = p1.azimuth(p2)
                    tmp = geodetic.distance_to_semi_arc(
                        p1.longitude, p1.latitude, azimuth, mesh.lons,
                        mesh.lats)
                else:
                    tmp = geodetic.min_distance_to_segment(
                        numpy.array([p1.longitude, p2.longitude]),
                        numpy.array([p1.latitude, p2.latitude]), mesh.lons,
                        mesh.lats)
                # Correcting the sign of the distance
                if i == 0:
                    tmp *= -1
                dists.append(tmp)

        # Computing distances
        dists = numpy.array(dists)
        iii = abs(dists).argmin(axis=0)
        dst = dists[iii, list(range(dists.shape[1]))]

        return dst
Exemplo n.º 24
0
 def test_several_points(self):
     plons = numpy.array([3.3, 4.3])
     plats = numpy.array([20.3, 15.3])
     dists = geodetic.distance_to_arc(4.0, 17.0, -123.0, plons, plats)
     expected_dists = [347.61490787, -176.03785187]
     self.assertTrue(numpy.allclose(dists, expected_dists))
Exemplo n.º 25
0
    def get_joyner_boore_distance(self, mesh):
        """
        See :meth:`superclass' method
        <openquake.hazardlib.geo.surface.base.BaseQuadrilateralSurface.get_joyner_boore_distance>`.

        This is an optimized version specific to planar surface that doesn't
        make use of the mesh.
        """
        # we define four great circle arcs that contain four sides
        # of projected planar surface:
        #
        #       ↓     II    ↓
        #    I  ↓           ↓  I
        #       ↓     +     ↓
        #  →→→→→TL→→→→1→→→→TR→→→→→     → azimuth direction →
        #       ↓     -     ↓
        #       ↓           ↓
        # III  -3+   IV    -4+  III             ↓
        #       ↓           ↓            downdip direction
        #       ↓     +     ↓                   ↓
        #  →→→→→BL→→→→2→→→→BR→→→→→
        #       ↓     -     ↓
        #    I  ↓           ↓  I
        #       ↓     II    ↓
        #
        # arcs 1 and 2 are directed from left corners to right ones (the
        # direction has an effect on the sign of the distance to an arc,
        # as it shown on the figure), arcs 3 and 4 are directed from top
        # corners to bottom ones.
        #
        # then we measure distance from each of the points in a mesh
        # to each of those arcs and compare signs of distances in order
        # to find a relative positions of projections of points and
        # projection of a surface.
        #
        # then we consider four special cases (labeled with Roman numerals)
        # and either pick one of distances to arcs or a closest distance
        # to corner.
        #
        # indices 0, 2 and 1 represent corners TL, BL and TR respectively.
        arcs_lons = self.corner_lons.take([0, 2, 0, 1])
        arcs_lats = self.corner_lats.take([0, 2, 0, 1])
        downdip_azimuth = (self.strike + 90) % 360
        arcs_azimuths = [self.strike, self.strike,
                         downdip_azimuth, downdip_azimuth]
        mesh_lons = mesh.lons.reshape((-1, 1))
        mesh_lats = mesh.lats.reshape((-1, 1))
        # calculate distances from all the target points to all four arcs
        dists_to_arcs = geodetic.distance_to_arc(
            arcs_lons, arcs_lats, arcs_azimuths, mesh_lons, mesh_lats
        )
        # ... and distances from all the target points to each of surface's
        # corners' projections (we might not need all of those but it's
        # better to do that calculation once for all).
        dists_to_corners = geodetic.min_geodetic_distance(
            self.corner_lons, self.corner_lats,
            mesh.lons.flatten(), mesh.lats.flatten()
        )

        # extract from ``dists_to_arcs`` signs (represent relative positions
        # of an arc and a point: +1 means on the left hand side, 0 means
        # on arc and -1 means on the right hand side) and minimum absolute
        # values of distances to each pair of parallel arcs.
        ds1, ds2, ds3, ds4 = numpy.sign(dists_to_arcs).transpose()
        dists_to_arcs = numpy.abs(dists_to_arcs).reshape(-1, 2, 2).min(axis=-1)

        jb_dists = numpy.select(
            # consider four possible relative positions of point and arcs:
            condlist=[
                # signs of distances to both parallel arcs are the same
                # in both pairs, case "I" on a figure above
                (ds1 == ds2) & (ds3 == ds4),
                # sign of distances to two parallels is the same only
                # in one pair, case "II"
                ds1 == ds2,
                # ... or another (case "III")
                ds3 == ds4
                # signs are different in both pairs (this is a "default"),
                # case "IV"
            ],

            choicelist=[
                # case "I": closest distance is the closest distance to corners
                dists_to_corners,
                # case "II": closest distance is distance to arc "1" or "2",
                # whichever is closer
                dists_to_arcs[:, 0],
                # case "III": closest distance is distance to either
                # arc "3" or "4"
                dists_to_arcs[:, 1]
            ],

            # default -- case "IV"
            default=0
        )

        return jb_dists.reshape(mesh.lons.shape)