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 from_fault_data(cls, fault_trace, upper_seismogenic_depth, lower_seismogenic_depth, dip, mesh_spacing): """ Create and return a fault surface using fault source data. :param openquake.hazardlib.geo.line.Line fault_trace: Geographical line representing the intersection between the fault surface and the earth surface. :param upper_seismo_depth: Minimum depth ruptures can reach, in km (i.e. depth to fault's top edge). :param lower_seismo_depth: Maximum depth ruptures can reach, in km (i.e. depth to fault's bottom edge). :param dip: Dip angle (i.e. angle between fault surface and earth surface), in degrees. :param mesh_spacing: Distance between two subsequent points in a mesh, in km. :returns: An instance of :class:`SimpleFaultSurface` created using that data. Uses :meth:`check_fault_data` for checking parameters. """ cls.check_fault_data(fault_trace, upper_seismogenic_depth, lower_seismogenic_depth, dip, mesh_spacing) # Loops over points in the top edge, for each point # on the top edge compute corresponding point on the bottom edge, then # computes equally spaced points between top and bottom points. vdist_top = upper_seismogenic_depth vdist_bottom = lower_seismogenic_depth hdist_top = vdist_top / math.tan(math.radians(dip)) hdist_bottom = vdist_bottom / math.tan(math.radians(dip)) strike = fault_trace[0].azimuth(fault_trace[-1]) azimuth = (strike + 90.0) % 360 mesh = [] for point in fault_trace.resample(mesh_spacing): top = point.point_at(hdist_top, vdist_top, azimuth) bottom = point.point_at(hdist_bottom, vdist_bottom, azimuth) mesh.append(top.equally_spaced_points(bottom, mesh_spacing)) # number of rows corresponds to number of points along dip # number of columns corresponds to number of points along strike surface_points = numpy.array(mesh).transpose().tolist() mesh = RectangularMesh.from_points_list(surface_points) assert 1 not in mesh.shape, ( "Mesh must have at least 2 nodes along both length and width." " Possible cause: Mesh spacing could be too large with respect to" " the fault length and width." ) return cls(mesh)
def from_points_list(cls, points): """ Create a gridded surface from a list of points. :parameter points: A list of :class:`~openquake.hazardlib.geo.Point` :returns: An instance of :class:`~openquake.hazardlib.geo.surface.gridded.GriddedSurface` """ return cls(RectangularMesh.from_points_list([points]))
def test_one_cell(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() self.assertAlmostEqual(dip, 45, delta=0.05) self.assertAlmostEqual(strike, 0, delta=0.05) row1 = [Point(45, -0.1), Point(45.2, 0.1)] row2 = [Point(45, -0.1, 1), Point(45.2, 0.1, 1)] mesh = RectangularMesh.from_points_list([row1, row2]) dip, strike = mesh.get_mean_inclination_and_azimuth() self.assertAlmostEqual(dip, 90) self.assertAlmostEqual(strike, 45, delta=0.1) row1 = [Point(90, -0.1), Point(90, 0.1)] row2 = [Point(90, -0.1, 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) self.assertAlmostEqual(strike, 0, delta=0.1)
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_from_points_list(self): lons = [[0, 1], [2, 3], [4, 5]] lats = [[1, 2], [-1, -2], [10, 20]] depths = [[11.1, 11.2], [11.3, 11.4], [11.5, 11.6]] points = [ [Point(lons[i][j], lats[i][j], depths[i][j]) for j in range(len(lons[i]))] for i in range(len(lons)) ] mesh = RectangularMesh.from_points_list(points) self.assertTrue((mesh.lons == lons).all()) self.assertTrue((mesh.lats == lats).all()) self.assertTrue((mesh.depths == depths).all()) points = [ [Point(lons[i][j], lats[i][j], depth=0) for j in range(len(lons[i]))] for i in range(len(lons)) ] mesh = RectangularMesh.from_points_list(points) self.assertTrue((mesh.lons == lons).all()) self.assertTrue((mesh.lats == lats).all()) self.assertIsNone(mesh.depths)
def from_fault_data(cls, edges, mesh_spacing): """ Create and return a fault surface using fault source data. :param edges: A list of at least two horizontal edges of the surface as instances of :class:`openquake.hazardlib.geo.line.Line`. The list should be in top-to-bottom order (the shallowest edge first). :param mesh_spacing: Distance between two subsequent points in a mesh, in km. :returns: An instance of :class:`ComplexFaultSurface` created using that data. :raises ValueError: If requested mesh spacing is too big for the surface geometry (doesn't allow to put a single mesh cell along length and/or width). Uses :meth:`check_fault_data` for checking parameters. """ cls.check_fault_data(edges, mesh_spacing) surface_nodes = [complex_fault_node(edges)] mean_length = numpy.mean([edge.get_length() for edge in edges]) num_hor_points = int(round(mean_length / mesh_spacing)) + 1 if num_hor_points <= 1: raise ValueError( 'mesh spacing %.1f km is too big for mean length %.1f km' % (mesh_spacing, mean_length) ) edges = [edge.resample_to_num_points(num_hor_points).points for i, edge in enumerate(edges)] vert_edges = [Line(v_edge) for v_edge in zip(*edges)] mean_width = numpy.mean([v_edge.get_length() for v_edge in vert_edges]) num_vert_points = int(round(mean_width / mesh_spacing)) + 1 if num_vert_points <= 1: raise ValueError( 'mesh spacing %.1f km is too big for mean width %.1f km' % (mesh_spacing, mean_width) ) points = zip(*[v_edge.resample_to_num_points(num_vert_points).points for v_edge in vert_edges]) mesh = RectangularMesh.from_points_list(list(points)) assert 1 not in mesh.shape self = cls(mesh) self.surface_nodes = surface_nodes return self
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 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 _create_mesh(self): points = [[Point(*coordinates) for coordinates in row] for row in self.coordinates_list] return RectangularMesh.from_points_list(points)
def from_fault_data(cls, fault_trace, upper_seismogenic_depth, lower_seismogenic_depth, dip, mesh_spacing): """ Create and return a fault surface using fault source data. :param openquake.hazardlib.geo.line.Line fault_trace: Geographical line representing the intersection between the fault surface and the earth surface. The line must be horizontal (i.e. all depth values must be equal). If the depths are not given, they are assumed to be zero, meaning the trace intersects the surface at sea level, e.g. fault_trace = Line([Point(1, 1), Point(1, 2)]). :param upper_seismo_depth: Minimum depth ruptures can reach, in km (i.e. depth to fault's top edge). :param lower_seismo_depth: Maximum depth ruptures can reach, in km (i.e. depth to fault's bottom edge). :param dip: Dip angle (i.e. angle between fault surface and earth surface), in degrees. :param mesh_spacing: Distance between two subsequent points in a mesh, in km. :returns: An instance of :class:`SimpleFaultSurface` created using that data. Uses :meth:`check_fault_data` for checking parameters. """ cls.check_fault_data(fault_trace, upper_seismogenic_depth, lower_seismogenic_depth, dip, mesh_spacing) # Loops over points in the top edge, for each point # on the top edge compute corresponding point on the bottom edge, then # computes equally spaced points between top and bottom points. vdist_top = upper_seismogenic_depth - fault_trace[0].depth vdist_bottom = lower_seismogenic_depth - fault_trace[0].depth hdist_top = vdist_top / math.tan(math.radians(dip)) hdist_bottom = vdist_bottom / math.tan(math.radians(dip)) strike = fault_trace[0].azimuth(fault_trace[-1]) azimuth = (strike + 90.0) % 360 mesh = [] for point in fault_trace.resample(mesh_spacing): top = point.point_at(hdist_top, vdist_top, azimuth) bottom = point.point_at(hdist_bottom, vdist_bottom, azimuth) mesh.append(top.equally_spaced_points(bottom, mesh_spacing)) # number of rows corresponds to number of points along dip # number of columns corresponds to number of points along strike surface_points = numpy.array(mesh).transpose().tolist() mesh = RectangularMesh.from_points_list(surface_points) assert 1 not in mesh.shape, ( "Mesh must have at least 2 nodes along both length and width." " Possible cause: Mesh spacing could be too large with respect to" " the fault length and width.") self = cls(mesh) self.surface_nodes = [ simple_fault_node(fault_trace, dip, upper_seismogenic_depth, lower_seismogenic_depth) ] return self
def _create_mesh(self): points = [[Point(*coordinates) for coordinates in row] for row in self.coordinates_list] return RectangularMesh.from_points_list(points)
def __init__(self, coordinates_list): points = [[Point(*coordinates) for coordinates in row] for row in coordinates_list] self.mesh = RectangularMesh.from_points_list(points)