def build_planar_surface(geometry): """ Builds the planar rupture surface from the openquake.nrmllib.models instance """ # Read geometry from wkt geom = wkt.loads(geometry.wkt) top_left = Point(geom.xy[0][0], geom.xy[1][0], geometry.upper_seismo_depth) top_right = Point(geom.xy[0][1], geom.xy[1][1], geometry.upper_seismo_depth) strike = top_left.azimuth(top_right) dip_dir = (strike + 90.) % 360. depth_diff = geometry.lower_seismo_depth - geometry.upper_seismo_depth bottom_right = top_right.point_at( depth_diff / np.tan(geometry.dip * (np.pi / 180.)), depth_diff, dip_dir) bottom_left = top_left.point_at( depth_diff / np.tan(geometry.dip * (np.pi / 180.)), depth_diff, dip_dir) return PlanarSurface(1.0, strike, geometry.dip, top_left, top_right, bottom_right, bottom_left)
def cartesian_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: Instance of :class:`openquake.hmtk.seismicity.catalogue.Catalogue` class containing only selected events ''' point_surface = Point(point.longitude, point.latitude, 0.) # As distance is 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( self.catalogue.data['longitude'] >= west_point.longitude, self.catalogue.data['longitude'] < east_point.longitude) is_surface = np.logical_and( is_long, self.catalogue.data['latitude'] >= south_point.latitude, self.catalogue.data['latitude'] < north_point.latitude) upper_depth, lower_depth = _check_depth_limits(kwargs) is_valid = np.logical_and( is_surface, self.catalogue.data['depth'] >= upper_depth, self.catalogue.data['depth'] < lower_depth) return self.select_catalogue(is_valid)
def 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 float distance: Distance (km) :returns: Instance of :class:`openquake.hmtk.seismicity.catalogue.Catalogue` containing only selected events ''' if kwargs['distance_type'] is 'epicentral': locations = Mesh( self.catalogue.data['longitude'], self.catalogue.data['latitude'], np.zeros(len(self.catalogue.data['longitude']), dtype=float)) point = Point(point.longitude, point.latitude, 0.0) else: locations = self.catalogue.hypocentres_as_mesh() is_close = point.closer_than(locations, distance) return self.select_catalogue(is_close)
def setUp(self): ''' ''' self.fault = None self.regionalisation = None self.msr = [(WC1994(), 1.0)] self.msr_sigma = [(-1.5, 0.15), (0.0, 0.7), (1.5, 0.15)] self.shear_mod = [(30.0, 0.8), (35.0, 0.2)] self.dlr = [(1.25E-5, 1.0)] self.config = [{}] self.slip = [(10.0, 1.0)] x0 = Point(30., 30., 0.) x1 = x0.point_at(30., 0., 30.) x2 = x1.point_at(30., 0., 60.) # Total length is 60 km self.trace = Line([x0, x1, x2]) self.dip = 90. self.upper_depth = 0. self.lower_depth = 20. self.simple_fault = SimpleFaultGeometry(self.trace, self.dip, self.upper_depth, self.lower_depth) # Creates a trace ~60 km long made of 3 points upper_edge = Line([x0, x1, x2]) lower_edge = Line([x0.point_at(40., 20., 130.), x1.point_at(42., 25., 130.), x2.point_at(41., 22., 130.)]) self.complex_fault = ComplexFaultGeometry([upper_edge, lower_edge], 2.0)
def _rup_to_point(distance, surface, origin, azimuth, distance_type='rjb', iter_stop=1E-5, maxiter=1000): """ """ pt0 = origin pt1 = origin.point_at(distance, 0., azimuth) r_diff = np.inf iterval = 0 while (np.fabs(r_diff) >= iter_stop) and (iterval <= maxiter): pt1mesh = Mesh(np.array([pt1.longitude]), np.array([pt1.latitude]), None) if distance_type == 'rjb': r_diff = distance - surface.get_joyner_boore_distance(pt1mesh) elif distance_type == 'rrup': r_diff = distance - surface.get_min_distance(pt1mesh) else: raise ValueError('Distance type must be rrup or rjb!') pt0 = Point(pt1.longitude, pt1.latitude) if r_diff > 0.: pt1 = pt0.point_at(r_diff, 0., azimuth) else: pt1 = pt0.point_at(r_diff, 0., (azimuth + 180.) % 360.) return pt1
def setUp(self): ''' Creates a complex fault typology ''' x0 = Point(30., 30., 0.) x1 = x0.point_at(30., 0., 30.) x2 = x1.point_at(30., 0., 60.) upper_edge = Line([x0, x1, x2]) lower_edge = Line([x0.point_at(40., 20., 130.), x1.point_at(42., 25., 130.), x2.point_at(41., 22., 130.)]) self.edges = [upper_edge, lower_edge] self.fault = None
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. mesh_spacing = 2. 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( mesh_spacing, ul, ur, br, bl ) _, xx, yy = ref_plane._project(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')
def setUp(self): ''' Create a simple fault of known length and downdip width ''' # Creates a trace ~60 km long made of 3 points x0 = Point(30., 30., 0.) x1 = x0.point_at(30., 0., 30.) x2 = x1.point_at(30., 0., 60.) # Total length is 60 km self.trace = Line([x0, x1, x2]) self.dip = 90. # Simple Vertical Strike-Slip fault # Total downdip width = 20. km self.upper_depth = 0. self.lower_depth = 20. self.fault = None
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 getLength(self): """ Compute length of rupture (km). For EdgeRupture, we compute the length as the length of the top edge projected to the surface. Returns: float: Rupture length in km. """ lons = self._toplons lats = self._toplats seg = self._group_index groups = np.unique(seg) ng = len(groups) rlength = 0 for i in range(ng): group_segments = np.where(groups[i] == seg)[0] nseg = len(group_segments) - 1 for j in range(nseg): ind = group_segments[j] P0 = Point(lons[ind], lats[ind]) P1 = Point(lons[ind + 1], lats[ind + 1]) dist = P0.distance(P1) rlength = rlength + dist return rlength
def _rup_to_point(distance, surface, origin, azimuth, distance_type='rjb', iter_stop=1E-3, maxiter=1000): """ """ pt0 = origin pt1 = origin.point_at(distance, 0., azimuth) print pt0, pt1 r_diff = np.inf dip = surface.dip sin_dip = np.sin(np.radians(dip)) dist_sin_dip = distance / sin_dip #max_surf_dist = surface.width / np.cos(np.radians(dip)) iterval = 0 while (np.fabs(r_diff) >= iter_stop) and (iterval <= maxiter): pt1mesh = Mesh(np.array([pt1.longitude]), np.array([pt1.latitude]), None) if distance_type == 'rjb' or np.fabs(dip - 90.0) < 1.0E-3: r_diff = (distance - surface.get_joyner_boore_distance(pt1mesh)).flatten() pt0 = Point(pt1.longitude, pt1.latitude) if r_diff > 0.: pt1 = pt0.point_at(r_diff, 0., azimuth) else: pt1 = pt0.point_at(np.fabs(r_diff), 0., (azimuth + 180.) % 360.) elif distance_type == 'rrup': rrup = surface.get_min_distance(pt1mesh).flatten() if azimuth >= 0.0 and azimuth <= 180.0: # On hanging wall r_diff = dist_sin_dip - (rrup / sin_dip) else: # On foot wall r_diff = distance - rrup pt0 = Point(pt1.longitude, pt1.latitude) #print azimuth, (azimuth + 180.0) % 360, rrup, r_diff, np.fabs(r_diff) if r_diff > 0.: pt1 = pt0.point_at(r_diff, 0., azimuth) else: pt1 = pt0.point_at(np.fabs(r_diff), 0., (azimuth + 180.) % 360.) else: raise ValueError('Distance type must be rrup or rjb!') iterval += 1 return pt1
def test_even_rows_even_columns_no_depths(self): lons = numpy.array([[10, 20], [10.002, 20.002]]) lats = numpy.array([[10, -10], [8, -8]]) mesh = RectangularMesh(lons, lats, depths=None) self.assertEqual(mesh.get_middle_point(), Point(15.001, 0))
def test_build_fault_model(self): # Tests the constuction of a fault model with two faults (1 simple, # 1 complex) each with two mfd rates - should produce four sources self.model = mtkActiveFaultModel('001', 'A Fault Model', faults=[]) x0 = Point(30., 30., 0.) x1 = x0.point_at(30., 0., 30.) x2 = x1.point_at(30., 0., 60.) # Total length is 60 km trace = Line([x0, x1, x2]) simple_fault = SimpleFaultGeometry(trace, 90., 0., 20.) # Creates a trace ~60 km long made of 3 points upper_edge = Line([x0, x1, x2]) lower_edge = Line( [x0.point_at(40., 20., 130.), x1.point_at(42., 25., 130.), x2.point_at(41., 22., 130.)]) complex_fault = ComplexFaultGeometry([upper_edge, lower_edge], 2.0) config = [{'MFD_spacing': 0.1, 'Maximum_Magnitude': 7.0, 'Maximum_Uncertainty': None, 'Model_Name': 'Characteristic', 'Model_Weight': 0.5, 'Sigma': 0.1, 'Lower_Bound': -1., 'Upper_Bound': 1.}, {'MFD_spacing': 0.1, 'Maximum_Magnitude': 7.5, 'Maximum_Uncertainty': None, 'Model_Name': 'Characteristic', 'Model_Weight': 0.5, 'Sigma': 0.1, 'Lower_Bound': -1., 'Upper_Bound': 1.}] fault1 = mtkActiveFault('001', 'Simple Fault 1', simple_fault, [(10.0, 1.0)], -90., None, aspect_ratio=1.0, scale_rel=[(WC1994(), 1.0)], shear_modulus=[(30.0, 1.0)], disp_length_ratio=[(1E-5, 1.0)]) fault1.generate_config_set(config) fault2 = mtkActiveFault('002', 'Complex Fault 1', complex_fault, [(10.0, 1.0)], -90., None, aspect_ratio=1.0, scale_rel=[(WC1994(), 1.0)], shear_modulus=[(30.0, 1.0)], disp_length_ratio=[(1E-5, 1.0)]) fault2.generate_config_set(config) self.model.faults = [fault1, fault2] # Generate source model self.model.build_fault_model() self.assertEqual(len(self.model.source_model.sources), 4) # First source should be an instance of a mtkSimpleFaultSource model1 = self.model.source_model.sources[0] self.assertTrue(isinstance(model1, mtkSimpleFaultSource)) self.assertEqual(model1.id, '001_1') self.assertAlmostEqual(model1.mfd.min_mag, 6.9) np.testing.assert_array_almost_equal( np.log10(np.array(model1.mfd.occurrence_rates)), np.array([-2.95320041, -2.54583708, -2.953200413])) # Second source should be an instance of a mtkSimpleFaultSource model2 = self.model.source_model.sources[1] self.assertTrue(isinstance(model2, mtkSimpleFaultSource)) self.assertEqual(model2.id, '001_2') self.assertAlmostEqual(model2.mfd.min_mag, 7.4) np.testing.assert_array_almost_equal( np.log10(np.array(model2.mfd.occurrence_rates)), np.array([-3.70320041, -3.29583708, -3.70320041])) # Third source should be an instance of a mtkComplexFaultSource model3 = self.model.source_model.sources[2] self.assertTrue(isinstance(model3, mtkComplexFaultSource)) self.assertEqual(model3.id, '002_1') self.assertAlmostEqual(model3.mfd.min_mag, 6.9) np.testing.assert_array_almost_equal( np.log10(np.array(model3.mfd.occurrence_rates)), np.array([-2.59033387, -2.18297054, -2.59033387])) # Fourth source should be an instance of a mtkComplexFaultSource model4 = self.model.source_model.sources[3] self.assertTrue(isinstance(model4, mtkComplexFaultSource)) self.assertEqual(model4.id, '002_2') self.assertAlmostEqual(model4.mfd.min_mag, 7.4) np.testing.assert_array_almost_equal( np.log10(np.array(model4.mfd.occurrence_rates)), np.array([-3.34033387, -2.93297054, -3.34033387]))
def test_mesh_on_surface(self): self._test(Mesh.from_points_list([Point(0, 0), Point(0, 1), Point(0, 2)]), Mesh.from_points_list([Point(-1, -1, 3.4), Point(2, 5)]), expected_distance_indices=[0, 2])
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 test_4(self): surface = DummySurface(_planar_test_data.TEST_7_RUPTURE_2_MESH) sites = Mesh.from_points_list([Point(-0.3, 0.4)]) self.assertAlmostEqual(55.58568426746, surface.get_min_distance(sites)[0], places=4)
def make_edge(edge): ls = ~edge.LineString.posList coords = numpy.array(ls).reshape(-1, 3) return Line([Point(*coord) for coord in coords])
def test_point_sources(self): sources = [ openquake.hazardlib.source.PointSource( source_id='point1', name='point1', tectonic_region_type=const.TRT.ACTIVE_SHALLOW_CRUST, mfd=openquake.hazardlib.mfd.EvenlyDiscretizedMFD( min_mag=4, bin_width=1, occurrence_rates=[5]), nodal_plane_distribution=openquake.hazardlib.pmf.PMF([ (1, openquake.hazardlib.geo.NodalPlane(strike=0.0, dip=90.0, rake=0.0)) ]), hypocenter_distribution=openquake.hazardlib.pmf.PMF([(1, 10)]), upper_seismogenic_depth=0.0, lower_seismogenic_depth=10.0, magnitude_scaling_relationship=openquake.hazardlib.scalerel. PeerMSR(), rupture_aspect_ratio=2, temporal_occurrence_model=PoissonTOM(1.), rupture_mesh_spacing=1.0, location=Point(10, 10)), openquake.hazardlib.source.PointSource( source_id='point2', name='point2', tectonic_region_type=const.TRT.ACTIVE_SHALLOW_CRUST, mfd=openquake.hazardlib.mfd.EvenlyDiscretizedMFD( min_mag=4, bin_width=2, occurrence_rates=[5, 6, 7]), nodal_plane_distribution=openquake.hazardlib.pmf.PMF([ (1, openquake.hazardlib.geo.NodalPlane(strike=0, dip=90, rake=0.0)), ]), hypocenter_distribution=openquake.hazardlib.pmf.PMF([(1, 10)]), upper_seismogenic_depth=0.0, lower_seismogenic_depth=10.0, magnitude_scaling_relationship=openquake.hazardlib.scalerel. PeerMSR(), rupture_aspect_ratio=2, temporal_occurrence_model=PoissonTOM(1.), rupture_mesh_spacing=1.0, location=Point(10, 11)), ] sites = [ openquake.hazardlib.site.Site(Point(11, 10), 1, 2, 3), openquake.hazardlib.site.Site(Point(10, 16), 2, 2, 3), openquake.hazardlib.site.Site(Point(10, 10.6, 1), 3, 2, 3), openquake.hazardlib.site.Site(Point(10, 10.7, -1), 4, 2, 3) ] sitecol = openquake.hazardlib.site.SiteCollection(sites) gsims = {const.TRT.ACTIVE_SHALLOW_CRUST: SadighEtAl1997()} truncation_level = 1 imts = {'PGA': [0.1, 0.5, 1.3]} s_filter = SourceFilter(sitecol, {const.TRT.ACTIVE_SHALLOW_CRUST: 30}) result = calc_hazard_curves(sources, s_filter, imts, gsims, truncation_level)['PGA'] # there are two sources and four sites. The first source contains only # one rupture, the second source contains three ruptures. # # the first source has 'maximum projection radius' of 0.707 km # the second source has 'maximum projection radius' of 500.0 km # # the epicentral distances for source 1 are: [ 109.50558394, # 667.16955987, 66.71695599, 77.83644865] # the epicentral distances for source 2 are: [ 155.9412148 , # 555.97463322, 44.47797066, 33.35847799] # # Considering that the source site filtering distance is set to 30 km, # for source 1, all sites have epicentral distance larger than # 0.707 + 30 km. This means that source 1 ('point 1') is not considered # in the calculation because too far. # for source 2, the 1st, 3rd and 4th sites have epicentral distances # smaller than 500.0 + 30 km. This means that source 2 ('point 2') is # considered in the calculation for site 1, 3, and 4. # # JB distances for rupture 1 in source 2 are: [ 155.43860273, # 555.26752644, 43.77086388, 32.65137121] # JB distances for rupture 2 in source 2 are: [ 150.98882575, # 548.90356541, 37.40690285, 26.28741018] # JB distances for rupture 3 in source 2 are: [ 109.50545819, # 55.97463322, 0. , 0. ] # # Considering that the rupture site filtering distance is set to 30 km, # rupture 1 (magnitude 4) is not considered because too far, rupture 2 # (magnitude 6) affect only the 4th site, rupture 3 (magnitude 8) # affect the 3rd and 4th sites. self.assertEqual(result.shape, (4, 3)) # 4 sites, 3 levels numpy.testing.assert_allclose(result[0], 0) # no contrib to site 1 numpy.testing.assert_allclose(result[1], 0) # no contrib to site 2 # test that depths are kept after filtering (sites 3 and 4 remain) s_filter = SourceFilter(sitecol, {'default': 100}) numpy.testing.assert_array_equal( s_filter.get_close_sites(sources[0]).depths, ([1, -1]))
def test_2(self): surface = DummySurface(_planar_test_data.TEST_7_RUPTURE_6_MESH) sites = Mesh.from_points_list([Point(-0.25, 0.25)]) self.assertAlmostEqual(40.09707543926, surface.get_min_distance(sites)[0], places=4)
def _computeStrikeDip(self): """ Loop over all triangles and get the average normal, north, and up vectors in ECEF. Use these to compute a representative strike and dip. """ seg = self._group_index groups = np.unique(seg) ng = len(groups) norm_vec = Vector(0, 0, 0) north_vec = Vector(0, 0, 0) up_vec = Vector(0, 0, 0) for i in range(ng): group_segments = np.where(groups[i] == seg)[0] nseg = len(group_segments) - 1 for j in range(nseg): ind = group_segments[j] P0 = Point(self._toplons[ind], self._toplats[ind], self._topdeps[ind]) P1 = Point(self._toplons[ind + 1], self._toplats[ind + 1], self._topdeps[ind + 1]) P2 = Point(self._botlons[ind + 1], self._botlats[ind + 1], self._botdeps[ind + 1]) P3 = Point(self._botlons[ind], self._botlats[ind], self._botdeps[ind]) P1up = Point(self._toplons[ind + 1], self._toplats[ind + 1], self._topdeps[ind + 1] - 1.0) P1N = Point(self._toplons[ind + 1], self._toplats[ind + 1] + 0.001, self._topdeps[ind + 1]) P3up = Point(self._botlons[ind], self._botlats[ind], self._botdeps[ind] - 1.0) P3N = Point(self._botlons[ind], self._botlats[ind] + 0.001, self._botdeps[ind]) p0 = Vector.fromPoint(P0) p1 = Vector.fromPoint(P1) p2 = Vector.fromPoint(P2) p3 = Vector.fromPoint(P3) p1up = Vector.fromPoint(P1up) p1N = Vector.fromPoint(P1N) p3up = Vector.fromPoint(P3up) p3N = Vector.fromPoint(P3N) # Sides s01 = p1 - p0 s02 = p2 - p0 s03 = p3 - p0 s21 = p1 - p2 s23 = p3 - p2 # First triangle t1norm = (s02.cross(s01)).norm() a = s01.mag() b = s02.mag() c = s21.mag() s = (a + b + c) / 2 A1 = np.sqrt(s * (s - a) * (s - b) * (s - c)) / 1000 # Second triangle t2norm = (s03.cross(s02)).norm() a = s03.mag() b = s23.mag() c = s02.mag() s = (a + b + c) / 2 A2 = np.sqrt(s * (s - a) * (s - b) * (s - c)) / 1000 # Up and North p1up = (p1up - p1).norm() p3up = (p3up - p3).norm() p1N = (p1N - p1).norm() p3N = (p3N - p3).norm() # Combine norm_vec = norm_vec + A1 * t1norm + A2 * t2norm north_vec = north_vec + A1 * p1N + A2 * p3N up_vec = up_vec + A1 * p1up + A2 * p3up norm_vec = norm_vec.norm() north_vec = north_vec.norm() up_vec = up_vec.norm() # Do I need to flip the vector because it is pointing down (i.e., # right-hand rule is violated)? flip = np.sign(up_vec.dot(norm_vec)) norm_vec = flip * norm_vec # Angle between up_vec and norm_vec is dip self._dip = np.arcsin(up_vec.cross(norm_vec).mag()) * 180 / np.pi # Normal vector projected to horizontal plane nvph = (norm_vec - up_vec.dot(norm_vec) * up_vec).norm() # Dip direction is angle between nvph and north; strike is orthogonal. cp = nvph.cross(north_vec) sign = np.sign(cp.dot(up_vec)) dp = nvph.dot(north_vec) strike = np.arctan2(sign * cp.mag(), dp) * 180 / np.pi - 90 if strike < -180: strike = strike + 360 self._strike = strike
def computeRjb(self, lon, lat, depth): """ Method for computing Joyner-Boore distance. Args: lon (array): Numpy array of longitudes. lat (array): Numpy array of latitudes. depth (array): Numpy array of depths (km; positive down). Returns: tuple: A tuple of an array of Joyner-Boore distance (km), and None. """ mesh_dx = self._mesh_dx # --------------------------------------------------------------------- # Sort out sites # --------------------------------------------------------------------- oldshape = lon.shape if len(oldshape) == 2: newshape = (oldshape[0] * oldshape[1], 1) else: newshape = (oldshape[0], 1) x, y, z = latlon2ecef(lat, lon, depth) x.shape = newshape y.shape = newshape z.shape = newshape sites_ecef = np.hstack((x, y, z)) # --------------------------------------------------------------------- # Get mesh # --------------------------------------------------------------------- mx = [] my = [] mz = [] u_groups = np.unique(self._group_index) n_groups = len(u_groups) for j in range(n_groups): g_ind = np.where(u_groups[j] == self._group_index)[0] nq = len(self._toplats[g_ind]) - 1 for i in range(nq): q = [ Point(self._toplons[g_ind[i]], self._toplats[g_ind[i]], 0), Point(self._toplons[g_ind[i + 1]], self._toplats[g_ind[i + 1]], 0), Point(self._botlons[g_ind[i + 1]], self._botlats[g_ind[i + 1]], 0), Point(self._botlons[g_ind[i]], self._botlats[g_ind[i]], 0) ] mesh = utils.get_quad_mesh(q, dx=mesh_dx) mx.extend(list(np.reshape(mesh['x'], (-1, )))) my.extend(list(np.reshape(mesh['y'], (-1, )))) mz.extend(list(np.reshape(mesh['z'], (-1, )))) mesh_mat = np.array([np.array(mx), np.array(my), np.array(mz)]) # --------------------------------------------------------------------- # Compute distance # --------------------------------------------------------------------- dist = np.zeros_like(x) for i in range(len(x)): sitecol = sites_ecef[i, :].reshape([3, 1]) dif = sitecol - mesh_mat distarray = np.sqrt(np.sum(dif * dif, axis=0)) dist[i] = np.min(distarray) / 1000.0 # convert to km dist = np.reshape(dist, oldshape) return dist, None
def setUp(self): super().setUp() self.site1_location = Point(1, 2) self.site2_location = Point(-2, -3) self.site1 = Site(vs30=456, vs30measured=False, z1pt0=12.1, z2pt5=15.1, location=self.site1_location) self.site2 = Site(vs30=1456, vs30measured=True, z1pt0=112.1, z2pt5=115.1, location=self.site2_location) min_distance = numpy.array([10, 11]) rx_distance = numpy.array([4, 5]) jb_distance = numpy.array([6, 7]) ry0_distance = numpy.array([8, 9]) azimuth = numpy.array([12, 34]) top_edge_depth = 30 width = 15 strike = 60.123 class FakeSurface(object): call_counts = collections.Counter() def get_azimuth(self, mesh): self.call_counts['get_azimuth'] += 1 return azimuth def get_strike(self): self.call_counts['get_strike'] += 1 return strike def get_dip(self): self.call_counts['get_dip'] += 1 return 45.4545 def get_min_distance(fake_surface, sitecol): [point1, point2] = sitecol self.assertEqual(point1.location, self.site1_location) self.assertEqual(point2.location, self.site2_location) fake_surface.call_counts['get_min_distance'] += 1 return min_distance def get_rx_distance(fake_surface, sitecol): [point1, point2] = sitecol self.assertEqual(point1.location, self.site1_location) self.assertEqual(point2.location, self.site2_location) fake_surface.call_counts['get_rx_distance'] += 1 return rx_distance def get_ry0_distance(fake_surface, sitecol): [point1, point2] = sitecol self.assertEqual(point1.location, self.site1_location) self.assertEqual(point2.location, self.site2_location) fake_surface.call_counts['get_ry0_distance'] += 1 return ry0_distance def get_joyner_boore_distance(fake_surface, sitecol): [point1, point2] = sitecol self.assertEqual(point1.location, self.site1_location) self.assertEqual(point2.location, self.site2_location) fake_surface.call_counts['get_joyner_boore_distance'] += 1 return jb_distance def get_top_edge_depth(fake_surface): fake_surface.call_counts['get_top_edge_depth'] += 1 return top_edge_depth def get_width(fake_surface): fake_surface.call_counts['get_width'] += 1 return width self.rupture_hypocenter = Point(2, 3, 40) self.rupture = BaseRupture( mag=123.45, rake=123.56, tectonic_region_type=const.TRT.VOLCANIC, hypocenter=self.rupture_hypocenter, surface=FakeSurface()) self.gsim_class.DEFINED_FOR_TECTONIC_REGION_TYPE = const.TRT.VOLCANIC self.fake_surface = FakeSurface
def test_build_fault_model(self): # Tests the constuction of a fault model with two faults (1 simple, # 1 complex) each with two mfd rates - should produce four sources self.model = mtkActiveFaultModel('001', 'A Fault Model', faults=[]) x0 = Point(30., 30., 0.) x1 = x0.point_at(30., 0., 30.) x2 = x1.point_at(30., 0., 60.) # Total length is 60 km trace = Line([x0, x1, x2]) simple_fault = SimpleFaultGeometry(trace, 90., 0., 20.) # Creates a trace ~60 km long made of 3 points upper_edge = Line([x0, x1, x2]) lower_edge = Line([ x0.point_at(40., 20., 130.), x1.point_at(42., 25., 130.), x2.point_at(41., 22., 130.) ]) complex_fault = ComplexFaultGeometry([upper_edge, lower_edge], 2.0) config = [{ 'MFD_spacing': 0.1, 'Maximum_Magnitude': 7.0, 'Maximum_Uncertainty': None, 'Model_Name': 'Characteristic', 'Model_Weight': 0.5, 'Sigma': 0.1, 'Lower_Bound': -1., 'Upper_Bound': 1. }, { 'MFD_spacing': 0.1, 'Maximum_Magnitude': 7.5, 'Maximum_Uncertainty': None, 'Model_Name': 'Characteristic', 'Model_Weight': 0.5, 'Sigma': 0.1, 'Lower_Bound': -1., 'Upper_Bound': 1. }] fault1 = mtkActiveFault('001', 'Simple Fault 1', simple_fault, [(10.0, 1.0)], -90., None, aspect_ratio=1.0, scale_rel=[(WC1994(), 1.0)], shear_modulus=[(30.0, 1.0)], disp_length_ratio=[(1E-5, 1.0)]) fault1.generate_config_set(config) fault2 = mtkActiveFault('002', 'Complex Fault 1', complex_fault, [(10.0, 1.0)], -90., None, aspect_ratio=1.0, scale_rel=[(WC1994(), 1.0)], shear_modulus=[(30.0, 1.0)], disp_length_ratio=[(1E-5, 1.0)]) fault2.generate_config_set(config) self.model.faults = [fault1, fault2] # Generate source model self.model.build_fault_model() self.assertEqual(len(self.model.source_model.sources), 4) # First source should be an instance of a mtkSimpleFaultSource model1 = self.model.source_model.sources[0] self.assertTrue(isinstance(model1, mtkSimpleFaultSource)) self.assertEqual(model1.id, '001_1') self.assertAlmostEqual(model1.mfd.min_mag, 6.9) np.testing.assert_array_almost_equal( np.log10(np.array(model1.mfd.occurrence_rates)), np.array([-2.95320041, -2.54583708, -2.953200413])) # Second source should be an instance of a mtkSimpleFaultSource model2 = self.model.source_model.sources[1] self.assertTrue(isinstance(model2, mtkSimpleFaultSource)) self.assertEqual(model2.id, '001_2') self.assertAlmostEqual(model2.mfd.min_mag, 7.4) np.testing.assert_array_almost_equal( np.log10(np.array(model2.mfd.occurrence_rates)), np.array([-3.70320041, -3.29583708, -3.70320041])) # Third source should be an instance of a mtkComplexFaultSource model3 = self.model.source_model.sources[2] self.assertTrue(isinstance(model3, mtkComplexFaultSource)) self.assertEqual(model3.id, '002_1') self.assertAlmostEqual(model3.mfd.min_mag, 6.9) np.testing.assert_array_almost_equal( np.log10(np.array(model3.mfd.occurrence_rates)), np.array([-2.59033387, -2.18297054, -2.59033387])) # Fourth source should be an instance of a mtkComplexFaultSource model4 = self.model.source_model.sources[3] self.assertTrue(isinstance(model4, mtkComplexFaultSource)) self.assertEqual(model4.id, '002_2') self.assertAlmostEqual(model4.mfd.min_mag, 7.4) np.testing.assert_array_almost_equal( np.log10(np.array(model4.mfd.occurrence_rates)), np.array([-3.34033387, -2.93297054, -3.34033387]))
def test_two_cells(self): top = [Point(0, -0.01), Point(0, 0.01)] middle = [Point(0.01, -0.01, 1.11), Point(0.01, 0.01, 1.11)] bottom = [Point(0.01, -0.01, 2.22), Point(0.01, 0.01, 2.22)] mesh = RectangularMesh.from_points_list([top, middle, bottom]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, math.degrees(math.atan2(2, 1)), delta=0.1) self.assertAlmostEqual(strike, 0, delta=0.02) bottom = [Point(0.01, -0.01, 3.33), Point(0.01, 0.01, 3.33)] mesh = RectangularMesh.from_points_list([top, middle, bottom]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, math.degrees(math.atan2(3, 1)), delta=0.1) self.assertAlmostEqual(strike, 0, delta=0.02) row1 = [Point(90, -0.1), Point(90, 0), Point(90, 0.1)] row2 = [Point(90, -0.1, 1), Point(90, 0, 1), Point(90, 0.1, 1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, 90) assert_angles_equal(self, strike, 360, delta=1e-7) row1 = [Point(-90.1, -0.1), Point(-90, 0), Point(-89.9, 0.1)] row2 = [ Point(-90.0, -0.1, 1), Point(-89.9, 0, 1), Point(-89.8, 0.1, 1) ] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(strike, 45, delta=1e-4) row1 = [Point(-90.1, -0.1), Point(-90, 0), Point(-89.9, 0.1)] row2 = [ Point(-90.0, -0.1, 1), Point(-89.9, 0, 1), Point(-89.8, 0.1, 1) ] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(strike, 45, delta=1e-3) row1 = [Point(-90.1, -0.1), Point(-90, 0), Point(-89.9, 0.1)] row2 = [Point(-90.2, -0.1, 1), Point(-90.1, 0, 1), Point(-90, 0.1, 1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(strike, 225, delta=1e-3)
def _parse_distance_data(self, event, site, metadata): """ Read in the distance related metadata and return an instance of the :class: smtk.sm_database.RecordDistance """ # Compute various distance metrics # Add calculation of Repi, Rhypo from event and station localizations (latitudes, longitudes, depth, elevation)? target_site = Mesh(np.array([site.longitude]), np.array([site.latitude]), np.array([0.0])) # Warning ratio fixed to 1.5 ratio=1.5 surface_modeled = rcfg.create_planar_surface( Point(event.longitude, event.latitude, event.depth), event.mechanism.nodal_planes.nodal_plane_1['strike'], event.mechanism.nodal_planes.nodal_plane_1['dip'], event.rupture.area, ratio) hypocenter = rcfg.get_hypocentre_on_planar_surface( surface_modeled, event.rupture.hypo_loc) # Rhypo Rhypo = get_float(metadata["HypD (km)"]) if Rhypo is None: Rhypo = hypocenter.distance_to_mesh(target_site) # Repi Repi = get_float(metadata["EpiD (km)"]) if Repi is None: Repi= hypocenter.distance_to_mesh(target_site, with_depths=False) # Rrup Rrup = get_float(metadata["Campbell R Dist. (km)"]) if Rrup is None: Rrup = surface_modeled.get_min_distance(target_site) # Rjb Rjb = get_float(metadata["Joyner-Boore Dist. (km)"]) if Rjb is None: Rjb = surface_modeled.get_joyner_boore_distance(target_site) # Need to check if Rx and Ry0 are consistant with the other metrics # when those are coming from the flatfile? # Rx Rx = surface_modeled.get_rx_distance(target_site) # Ry0 Ry0 = surface_modeled.get_ry0_distance(target_site) distance = RecordDistance( repi = float(Repi), rhypo = float(Rhypo), rjb = float(Rjb), rrup = float(Rrup), r_x = float(Rx), ry0 = float(Ry0)) distance.azimuth = get_float(metadata["Source to Site Azimuth (deg)"]) distance.hanging_wall = get_float(metadata["FW/HW Indicator"]) # distance = RecordDistance( # get_float(metadata["EpiD (km)"]), # get_float(metadata["HypD (km)"]), # get_float(metadata["Joyner-Boore Dist. (km)"]), # get_float(metadata["Campbell R Dist. (km)"])) # distance.azimuth = get_float(metadata["Source to Site Azimuth (deg)"]) # distance.hanging_wall = get_float(metadata["FW/HW Indicator"]) return distance
def test_1(self): surface = FakeSurface(_planar_test_data.TEST_7_RUPTURE_6_MESH) sites = Mesh.from_points_list([Point(0, 0)]) self.assertAlmostEqual(8.01185807319, surface.get_min_distance(sites)[0])
def test_get_middle_point(self): corners = [[(0.0, 0.0, 0.0), (0.0, 0.089932, 0.0)], [(0.0, 0.0, 10.0), (0.0, 0.089932, 10.0)]] surface = DummySurface(corners) self.assertTrue( Point(0.0, 0.044966, 5.0) == surface.get_middle_point())
def test_point_outside(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.2, -0.2), Point(1, 1, 1), Point(4, 5), Point(8, 10.4), Point(0.05, 0.15, 10) ]) dists = surface.get_joyner_boore_distance(sites) expected_dists = [ Point(-0.2, -0.2).distance(Point(-0.1, -0.1)), Point(1, 1).distance(Point(0.1, 0.1)), Point(4, 5).distance(Point(0.1, 0.1)), Point(8, 10.4).distance(Point(0.1, 0.1)), Point(0.05, 0.15).distance(Point(0.05, 0.1)) ] numpy.testing.assert_allclose(dists, expected_dists, rtol=0.01)
def test_3(self): surface = DummySurface(_planar_test_data.TEST_7_RUPTURE_2_MESH) sites = Mesh.from_points_list([Point(0, 0)]) self.assertAlmostEqual(7.01186304977, surface.get_min_distance(sites)[0])
def test_one_cell_topo(self): top = [Point(0, -0.01, -3.00), Point(0, 0.01, -3.00)] bottom = [Point(0.01, -0.01, -1.89), Point(0.01, 0.01, -1.89)] mesh = RectangularMesh.from_points_list([top, bottom]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, 45, delta=0.1) self.assertAlmostEqual(strike, 0, delta=0.05) row1 = [Point(45, -0.1, -3.00), Point(45.2, 0.1, -3.00)] row2 = [Point(45, -0.1, -2.00), Point(45.2, 0.1, -2.00)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, 90) self.assertAlmostEqual(strike, 225, delta=0.1) row1 = [Point(90, -0.1, -3.00), Point(90, 0.1, -3.00)] row2 = [Point(90, -0.1, -2.00), Point(90, 0.1, -2.00)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, 90) self.assertAlmostEqual(strike, 0, delta=0.1)
def test_several_sites(self): surface = DummySurface(_planar_test_data.TEST_7_RUPTURE_2_MESH) sites = Mesh.from_points_list([Point(0, 0), Point(-0.3, 0.4)]) dists = surface.get_min_distance(sites) expected_dists = [7.01186301, 55.58568427] numpy.testing.assert_allclose(dists, expected_dists)
def test2_site_on_the_foot_wall(self): surface = self._test1to7surface() sites = Mesh.from_points_list([Point(0.05, -0.05), Point(-140, -0.05)]) dists = surface.get_rx_distance(sites) expected_dists = [-5.559752615413244] * 2 numpy.testing.assert_allclose(dists, expected_dists, rtol=.01)
def test_mesh_and_point_on_surface(self): self._test(Mesh.from_points_list([Point(0, 0), Point(0, 1), Point(0, 2)]), Mesh.from_points_list([Point(1, 1), Point(-1, 0)]), expected_distance_indices=[1, 0])
def test3_site_on_centroid(self): surface = self._test1to7surface() sites = Mesh.from_points_list([Point(0.05, 0)]) self.assertAlmostEqual(surface.get_rx_distance(sites)[0], 0)
def test_point_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.5, 1.5)]), expected_distance_indices=[1])
def test6_one_degree_distance(self): surface = self._test1to7surface() sites = Mesh.from_points_list([Point(0.05, -1), Point(20, 1)]) dists = surface.get_rx_distance(sites) expected_dists = [-111.19505230826488, +111.19505230826488] numpy.testing.assert_allclose(dists, expected_dists, rtol=.01)
def test_on_surface(self): row1 = [Point(0, 0), Point(0, 1)] row2 = [Point(1, 0), Point(1, 1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertEqual(dip, 0) self.assertAlmostEqual(strike, 0, delta=0.5) row1 = [Point(0, 0), Point(0, -1)] row2 = [Point(1, 0), Point(1, -1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertEqual(dip, 0) self.assertAlmostEqual(strike, 180, delta=0.5) row1 = [Point(0, 0), Point(1, 1)] row2 = [Point(1, 0), Point(2, 1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertEqual(dip, 0) self.assertAlmostEqual(strike, 45, delta=0.01) row1 = [Point(0, 0), Point(1, -1)] row2 = [Point(1, 0), Point(2, -1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertEqual(dip, 0) self.assertAlmostEqual(strike, 135, delta=0.01) row1 = [Point(0, 0), Point(-1, -1)] row2 = [Point(-1, 0), Point(-2, -1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertEqual(dip, 0) self.assertAlmostEqual(strike, 225, delta=0.01) row1 = [Point(0, 0), Point(-1, 1)] row2 = [Point(-1, 0), Point(-2, 1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertEqual(dip, 0) self.assertAlmostEqual(strike, 315, delta=0.01)
def test7_ten_degrees_distance(self): surface = self._test1to7surface() sites = Mesh.from_points_list([Point(0, -10), Point(-15, 10)]) dists = surface.get_rx_distance(sites) expected_dists = [-1111.9505230826488, +1111.9505230826488] numpy.testing.assert_allclose(dists, expected_dists, rtol=.01)
def test_even_rows_odd_columns_with_topo(self): lons = numpy.array([[20], [21]]) lats = numpy.array([[-1], [1]]) depths = numpy.array([[-1.1], [-1.3]]) mesh = RectangularMesh(lons, lats, depths=depths) self.assertEqual(mesh.get_middle_point(), Point(20.5, 0, -1.2))
def __init__(self, coordinates_list): points = [[Point(*coordinates) for coordinates in row] for row in coordinates_list] self.mesh = RectangularMesh.from_points_list(points)
def test1_site_on_the_edges(self): surface = self._test_rectangular_surface() sites = Mesh.from_points_list([Point(0.0, 0.05), Point(0.0, -0.05)]) dists = surface.get_ry0_distance(sites) expected_dists = [0, 0] numpy.testing.assert_allclose(dists, expected_dists)
def test_from_points_list_with_depth(self): points = [Point(0, 1, 2), Point(2, 3, 4), Point(5, 7, 10)] mesh = Mesh.from_points_list(points) self.assertTrue((mesh.depths == [2, 4, 10]).all()) self.assertEqual(mesh.depths.dtype, numpy.float)