def test_mesh_and_point_not_on_surface(self): self._test(Mesh.from_points_list( [Point(0, 0, 1), Point(0, 1, 2), Point(0, 2, 3)]), Mesh.from_points_list( [Point(0, 1.5, 3), Point(0, 1.5, 0.9)]), expected_distance_indices=[2, 1])
def select_square_centred_on_point(self, point, distance, **kwargs): '''Select earthquakes from within a square centered on a point :param point: Centre point as instance of nhlib.geo.point.Point class :param distance: Distance (km) :returns: Selected catalogue (as dictionary) and number of selected events ''' point_surface = Point(point.longitude, point.latitude, 0.) north_point = point_surface.point_at(distance, 0., 0.) east_point = point_surface.point_at(distance, 0., 90.) south_point = point_surface.point_at(distance, 0., 180.) west_point = point_surface.point_at(distance, 0., 270.) is_long = np.logical_and( catalogue['longitude'] >= west_point.longitude, catalogue['longitude'] < east_point.longitude) is_surface = np.logical_and( is_long, catalogue['latitude'] >= south_point.latitude, catalogue['latitude'] < north_point.latitude) upper_depth, lower_depth = _check_depth_limits(kwargs) is_valid = np.logical_and( is_surface, catalogue['depth'] >= upper_depth, catalogue['depth'] < lower_depth) number_selected = np.sum(is_valid) is_valid = np.logical_not(is_valid) return purge_catalogue(catalogue, is_valid.astype(int)), \ number_selected
def test(self): s1 = Site(location=Point(10, 20, 30), vs30=1.2, vs30measured=True, z1pt0=3.4, z2pt5=5.6) s2 = Site(location=Point(-1.2, -3.4, -5.6), vs30=55.4, vs30measured=False, z1pt0=66.7, z2pt5=88.9) cll = SiteCollection([s1, s2]) self.assertTrue((cll.vs30 == [1.2, 55.4]).all()) self.assertTrue((cll.vs30measured == [True, False]).all()) self.assertTrue((cll.z1pt0 == [3.4, 66.7]).all()) self.assertTrue((cll.z2pt5 == [5.6, 88.9]).all()) self.assertTrue((cll.mesh.lons == [10, -1.2]).all()) self.assertTrue((cll.mesh.lats == [20, -3.4]).all()) self.assertIs(cll.mesh.depths, None) for arr in (cll.vs30, cll.z1pt0, cll.z2pt5): self.assertIsInstance(arr, numpy.ndarray) self.assertEqual(arr.flags.writeable, False) self.assertEqual(arr.dtype, float) self.assertIsInstance(cll.vs30measured, numpy.ndarray) self.assertEqual(cll.vs30measured.flags.writeable, False) self.assertEqual(cll.vs30measured.dtype, bool) self.assertEqual(len(cll), 2)
def test_get_strike_1(self): p1 = Point(0.0, 0.0) p2 = Point(0.0635916966572, 0.0635916574897) surface = SimpleFaultSurface.from_fault_data(Line([p1, p2]), 1.0, 6.0, 89.9, 1.0) self.assertAlmostEquals(45.0, surface.get_strike(), delta=1e-4)
def test_point_on_the_border(self): corners = [[(0.1, -0.1, 1), (-0.1, -0.1, 1)], [(0.1, 0.1, 2), (-0.1, 0.1, 2)]] surface = DummySurface(corners) sites = Mesh.from_points_list([Point(-0.1, 0.04), Point(0.1, 0.03)]) dists = surface.get_joyner_boore_distance(sites) expected_dists = [0] * 2 self.assertTrue(numpy.allclose(dists, expected_dists, atol=1e-4))
def test_from_points_list_no_depth(self): points = [Point(0, 1), Point(2, 3), Point(5, 7)] mesh = Mesh.from_points_list(points) self.assertTrue((mesh.lons == [0, 2, 5]).all()) self.assertTrue((mesh.lats == [1, 3, 7]).all()) self.assertEqual(mesh.lons.dtype, numpy.float) self.assertEqual(mesh.lats.dtype, numpy.float) self.assertIs(mesh.depths, None)
def test4_site_along_strike(self): surface = self._test1to7surface() sites = Mesh.from_points_list( [Point(0.2, 0), Point(67.6, 0), Point(90.33, 0)]) dists = surface.get_rx_distance(sites) expected_dists = [0] * 3 self.assertTrue(numpy.allclose(dists, expected_dists))
def test_get_dip_2(self): p1 = Point(0.0, 0.0) p2 = Point(0.0635916966572, 0.0635916574897) surface = SimpleFaultSurface.from_fault_data(Line([p1, p2]), 1.0, 6.0, 30.0, 1.0) self.assertAlmostEquals(30.0, surface.get_dip(), 1)
def test5_site_opposite_to_strike_direction(self): surface = self._test1to7surface() sites = Mesh.from_points_list( [Point(-0.2, 0), Point(-67.6, 0), Point(-90.33, 0)]) dists = surface.get_rx_distance(sites) expected_dists = [0] * 3 self.assertTrue(numpy.allclose(dists, expected_dists))
def test_mesh_of_one_point(self): lons = numpy.array([[1.]]) lats = numpy.array([[0.]]) depths = numpy.array([[1.]]) mesh = RectangularMesh(lons, lats, depths) target_mesh = Mesh.from_points_list([Point(1, 0), Point(0.5, 0)]) dists = mesh.get_joyner_boore_distance(target_mesh) expected_dists = [0, Point(0.5, 0).distance(Point(1, 0))] self.assertTrue(numpy.allclose(dists, expected_dists, atol=0.2))
def test_get_dip_1(self): p1 = Point(0.0, 0.0) p2 = Point(0.0635916966572, 0.0635916574897) p3 = Point(0.0860747816618, 0.102533437776) surface = SimpleFaultSurface.from_fault_data(Line([p1, p2, p3]), 1.0, 6.0, 90.0, 1.0) self.assertAlmostEquals(90.0, surface.get_dip(), delta=1e-6)
def test_mesh_of_two_points(self): lons = numpy.array([[0, 0.5, 1]], float) lats = numpy.array([[0, 0, 0]], float) depths = numpy.array([[1, 0, 1]], float) mesh = RectangularMesh(lons, lats, depths) target_mesh = Mesh.from_points_list([Point(0.5, 1), Point(0.5, 0)]) dists = mesh.get_joyner_boore_distance(target_mesh) expected_dists = [Point(0.5, 1).distance(Point(0.5, 0)), 0] numpy.testing.assert_almost_equal(dists, expected_dists)
def test_get_mesh_5(self): p1 = Point(179.9, 0.0) p2 = Point(180.0, 0.0) p3 = Point(-179.9, 0.0) fault = SimpleFaultSurface.from_fault_data(Line([p1, p2, p3]), 1.0, 6.0, 90.0, 1.0) self.assert_mesh_is(fault, test_data.TEST_5_MESH)
def test_dip_over_90_degree(self): top = [Point(0, -0.01), Point(0, 0.01)] bottom = [Point(-0.01, -0.01, 1.11), Point(-0.01, 0.01, 1.11)] mesh = RectangularMesh.from_points_list([top, bottom]) dip, strike = mesh.get_mean_inclination_and_azimuth() # dip must be still in a range 0..90 self.assertAlmostEqual(dip, 45, delta=0.05) # strike must be reversed self.assertAlmostEqual(strike, 180, delta=0.05)
def test_get_mesh_4(self): p1 = Point(0.0, 0.0, 0.0) p2 = Point(0.0, 0.0359728811759, 0.0) p3 = Point(0.0190775080917, 0.0550503815182, 0.0) p4 = Point(0.03974514139, 0.0723925718856, 0.0) fault = SimpleFaultSurface.from_fault_data(Line([p1, p2, p3, p4]), 0.0, 4.0, 90.0, 1.0) self.assert_mesh_is(fault, test_data.TEST_4_MESH)
def test_point_inside(self): corners = [[(-0.1, -0.1, 1), (0.1, -0.1, 1)], [(-0.1, 0.1, 2), (0.1, 0.1, 2)]] surface = DummySurface(corners) sites = Mesh.from_points_list( [Point(0, 0), Point(0, 0, 20), Point(0.01, 0.03)]) dists = surface.get_joyner_boore_distance(sites) expected_dists = [0] * 3 self.assertTrue(numpy.allclose(dists, expected_dists))
def test_get_mesh_2(self): p1 = Point(0.0, 0.0, 0.0) p2 = Point(0.0, 0.0359728811759, 0.0) p3 = Point(0.0190775080917, 0.0550503815182, 0.0) p4 = Point(0.03974514139, 0.0723925718856, 0.0) fault = SimpleFaultSurface.from_fault_data(Line([p1, p2, p3, p4]), 2.12132034356, 4.2426406871192848, 45.0, 1.0) self.assert_mesh_is(fault, test_data.TEST_2_MESH)
def test_dip_90_three_points(self): polygon = SimpleFaultSurface.surface_projection_from_fault_data( Line([Point(1, -20), Point(1, -20.2), Point(2, -19.7)]), dip=90, upper_seismogenic_depth=30, lower_seismogenic_depth=50, ) elons = [1, 1, 2] elats = [-20.2, -20., -19.7] numpy.testing.assert_allclose(polygon.lons, elons) numpy.testing.assert_allclose(polygon.lats, elats)
def test_dip_90_self_intersection(self): polygon = SimpleFaultSurface.surface_projection_from_fault_data( Line([Point(1, -2), Point(2, -1.9), Point(3, -2.1), Point(4, -2)]), dip=90, upper_seismogenic_depth=10, lower_seismogenic_depth=20, ) elons = [3., 1., 2., 4.] elats = [-2.1, -2., -1.9, -2.] numpy.testing.assert_allclose(polygon.lons, elons) numpy.testing.assert_allclose(polygon.lats, elats)
def test_one_cell_unequal_area(self): # top-left triangle is vertical, has dip of 90 degrees, zero # strike and area of 1 by 1 over 2. bottom-right one has dip # of atan2(1, sqrt(2) / 2.0) which is 54.73561 degrees, strike # of 45 degrees and area that is 1.73246136 times area of the # first one's. weighted mean dip is 67.5 degrees and weighted # mean strike is 28.84 degrees top = [Point(0, -0.01), Point(0, 0.01)] bottom = [Point(0, -0.01, 2.22), Point(0.02, 0.01, 2.22)] mesh = RectangularMesh.from_points_list([top, bottom]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, 67.5, delta=0.05) self.assertAlmostEqual(strike, 28.84, delta=0.05)
def test_even_rows_even_columns_with_depths(self): lons = numpy.array([[10, 20], [12, 22]]) lats = numpy.array([[10, -10], [8, -9]]) depths = numpy.array([[2, 3], [4, 5]]) mesh = RectangularMesh(lons, lats, depths=depths) self.assertEqual(mesh.get_middle_point(), Point(15.996712, -0.250993, 3.5))
def test_one_point(self): mesh = Mesh.from_points_list([Point(7, 7)]) polygon = mesh.get_convex_hull() elons = [7.0000453, 7., 6.9999547, 7] elats = [7., 6.99995503, 7., 7.00004497] numpy.testing.assert_allclose(polygon.lons, elons) numpy.testing.assert_allclose(polygon.lats, elats)
def test_dip_90_two_points(self): polygon = SimpleFaultSurface.surface_projection_from_fault_data( Line([Point(2, 2), Point(1, 1)]), dip=90, upper_seismogenic_depth=10, lower_seismogenic_depth=20, ) elons = [ 1.00003181, 0.99996821, 0.99996819, 1.99996819, 2.00003182, 2.00003181 ] elats = [ 0.99996822, 0.99996819, 1.00003178, 2.0000318, 2.0000318, 1.9999682 ] numpy.testing.assert_allclose(polygon.lons, elons) numpy.testing.assert_allclose(polygon.lats, elats)
def test_fault_trace_points(self): """ The fault trace must have at least two points. """ fault_trace = Line([Point(0.0, 0.0)]) self.assertRaises(ValueError, SimpleFaultSurface.check_fault_data, fault_trace, 0.0, 1.0, 90.0, 1.0)
def get_middle_point(self): """ Return the middle point of the mesh. :returns: An instance of :class:`~nhlib.geo.point.Point`. The middle point is taken from the middle row and a middle column of the mesh if there are odd number of both. Otherwise the geometric mean point of two or four middle points. """ num_rows, num_cols = self.lons.shape mid_row = num_rows // 2 depth = 0 if num_rows & 1 == 1: # there are odd number of rows mid_col = num_cols // 2 if num_cols & 1 == 1: # odd number of columns, we can easily take # the middle point if self.depths is not None: depth = self.depths[mid_row][mid_col] return Point(self.lons[mid_row][mid_col], self.lats[mid_row][mid_col], depth) else: # even number of columns, need to take two middle # points on the middle row lon1, lon2 = self.lons[mid_row][mid_col - 1:mid_col + 1] lat1, lat2 = self.lats[mid_row][mid_col - 1:mid_col + 1] if self.depths is not None: depth1 = self.depths[mid_row][mid_col - 1] depth2 = self.depths[mid_row][mid_col] else: # there are even number of rows. take the row just above # and the one just below the middle and find middle point # of each submesh1 = self[mid_row - 1:mid_row] submesh2 = self[mid_row:mid_row + 1] p1, p2 = submesh1.get_middle_point(), submesh2.get_middle_point() lon1, lat1, depth1 = p1.longitude, p1.latitude, p1.depth lon2, lat2, depth2 = p2.longitude, p2.latitude, p2.depth # we need to find the middle between two points if self.depths is not None: depth = (depth1 + depth2) / 2.0 lon, lat = geo_utils.get_middle_point(lon1, lat1, lon2, lat2) return Point(lon, lat, depth)
def __iter__(self): """ Generate :class:`~nhlib.geo.point.Point` objects the mesh is composed of. Coordinates arrays are processed sequentially (as if they were flattened). """ lons = self.lons.flat lats = self.lats.flat if self.depths is not None: depths = self.depths.flat for i in xrange(self.lons.size): yield Point(lons[i], lats[i], depths[i]) else: for i in xrange(self.lons.size): yield Point(lons[i], lats[i])
def test8_strike_of_45_degrees(self): corners = [[(0.05, 0.05, 8), (-0.05, -0.05, 8)], [(0.05, 0.05, 9), (-0.05, -0.05, 9)]] surface = DummySurface(corners) sites = Mesh.from_points_list([Point(0.05, 0)]) self.assertAlmostEqual(surface.get_rx_distance(sites)[0], 3.9313415355436705, places=4)
def test_three_points(self): polygon = SimpleFaultSurface.surface_projection_from_fault_data( Line([Point(10, -20), Point(11, -20.2), Point(12, -19.7)]), dip=30, upper_seismogenic_depth=25.3, lower_seismogenic_depth=53.6, ) elons = [ 11.13560807, 10.1354272, 10.06374285, 12.06361991, 12.13515987 ] elats = [ -21.02520738, -20.82520794, -20.3895235, -20.08952368, -20.52520878 ] numpy.testing.assert_allclose(polygon.lons, elons) numpy.testing.assert_allclose(polygon.lats, elats)
def assert_mesh_is(testcase, surface, expected_mesh): mesh = surface.get_mesh() testcase.assertIs(mesh, surface.get_mesh()) expected_mesh = list(itertools.chain(*expected_mesh)) testcase.assertEqual(len(mesh), len(expected_mesh)) testcase.assertIsInstance(mesh, Mesh) for i, point in enumerate(mesh): expected_point = Point(*expected_mesh[i]) distance = expected_point.distance(point) * 1e3 testcase.assertAlmostEqual( 0, distance, delta=2, # allow discrepancy of 2 meters msg="point %d is off: %s != %s (distance is %.3fm)" % (i, point, expected_point, distance) )
def test_simple(self): lons = numpy.array([numpy.arange(-1, 1.2, 0.2)] * 11) lats = lons.transpose() + 1 depths = lats + 10 mesh = RectangularMesh(lons, lats, depths) check = lambda lon, lat, depth, expected_distance, **kwargs: \ self.assertAlmostEqual( mesh.get_joyner_boore_distance( Mesh.from_points_list([Point(lon, lat, depth)]) )[0], expected_distance, **kwargs ) check(lon=0, lat=0.5, depth=0, expected_distance=0) check(lon=1, lat=1, depth=0, expected_distance=0) check(lon=0.6, lat=-1, depth=0, expected_distance=Point(0.6, -1).distance(Point(0.6, 0)), delta=0.1) check(lon=-0.8, lat=2.1, depth=10, expected_distance=Point(-0.8, 2.1).distance(Point(-0.8, 2)), delta=0.02) check(lon=0.75, lat=2.3, depth=3, expected_distance=Point(0.75, 2.3).distance(Point(0.75, 2)), delta=0.04)
def assert_mesh_is(testcase, surface, expected_mesh): mesh = surface.get_mesh() testcase.assertIs(mesh, surface.get_mesh()) expected_mesh = list(itertools.chain(*expected_mesh)) testcase.assertEqual(len(mesh), len(expected_mesh)) testcase.assertIsInstance(mesh, Mesh) for i, point in enumerate(mesh): expected_point = Point(*expected_mesh[i]) distance = expected_point.distance(point) * 1e3 testcase.assertAlmostEqual( 0, distance, delta=2, # allow discrepancy of 2 meters msg="point %d is off: %s != %s (distance is %.3fm)" % (i, point, expected_point, distance))
def _test(self, points, site, expected_distance): lons, lats, depths = numpy.array(points).transpose() lons = lons.transpose() lats = lats.transpose() depths = depths.transpose() mesh = RectangularMesh(lons, lats, depths) distance = mesh.get_joyner_boore_distance( Mesh.from_points_list([Point(*site)]))[0] self.assertAlmostEqual(distance, expected_distance, delta=0.02)
def select_circular_distance_from_point(self, point, distance, **kwargs): '''Select earthquakes within a distance from a Point :param point: Centre point as instance of nhlib.geo.point.Point class :param distance: Distance (km) :returns: Selected catalogue (as dictionary) and number of selected events ''' if kwargs['distance_type'] is 'epicentral': locations = Mesh(catalogue['longitude'], catalogue['latitude'], np.zeros(len(catalogue['longitude']), dtype=float)) point = Point(point.longitude, point.latitude, 0.0) else: locations = self.catalogue_mesh is_close = (point.closer_than(locations, distance)) number_selected = np.sum(is_close) is_close = np.logical_not(is_close) return purge_catalogue(catalogue, is_close.astype(int)), \ number_selected