Esempio n. 1
0
 def hypocentres_to_cartesian(self):
     '''
     Render the hypocentres to a cartesian array
     '''
     return spherical_to_cartesian(self.data['longitude'],
                                   self.data['latitude'],
                                   self.data['depth'])
Esempio n. 2
0
    def triangulate(self):
        """
        Convert mesh points to vectors in Cartesian space.

        :returns:
            Tuple of four elements, each being 2d numpy array of 3d vectors
            (the same structure and shape as the mesh itself). Those arrays
            are:

            #. points vectors,
            #. vectors directed from each point (excluding the last column)
               to the next one in a same row →,
            #. vectors directed from each point (excluding the first row)
               to the previous one in a same column ↑,
            #. vectors pointing from a bottom left point of each mesh cell
               to top right one ↗.

            So the last three arrays of vectors allow to construct triangles
            covering the whole mesh.
        """
        points = geo_utils.spherical_to_cartesian(self.lons, self.lats,
                                                  self.depths)
        # triangulate the mesh by defining vectors of triangles edges:
        # →
        along_azimuth = points[:, 1:] - points[:, :-1]
        # ↑
        updip = points[:-1] - points[1:]
        # ↗
        diag = points[:-1, 1:] - points[1:, :-1]

        return points, along_azimuth, updip, diag
Esempio n. 3
0
 def _test(self, lons_lats_depths, vectors):
     lons, lats, depths = lons_lats_depths
     res_cart = utils.spherical_to_cartesian(lons, lats, depths)
     aac(vectors, res_cart, atol=1E-7)
     res_sphe = utils.cartesian_to_spherical(res_cart)
     self.assertIsInstance(res_sphe, tuple)
     self.assertEqual(len(res_sphe), 3)
     if depths is None:
         depths = numpy.zeros_like(lons)
     self.assertEqual(numpy.array(res_sphe).shape,
                      numpy.array([lons, lats, depths]).shape)
     aac([lons, lats, depths], res_sphe)
    def check_aki_richards_convention(cls, edges):
        """
        Verify that surface (as defined by corner points) conforms with Aki and
        Richard convention (i.e. surface dips right of surface strike)

        This method doesn't have to be called by hands before creating the
        surface object, because it is called from :meth:`from_fault_data`.
        """
        # 1) extract 4 corner points of surface mesh
        # 2) compute cross products between left and right edges and top edge
        # (these define vectors normal to the surface)
        # 3) compute dot products between cross product results and
        # position vectors associated with upper left and right corners (if
        # both angles are less then 90 degrees then the surface is correctly
        # defined)
        ul = edges[0].points[0]
        ur = edges[0].points[-1]
        bl = edges[-1].points[0]
        br = edges[-1].points[-1]
        ul, ur, bl, br = spherical_to_cartesian(
            [ul.longitude, ur.longitude, bl.longitude, br.longitude],
            [ul.latitude, ur.latitude, bl.latitude, br.latitude],
            [ul.depth, ur.depth, bl.depth, br.depth],
        )

        top_edge = ur - ul
        left_edge = bl - ul
        right_edge = br - ur
        left_cross_top = numpy.cross(left_edge, top_edge)
        right_cross_top = numpy.cross(right_edge, top_edge)

        left_cross_top /= numpy.sqrt(numpy.dot(left_cross_top, left_cross_top))
        right_cross_top /= numpy.sqrt(
            numpy.dot(right_cross_top, right_cross_top)
        )
        ul /= numpy.sqrt(numpy.dot(ul, ul))
        ur /= numpy.sqrt(numpy.dot(ur, ur))

        # rounding to 1st digit, to avoid ValueError raised for floating point
        # imprecision
        angle_ul = round(
            numpy.degrees(numpy.arccos(numpy.dot(ul, left_cross_top))), 1
        )
        angle_ur = round(
            numpy.degrees(numpy.arccos(numpy.dot(ur, right_cross_top))), 1
        )

        if (angle_ul > 90) or (angle_ur > 90):
            raise ValueError(
                "Surface does not conform with Aki & Richards convention"
            )
Esempio n. 5
0
 def test_hypocentres_to_cartesian(self):
     # Tests the function to render the hypocentres to a cartesian array.
     # The invoked function nhlib.geo.utils.spherical_to_cartesian is
     # tested as part of the nhlib suite. The test here is included for
     # coverage
     cat = Catalogue()
     cat.data['longitude'] = np.array([2., 3.])
     cat.data['latitude'] = np.array([2., 3.])
     cat.data['depth'] = np.array([2., 3.])
     expected_data = spherical_to_cartesian(cat.data['longitude'],
                                            cat.data['latitude'],
                                            cat.data['depth'])
     model_output = cat.hypocentres_to_cartesian()
     np.testing.assert_array_almost_equal(expected_data, model_output)
Esempio n. 6
0
 def test2(self):
     surface = PlanarSurface(
         20, 30,
         Point(3.9, 2.2, 10), Point(4.90402718, 3.19634248, 10),
         Point(5.9, 2.2, 90), Point(4.89746275, 1.20365263, 90))
     plons, plats, pdepths = [[4., 4.3, 3.1], [1.5, 1.7, 3.5],
                              [11., 12., 13.]]
     xyz = geo_utils.spherical_to_cartesian(plons, plats, pdepths)
     dists, xx, yy = surface._project(xyz)
     lons, lats, depths = surface._project_back(dists, xx, yy)
     aaae = numpy.testing.assert_array_almost_equal
     aaae(lons, plons)
     aaae(lats, plats)
     aaae(depths, pdepths)
Esempio n. 7
0
 def _test(self, lons_lats_depths, vectors):
     (lons, lats, depths) = lons_lats_depths
     res_cart = utils.spherical_to_cartesian(lons, lats, depths)
     self.assertIsInstance(res_cart, numpy.ndarray)
     self.assertTrue(numpy.allclose(vectors, res_cart), str(res_cart))
     res_sphe = utils.cartesian_to_spherical(res_cart)
     self.assertIsInstance(res_sphe, tuple)
     self.assertEqual(len(res_sphe), 3)
     if depths is None:
         depths = numpy.zeros_like(lons)
     self.assertEqual(numpy.array(res_sphe).shape,
                      numpy.array([lons, lats, depths]).shape)
     self.assertTrue(numpy.allclose([lons, lats, depths], res_sphe),
                     str(res_sphe))
Esempio n. 8
0
    def check_surface_validity(cls, edges):
        """
        Check validity of the surface.

        Project edge points to vertical plane anchored to surface upper left
        edge and with strike equal to top edge strike. Check that resulting
        polygon is valid.

        This method doesn't have to be called by hands before creating the
        surface object, because it is called from :meth:`from_fault_data`.
        """
        # extract coordinates of surface boundary (as defined from edges)
        full_boundary = []
        left_boundary = []
        right_boundary = []

        for i in range(1, len(edges) - 1):
            left_boundary.append(edges[i].points[0])
            right_boundary.append(edges[i].points[-1])

        full_boundary.extend(edges[0].points)
        full_boundary.extend(right_boundary)
        full_boundary.extend(edges[-1].points[::-1])
        full_boundary.extend(left_boundary[::-1])

        lons = [p.longitude for p in full_boundary]
        lats = [p.latitude for p in full_boundary]
        depths = [p.depth for p in full_boundary]

        # define reference plane. Corner points are separated by an arbitrary
        # distance of 10 km. The mesh spacing is set to 2 km. Both corner
        # distance and mesh spacing values do not affect the algorithm results.
        ul = edges[0].points[0]
        strike = ul.azimuth(edges[0].points[-1])
        dist = 10.

        ur = ul.point_at(dist, 0, strike)
        bl = Point(ul.longitude, ul.latitude, ul.depth + dist)
        br = bl.point_at(dist, 0, strike)

        # project surface boundary to reference plane and check for
        # validity.
        ref_plane = PlanarSurface.from_corner_points(ul, ur, br, bl)
        _, xx, yy = ref_plane._project(
            spherical_to_cartesian(lons, lats, depths))
        coords = [(x, y) for x, y in zip(xx, yy)]
        p = shapely.geometry.Polygon(coords)
        if not p.is_valid:
            raise ValueError('Edges points are not in the right order')
Esempio n. 9
0
 def _init_plane(self):
     """
     Prepare everything needed for projecting arbitrary points on a plane
     containing the surface.
     """
     tl, tr, bl, br = geo_utils.spherical_to_cartesian(self.corner_lons, self.corner_lats, self.corner_depths)
     # these two parameters define the plane that contains the surface
     # (in 3d Cartesian space): a normal unit vector,
     self.normal = geo_utils.normalized(numpy.cross(tl - tr, tl - bl))
     # ... and scalar "d" parameter from the plane equation (uses
     # an equation (3) from http://mathworld.wolfram.com/Plane.html)
     self.d = -(self.normal * tl).sum()
     # these two 3d vectors together with a zero point represent surface's
     # coordinate space (the way to translate 3d Cartesian space with
     # a center in earth's center to 2d space centered in surface's top
     # left corner with basis vectors directed to top right and bottom left
     # corners. see :meth:`_project`.
     self.uv1 = geo_utils.normalized(tr - tl)
     self.uv2 = numpy.cross(self.normal, self.uv1)
     self.zero_zero = tl
Esempio n. 10
0
 def _init_plane(self):
     """
     Prepare everything needed for projecting arbitrary points on a plane
     containing the surface.
     """
     tl, tr, bl, br = geo_utils.spherical_to_cartesian(
         self.corner_lons, self.corner_lats, self.corner_depths)
     # these two parameters define the plane that contains the surface
     # (in 3d Cartesian space): a normal unit vector,
     self.normal = geo_utils.normalized(numpy.cross(tl - tr, tl - bl))
     # ... and scalar "d" parameter from the plane equation (uses
     # an equation (3) from http://mathworld.wolfram.com/Plane.html)
     self.d = -(self.normal * tl).sum()
     # these two 3d vectors together with a zero point represent surface's
     # coordinate space (the way to translate 3d Cartesian space with
     # a center in earth's center to 2d space centered in surface's top
     # left corner with basis vectors directed to top right and bottom left
     # corners. see :meth:`_project`.
     self.uv1 = geo_utils.normalized(tr - tl)
     self.uv2 = numpy.cross(self.normal, self.uv1)
     self.zero_zero = tl
Esempio n. 11
0
 def close_sids(self, src_or_rec, trt=None):
     """
     :param src_or_rec: a source or a rupture record
     :param trt: passed only if src_or_rec is a rupture record
     :returns:
        the site indices within the maximum_distance of the hypocenter,
        plus the maximum size of the bounding box
     """
     if self.sitecol is None:
         return []
     elif not self.integration_distance:  # do not filter
         return self.sitecol.sids
     if not hasattr(self, 'kdt'):
         self.kdt = cKDTree(self.sitecol.xyz)
     if trt:  # rupture, called by GmfGetter.gen_computers
         dlon = get_longitudinal_extent(
             src_or_rec['minlon'], src_or_rec['maxlon']) / 2.
         dlat = (src_or_rec['maxlat'] - src_or_rec['minlat']) / 2.
         lon, lat, dep = src_or_rec['hypo']
         dist = self.integration_distance(trt) + numpy.sqrt(
             dlon**2 + dlat**2) / KM_TO_DEGREES
         dist += 10  # added 10 km of buffer to guard against numeric errors
         # the test most sensitive to the buffer effect is in oq-risk-tests,
         # case_ucerf/job_eb.ini; without buffer, sites can be discarded
         # even if within the maximum_distance
     else:  # source
         trt = src_or_rec.tectonic_region_type
         try:
             bbox = self.integration_distance.get_enlarged_box(src_or_rec)
         except BBoxError:  # do not filter
             return self.sitecol.sids
         dlon, dlat = (bbox[2] - bbox[0]) / 2., (bbox[3] - bbox[1]) / 2.
         lon, lat, dep = (
             (bbox[2] + bbox[0]) / 2., (bbox[3] + bbox[1]) / 2, 0)
         dist = numpy.sqrt(dlon**2 + dlat**2) / KM_TO_DEGREES
     xyz = spherical_to_cartesian(lon, lat, dep)
     sids = U32(self.kdt.query_ball_point(xyz, dist, eps=.001))
     sids.sort()
     return sids
Esempio n. 12
0
    def _project(self, lons, lats, depths):
        """
        Project points to a surface's plane.

        Parameters are lists or numpy arrays of coordinates of points
        to project.

        :returns:
            A tuple of three items: distances between original points
            and surface's plane in km, "x" and "y" coordinates of points'
            projections to the plane (in a surface's coordinate space).
        """
        points = geo_utils.spherical_to_cartesian(lons, lats, depths)

        # uses method from http://www.9math.com/book/projection-point-plane
        dists = (self.normal * points).sum(axis=-1) + self.d
        t0 = - dists
        projs = points + self.normal * t0.reshape(t0.shape + (1, ))

        # translate projected points' to surface's coordinate space
        vectors2d = projs - self.zero_zero
        xx = (vectors2d * self.uv1).sum(axis=-1)
        yy = (vectors2d * self.uv2).sum(axis=-1)
        return dists, xx, yy
Esempio n. 13
0
 def close_sids(self, rec, trt):
     """
     :param rec:
        a record with fields mag, minlon, minlat, maxlon, maxlat, hypo
     :param trt:
        tectonic region type string
     :returns:
        the site indices within the maximum_distance of the hypocenter,
        plus the maximum size of the bounding box
     """
     if self.sitecol is None:
         return []
     elif not self.integration_distance:  # do not filter
         return self.sitecol.sids
     if not hasattr(self, 'kdt'):
         self.kdt = cKDTree(self.sitecol.xyz)
     xyz = spherical_to_cartesian(*rec['hypo'])
     dlon = get_longitudinal_extent(rec['minlon'], rec['maxlon'])
     dlat = rec['maxlat'] - rec['minlat']
     delta = max(dlon, dlat) / KM_TO_DEGREES
     maxradius = self.integration_distance(trt) + delta
     sids = U32(self.kdt.query_ball_point(xyz, maxradius, eps=.001))
     sids.sort()
     return sids
Esempio n. 14
0
    def _project(self, lons, lats, depths):
        """
        Project points to a surface's plane.

        Parameters are lists or numpy arrays of coordinates of points
        to project.

        :returns:
            A tuple of three items: distances between original points
            and surface's plane in km, "x" and "y" coordinates of points'
            projections to the plane (in a surface's coordinate space).
        """
        points = geo_utils.spherical_to_cartesian(lons, lats, depths)

        # uses method from http://www.9math.com/book/projection-point-plane
        dists = (self.normal * points).sum(axis=-1) + self.d
        t0 = -dists
        projs = points + self.normal * t0.reshape(t0.shape + (1, ))

        # translate projected points' to surface's coordinate space
        vectors2d = projs - self.zero_zero
        xx = (vectors2d * self.uv1).sum(axis=-1)
        yy = (vectors2d * self.uv2).sum(axis=-1)
        return dists, xx, yy
Esempio n. 15
0
 def xyz(self):
     """
     :returns: an array of shape (N, 3) with the cartesian coordinates
     """
     return geo_utils.spherical_to_cartesian(self.lons.flat, self.lats.flat,
                                             self.depths.flat)
Esempio n. 16
0
 def test_from_vector(self):
     point = geo.Point(12.34, -56.78, 91.011)
     vector = spherical_to_cartesian(point.longitude, point.latitude,
                                     point.depth)
     self.assertEqual(point, geo.Point.from_vector(vector))
Esempio n. 17
0
 def test_from_vector(self):
     point = geo.Point(12.34, -56.78, 91.011)
     vector = spherical_to_cartesian(point.x, point.y, point.z)
     self.assertEqual(point, geo.Point.from_vector(vector))
Esempio n. 18
0
 def weight(rec, md=getdefault(maxdist, trt_by_grp[grp_id])):
     xyz = spherical_to_cartesian(*rec['hypo'])
     nsites = len(kdt.query_ball_point(xyz, md, eps=.001))
     return rec['n_occ'] * numpy.ceil((nsites + 1) / 1000)
Esempio n. 19
0
 def get_cdist(self, rec):
     """
     :returns: array of N euclidean distances from rec['hypo']
     """
     xyz = spherical_to_cartesian(*rec['hypo']).reshape(1, 3)
     return distance.cdist(self.sitecol.xyz, xyz)[:, 0]
Esempio n. 20
0
 def test_from_vector(self):
     point = geo.Point(12.34, -56.78, 91.011)
     vector = spherical_to_cartesian(point.longitude, point.latitude,
                                     point.depth)
     self.assertEqual(point, geo.Point.from_vector(vector))
Esempio n. 21
0
 def xyz(self):
     """
     :returns: an array of shape (N, 3) with the cartesian coordinates
     """
     return geo_utils.spherical_to_cartesian(
         self.lons.flat, self.lats.flat, self.depths.flat)
Esempio n. 22
0
 def test_from_vector(self):
     point = geo.Point(12.34, -56.78, 91.011)
     vector = spherical_to_cartesian(point.x, point.y, point.z)
     self.assertEqual(point, geo.Point.from_vector(vector))