def test_create_oqhazardlib_source(self): # Tests to ensure the hazardlib source is created trace = line.Line([point.Point(10., 10.), point.Point(11., 10.)]) mfd1 = TruncatedGRMFD(5.0, 8.0, 0.1, 3.0, 1.0) self.fault_source = mtkSimpleFaultSource( '001', 'A Fault Source', trt='Active Shallow Crust', geometry=None, dip=90., upper_depth=0., lower_depth=20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=mfd1, rake=0.) self.fault_source.create_geometry(trace, 90., 0., 20., 1.0) test_source = self.fault_source.create_oqhazardlib_source(TOM, 2.0, True) self.assertIsInstance(test_source, SimpleFaultSource) self.assertIsInstance(test_source.mfd, TruncatedGRMFD) self.assertAlmostEqual(test_source.mfd.b_val, 1.0) self.assertIsInstance(test_source.magnitude_scaling_relationship, WC1994)
def test_create_oqhazardlib_complex_fault_source(self): """ Tests the conversion of a point source to an instance of the :class: openquake.hazardlib.source.complex_fault.ComplexFaultSource """ complex_edges = [ line.Line([point.Point(11., 10., 0.), point.Point(10., 10., 0.)]), line.Line( [point.Point(11.5, 10., 21.), point.Point(10.0, 10., 21.)]) ] self.fault_source = mtkComplexFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=None, mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=models.TGRMFD( a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) self.fault_source.create_geometry(complex_edges, 2.0) test_source = self.fault_source.create_oqhazardlib_source( TOM, 5.0, True) self.assertIsInstance(test_source, ComplexFaultSource) self.assertIsInstance(test_source.mfd, TruncatedGRMFD) self.assertAlmostEqual(test_source.mfd.b_val, 1.0) self.assertIsInstance(test_source.magnitude_scaling_relationship, WC1994)
def test_create_oqhazardlib_source(self): # Define a complete source area_geom = polygon.Polygon([ point.Point(10., 10.), point.Point(12., 10.), point.Point(12., 8.), point.Point(10., 8.) ]) mfd1 = TruncatedGRMFD(5.0, 8.0, 0.1, 3.0, 1.0) self.area_source = mtkAreaSource('001', 'A Point Source', trt='Active Shallow Crust', geometry=area_geom, upper_depth=0., lower_depth=20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=mfd1, nodal_plane_dist=None, hypo_depth_dist=None) test_source = self.area_source.create_oqhazardlib_source( TOM, 1.0, 10.0, True) self.assertIsInstance(test_source, AreaSource) self.assertIsInstance(test_source.mfd, TruncatedGRMFD) self.assertAlmostEqual(test_source.mfd.b_val, 1.0) self.assertIsInstance(test_source.nodal_plane_distribution, PMF) self.assertIsInstance(test_source.hypocenter_distribution, PMF) self.assertIsInstance(test_source.magnitude_scaling_relationship, WC1994)
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
def get_top_edge(lat, lon, dep): """ Determine which edge of a quadrilateral rupture surface is the top. :param lat: Sequence of 4 or 5 latitudes defining vertices of rupture surface. :param lon: Sequence of 4 or 5 longitudes defining vertices of rupture surface. :param dep: Sequence of 4 or 5 depths defining vertices of rupture surface. :returns: (P0,P1) where P0 and P1 are Vector objects in ECEF coordinates indicating the vertices of the top edge. """ lat = np.array(lat) lon = np.array(lon) dep = np.array(dep) p1 = None p2 = None if sum(np.diff(dep)) == 0: p1 = Vector.fromPoint(point.Point(lon[0], lat[0], dep[0])) p2 = Vector.fromPoint(point.Point(lon[1], lat[1], dep[1])) else: dep2 = dep[0:4] dd = np.diff(dep2) idx = dd == 0 idx = np.append(idx, False) p1idx = dep2[idx].argmin() + 1 p2idx = p1idx + 1 p1 = Vector.fromPoint(point.Point(lon[p1idx], lat[p1idx], 0.0)) p2 = Vector.fromPoint(point.Point(lon[p2idx], lat[p2idx], 0.0)) return (p1, p2)
def test_select_within_fault_distance(self): # Tests the selection of events within a distance from the fault # Set up catalouge self.catalogue = Catalogue() self.catalogue.data['longitude'] = np.arange(0., 5.5, 0.5) self.catalogue.data['latitude'] = np.arange(0., 5.5, 0.5) self.catalogue.data['depth'] = np.zeros(11, dtype=float) self.catalogue.data['eventID'] = np.arange(0, 11, 1) self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') trace_as_line = line.Line([point.Point(2.0, 3.0), point.Point(3.0, 2.0)]) self.fault_source.create_geometry(trace_as_line, 30., 0., 30.) selector0 = CatalogueSelector(self.catalogue) # Test 1 - simple case Joyner-Boore distance self.fault_source.select_catalogue(selector0, 40.) np.testing.assert_array_almost_equal( np.array([2., 2.5]), self.fault_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([2., 2.5]), self.fault_source.catalogue.data['latitude']) # Test 2 - simple case Rupture distance self.fault_source.catalogue = None self.fault_source.select_catalogue(selector0, 40., 'rupture') np.testing.assert_array_almost_equal( np.array([2.5]), self.fault_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([2.5]), self.fault_source.catalogue.data['latitude']) # Test 3 - for vertical fault ensure that Joyner-Boore distance # behaviour is the same as for rupture distance fault1 = mtkSimpleFaultSource('102', 'A vertical fault') fault1.create_geometry(trace_as_line, 90., 0., 30.) self.fault_source.create_geometry(trace_as_line, 90., 0., 30.) # Joyner-Boore self.fault_source.select_catalogue(selector0, 40.) # Rupture fault1.select_catalogue(selector0, 40., 'rupture') np.testing.assert_array_almost_equal( self.fault_source.catalogue.data['longitude'], fault1.catalogue.data['longitude']) np.testing.assert_array_almost_equal( self.fault_source.catalogue.data['latitude'], fault1.catalogue.data['latitude']) # The usual test to ensure error is raised when no events in catalogue self.catalogue = Catalogue() selector0 = CatalogueSelector(self.catalogue) with self.assertRaises(ValueError) as ver: self.fault_source.select_catalogue(selector0, 40.0) self.assertEqual(str(ver.exception), 'No events found in catalogue!')
def test_geometry_inputs(self): # Tests the geometry definition simple_polygon = polygon.Polygon([point.Point(2.0, 3.0), point.Point(3.0, 3.0), point.Point(3.0, 2.0), point.Point(2.0, 2.0)]) simple_polygon_array = np.array([[2.0, 3.0], [3.0, 3.0], [3.0, 2.0], [2.0, 2.0]]) # Using nhlib.geo.polygon.Polygon class as input self.area_source.create_geometry(simple_polygon, 0.0, 30.0) # Check that geometry is an instance of nhlib.geo.polygon.Polygon self.assertTrue(isinstance(self.area_source.geometry, polygon.Polygon)) np.testing.assert_array_almost_equal(self.area_source.geometry.lons, np.array([2., 3., 3., 2.])) np.testing.assert_array_almost_equal(self.area_source.geometry.lats, np.array([3., 3., 2., 2.])) self.assertAlmostEqual(0.0, self.area_source.upper_depth) self.assertAlmostEqual(30.0, self.area_source.lower_depth) self.area_source = mtkAreaSource('101', 'A Source') # Using numpy array as input self.area_source.create_geometry(simple_polygon_array, 0.0, 30.0) self.assertTrue(isinstance(self.area_source.geometry, polygon.Polygon)) # Check that geometry is an instance of nhlib.geo.polygon.Polygon np.testing.assert_array_almost_equal(self.area_source.geometry.lons, np.array([2., 3., 3., 2.])) np.testing.assert_array_almost_equal(self.area_source.geometry.lats, np.array([3., 3., 2., 2.])) self.assertAlmostEqual(0.0, self.area_source.upper_depth) self.assertAlmostEqual(30.0, self.area_source.lower_depth) # For any other input type - check ValueError is raised self.area_source = mtkAreaSource('101', 'A Source') with self.assertRaises(ValueError) as ver: self.area_source.create_geometry('a bad input', 0.0, 30.0) self.assertEqual(str(ver.exception), 'Unrecognised or unsupported geometry definition') # For numpy array with only two rows self.area_source = mtkAreaSource('101', 'A Source') simple_polygon_array = np.array([[2.0, 3.0], [3.0, 3.0]]) with self.assertRaises(ValueError) as ver: self.area_source.create_geometry(simple_polygon_array, 0.0, 30.0) self.assertEqual(str(ver.exception), 'Incorrectly formatted polygon geometry - ' 'needs three or more vertices')
def test_select_events_in_source(self): ''' Basic test of method to select events from catalogue in polygon ''' self.area_source = mtkAreaSource('101', 'A Source') simple_polygon = polygon.Polygon([ point.Point(2.0, 3.0), point.Point(3.0, 3.0), point.Point(3.0, 2.0), point.Point(2.0, 2.0) ]) self.catalogue.data['eventID'] = np.arange(0, 7, 1) self.catalogue.data['longitude'] = np.arange(1.0, 4.5, 0.5) self.catalogue.data['latitude'] = np.arange(1.0, 4.5, 0.5) self.catalogue.data['depth'] = np.ones(7, dtype=float) # Simple Case - No buffer selector0 = CatalogueSelector(self.catalogue) self.area_source.create_geometry(simple_polygon, 0., 30.) self.area_source.select_catalogue(selector0, 0.) np.testing.assert_array_almost_equal( np.array([2., 2.5, 3.]), self.area_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([2., 2.5, 3.]), self.area_source.catalogue.data['latitude']) np.testing.assert_array_almost_equal( np.array([1., 1., 1.]), self.area_source.catalogue.data['depth']) # Simple case - dilated by 200 km (selects all) self.area_source.select_catalogue(selector0, 200.) np.testing.assert_array_almost_equal( np.array([1., 1.5, 2., 2.5, 3., 3.5, 4.0]), self.area_source.catalogue.data['longitude']) np.testing.assert_array_almost_equal( np.array([1., 1.5, 2., 2.5, 3., 3.5, 4.0]), self.area_source.catalogue.data['latitude']) np.testing.assert_array_almost_equal( np.ones(7, dtype=float), self.area_source.catalogue.data['depth']) # Bad case - no events in catalogue self.catalogue = Catalogue() selector0 = CatalogueSelector(self.catalogue) with self.assertRaises(ValueError) as ver: self.area_source.select_catalogue(selector0, 0.0) self.assertEqual(ver.exception.message, 'No events found in catalogue!')
def setUp(self): warnings.simplefilter("ignore") self.catalogue = Catalogue() self.fault_source = None self.trace_line = [line.Line([point.Point(1.0, 0.0, 1.0), point.Point(0.0, 1.0, 0.9)])] self.trace_line.append(line.Line([point.Point(1.2, 0.0, 40.), point.Point(1.0, 1.0, 45.), point.Point(0.0, 1.3, 42.)])) self.trace_array = [np.array([[1.0, 0.0, 1.0], [0.0, 1.0, 0.9]])] self.trace_array.append(np.array([[1.2, 0.0, 40.], [1.0, 1.0, 45.], [0.0, 1.3, 42.]]))
def test_create_oqnmrl_simple_fault_source(self): ''' Tests the conversion of a point source to an instance of the :class: oqnrmllib.models.SimpleFaultSource ''' trace = line.Line([point.Point(10., 10.), point.Point(11., 10.)]) #sflt_geom = SimpleFaultSurface.from_fault_data(trace, 0., 20., 90., 1.) # Define a complete source self.fault_source = mtkSimpleFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=None, dip=90., upper_depth=0., lower_depth=20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=models.TGRMFD( a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) self.fault_source.create_geometry(trace, 90., 0., 20., 1.0) expected_geometry = models.SimpleFaultGeometry( wkt='LINESTRING (10.0 10.0, 11.0 10.0)', dip=90., upper_seismo_depth=0., lower_seismo_depth=20.) expected_source = models.SimpleFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=expected_geometry, mag_scale_rel='WC1994', rupt_aspect_ratio=1.0, mfd=models.TGRMFD( a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) test_source = self.fault_source.create_oqnrml_source(use_defaults=True) self.assertTrue(isinstance(test_source, models.SimpleFaultSource)) self.assertEqual(test_source.id, expected_source.id) self.assertEqual(test_source.name, expected_source.name) self.assertDictEqual(test_source.geometry.__dict__, expected_source.geometry.__dict__) self.assertAlmostEqual(test_source.mfd.b_val, expected_source.mfd.b_val)
def test_create_oqnmrl_complex_fault_source(self): ''' Tests the conversion of a point source to an instance of the :class: oqnrmllib.models.AreaSource ''' # Define a complete source complex_edges = [ line.Line([point.Point(10., 10., 0.), point.Point(11., 10., 0.)]), line.Line( [point.Point(10., 10., 20.), point.Point(11.5, 10., 21.)]) ] self.fault_source = mtkComplexFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=None, mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=models.TGRMFD( a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=0.) self.fault_source.create_geometry(complex_edges, 2.0) expected_geometry = models.ComplexFaultGeometry( top_edge_wkt='LINESTRING (10.0 10.0 0.0, 11.0 10.0 0.0)', bottom_edge_wkt='LINESTRING (10.0 10.0 20.0, 11.5 10.0 21.0)') expected_source = models.ComplexFaultSource('001', 'A Fault Source', trt='Active Shallow Crust', geometry=expected_geometry, mag_scale_rel='WC1994', rupt_aspect_ratio=1.0, mfd=models.TGRMFD( a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), rake=90.) test_source = self.fault_source.create_oqnrml_source(use_defaults=True) self.assertTrue(isinstance(test_source, models.ComplexFaultSource)) self.assertEqual(test_source.id, expected_source.id) self.assertEqual(test_source.name, expected_source.name) self.assertAlmostEqual(test_source.mfd.b_val, expected_source.mfd.b_val)
def toPoint(self): """ Convert the Vector to a hazardlib Point object, after translating back to lat,lon,depth. :returns: a Point object as defined at https://github.com/gem/oq-hazardlib/blob/master/openquake/hazardlib/geo/point.py """ lat, lon, dep = ecef2latlon(self.x, self.y, self.z) return point.Point(lon, lat, dep)
def test_create_oqnmrl_area_source(self): ''' Tests the conversion of a point source to an instance of the :class: oqnrmllib.models.AreaSource ''' # Define a complete source area_geom = polygon.Polygon([ point.Point(10., 10.), point.Point(12., 10.), point.Point(12., 8.), point.Point(10., 8.) ]) self.area_source = mtkAreaSource('001', 'A Point Source', trt='Active Shallow Crust', geometry=area_geom, upper_depth=0., lower_depth=20., mag_scale_rel=None, rupt_aspect_ratio=1.0, mfd=models.TGRMFD(a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), nodal_plane_dist=None, hypo_depth_dist=None) expected_source = models.AreaSource('001', 'A Point Source', geometry=models.AreaGeometry( area_geom.wkt, 0., 20.), mag_scale_rel='WC1994', rupt_aspect_ratio=1.0, mfd=models.TGRMFD(a_val=3., b_val=1.0, min_mag=5.0, max_mag=8.0), nodal_plane_dist=None, hypo_depth_dist=None) test_source = self.area_source.create_oqnrml_source(use_defaults=True) self.assertTrue(isinstance(test_source, models.AreaSource)) self.assertEqual(test_source.id, expected_source.id) self.assertEqual(test_source.name, expected_source.name) self.assertAlmostEqual(test_source.mfd.b_val, expected_source.mfd.b_val)
def test_create_complex_geometry(self): ''' Tests the complex geometry creation ''' self.fault_source = mtkComplexFaultSource('101', 'A complex fault') # Test case when input as list of nhlib.geo.line.Line self.fault_source.create_geometry(self.trace_line, mesh_spacing=2.0) self.assertIsInstance(self.fault_source.geometry, ComplexFaultSurface) # Use the dip as a simple indicator of geometrical success! self.assertAlmostEqual(self.fault_source.dip, 40.5398531, 2) # Create a second instance fault2 = mtkComplexFaultSource('101', 'A complex fault') fault2.create_geometry(self.trace_array, mesh_spacing=2.0) self.assertIsInstance(fault2.geometry, ComplexFaultSurface) # Compare it to the first self.assertAlmostEqual(self.fault_source.dip, fault2.dip) # If less than two edges are input ensure error is raised bad_traces = [ line.Line([point.Point(1.0, 0.0, 3.0), point.Point(1.0, 0.0, 3.0)]) ] self.fault_source = mtkComplexFaultSource('101', 'A complex fault') with self.assertRaises(ValueError) as ver: self.fault_source.create_geometry(bad_traces) self.assertEqual(ver.exception.message, 'Complex fault geometry ' 'incorrectly defined') # If an edge is not defined from either a nhlib.geo.line.Line instance # or numpy.ndarray then ensure error is raised bad_traces = [ line.Line([point.Point(1.0, 0.0, 3.0), point.Point(1.0, 0.0, 3.0)]) ] bad_traces.append('a bad input') self.fault_source = mtkComplexFaultSource('101', 'A complex fault') with self.assertRaises(ValueError) as ver: self.fault_source.create_geometry(bad_traces) self.assertEqual(ver.exception.message, 'Unrecognised or unsupported ' 'geometry definition')
def getHypo(self): """ :returns: Hypocenter point. """ hyplat = self.getEventParam('lat') hyplon = self.getEventParam('lon') hypdepth = self.getEventParam('depth') hyppoint = point.Point(hyplon, hyplat, hypdepth) return hyppoint
def test_create_fault_geometry(self): # Tests the creation of the fault geometry. Testing only behaviour # for creating SimpleFaultSurface classes - not the values in the # class (assumes nhlib implementation is correct) # Case 1 - trace input as instance of nhlib.geo.line.Line class self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') trace_as_line = line.Line( [point.Point(2.0, 3.0), point.Point(3.0, 2.0)]) self.fault_source.create_geometry(trace_as_line, 60., 0., 30.) self.assertIsInstance(self.fault_source.geometry, SimpleFaultSurface) # Case 2 - trace input as numpy array trace_as_array = np.array([[2.0, 3.0], [3.0, 2.0]]) self.fault_source = mtkSimpleFaultSource('101', 'A simple fault') self.fault_source.create_geometry(trace_as_array, 60., 0., 30.) self.assertIsInstance(self.fault_source.geometry, SimpleFaultSurface) # Case 3 - raises error when something else is input with self.assertRaises(ValueError) as ver: self.fault_source.create_geometry('a bad input!', 60., 0., 30.) self.assertEqual(str(ver.exception), 'Unrecognised or unsupported geometry definition')
def _setQuadrilaterals(self): """ Create internal list of N quadrilaterals. """ # Fault QA rules # 1) Fault must consist of 1 or more quadrilaterals, where each quad # top/bottom edges are parallel to the surface # 2) The strike angle of each quadrilateral is defined by the first two # vertices of that quad # 3) The dip angle is defined by segments 2 and 3, or 1 and 4. This # angle must be clockwise with respect to the strike angle, and # between 0 and 90 degrees. # 4) The top edge of each quad must be defined by the first two vertices # of that quad. # 5) 4 points of quadrilateral must be co-planar self._lon = np.array(self._lon) self._lat = np.array(self._lat) self._depth = np.array(self._depth) inan = np.isnan(self._lon) numnans = len(self._lon[inan]) numsegments = numnans + 1 # requirements: # 1) Coordinate arrays must be same length # 2) Polygons must be quadrilaterals # 3) Quads must be closed # 4) Quads must be planar if len(self._lon) != len(self._lat) != len(self._depth): raise IndexError( 'Length of input lon,lat,depth arrays must be equal') # Addition: self._segment_index # It is also convenient to create a list of indexes for which 'trace' # each quad is on (i.e, grouped). This information is required for GC2 # calculations. Also, in some rare situations, we need to be able to # overwrite the default values. istart = 0 endpoints = list(np.where(np.isnan(self._lon))[0]) endpoints.append(len(self._lon)) self._quadrilaterals = [] self._segment_index = [] segind = 0 for iend in endpoints: lonseg = self._lon[istart:iend][0:-1] # remove closing points latseg = self._lat[istart:iend][0:-1] depthseg = self._depth[istart:iend][0:-1] # each segment can have many contiguous quadrilaterals defined in it # separations (nans) between segments mean that segments are not # contiguous. npoints = len(lonseg) nquads = int((npoints - 4) / 2) + 1 startidx = 0 endidx = -1 for i in range(0, nquads): topLeft = point.Point(lonseg[startidx], latseg[startidx], depthseg[startidx]) topRight = point.Point(lonseg[startidx + 1], latseg[startidx + 1], depthseg[startidx + 1]) bottomRight = point.Point(lonseg[endidx - 1], latseg[endidx - 1], depthseg[endidx - 1]) bottomLeft = point.Point(lonseg[endidx], latseg[endidx], depthseg[endidx]) surface = self._validateQuad(topLeft, topRight, bottomRight, bottomLeft) self._quadrilaterals.append(surface) startidx += 1 endidx -= 1 istart = iend + 1 self._segment_index.extend([segind] * nquads) segind = segind + 1
def test_so6(): magnitude = 7.2 dip = np.array([70]) rake = 135 width = np.array([15]) L = 80 rupx = np.array([0, 0]) rupy = np.array([0, L]) zp = np.array([0]) # Convert to lat/lon proj = geo.utils.get_orthographic_projection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) # Dummy origin origin = Origin({ 'lat': 0, 'lon': 0, 'depth': 0, 'mag': 0, 'eventsourcecode': 'so6', 'rake': rake }) # Rupture rup = QuadRupture.fromTrace(np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='rv4') # Sites x = np.linspace(-80, 80, 21) y = np.linspace(-50, 130, 21) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) sdepth = np.zeros_like(slon) # Fix origin tmp = rup.getQuadrilaterals()[0] pp0 = Vector.fromPoint( point.Point(tmp[0].longitude, tmp[0].latitude, tmp[0].depth)) pp1 = Vector.fromPoint( point.Point(tmp[1].longitude, tmp[1].latitude, tmp[1].depth)) pp2 = Vector.fromPoint( point.Point(tmp[2].longitude, tmp[2].latitude, tmp[2].depth)) pp3 = Vector.fromPoint( point.Point(tmp[3].longitude, tmp[3].latitude, tmp[3].depth)) dxp = 10 / L dyp = (width - 5) / width mp0 = pp0 + (pp1 - pp0) * dxp mp1 = pp3 + (pp2 - pp3) * dxp rp = mp0 + (mp1 - mp0) * dyp epilat, epilon, epidepth = ecef2latlon(rp.x, rp.y, rp.z) epix, epiy = proj(epilon, epilat, reverse=False) origin = Origin({ 'lat': epilat, 'lon': epilon, 'depth': epidepth, 'mag': magnitude, 'eventsourcecode': 'so6', 'rake': rake }) ruplat = [a.latitude for a in rup.getQuadrilaterals()[0]] ruplon = [a.longitude for a in rup.getQuadrilaterals()[0]] ruplat = np.append(ruplat, ruplat[0]) ruplon = np.append(ruplon, ruplon[0]) rupx, rupy = proj(ruplon, ruplat, reverse=False) test1 = Bayless2013(origin, rup, slat, slon, sdepth, T=5) fd = test1.getFd() fd_test = np.array([ [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -8.92879772e-03, -1.74526918e-02, -2.22981746e-02, -2.34350450e-02, -2.13620062e-02, -1.72712346e-02, -1.29509613e-02, -1.02545064e-02, -1.03010185e-02, -1.28847597e-02, -1.66274727e-02, -1.96984070e-02, -2.05377743e-02, -1.81831337e-02, -1.21881814e-02, -2.64862879e-03, 0.00000000e+00, 0.00000000e+00 ], [ 0.00000000e+00, 0.00000000e+00, -8.73221519e-03, -2.21421374e-02, -3.18438939e-02, -3.71488270e-02, -3.76239913e-02, -3.35015951e-02, -2.61748968e-02, -1.83864728e-02, -1.34793002e-02, -1.36687799e-02, -1.85727143e-02, -2.55527671e-02, -3.14227568e-02, -3.38933995e-02, -3.19289607e-02, -2.53396980e-02, -1.45943649e-02, -3.71405488e-04, 0.00000000e+00 ], [ 0.00000000e+00, -2.54621422e-03, -2.11428566e-02, -3.68609103e-02, -4.87464747e-02, -5.56539037e-02, -5.64419387e-02, -5.05331157e-02, -3.52919381e-02, -2.18782050e-02, -1.40858125e-02, -1.47354546e-02, -2.35727189e-02, -3.74838465e-02, -4.75915414e-02, -5.13000399e-02, -4.87882409e-02, -4.05716321e-02, -2.77368254e-02, -1.13542729e-02, 0.00000000e+00 ], [ 0.00000000e+00, -1.21642958e-02, -3.33747360e-02, -5.21661817e-02, -6.74724509e-02, -7.77628842e-02, -8.00243748e-02, -6.42496853e-02, -4.38124530e-02, -1.97027426e-02, -1.45897731e-02, -1.07427056e-02, -3.08235222e-02, -4.82656988e-02, -6.67692677e-02, -7.35152908e-02, -6.85574283e-02, -5.71811573e-02, -4.12138780e-02, -2.20396726e-02, -6.24121310e-04 ], [ 0.00000000e+00, -2.00643401e-02, -4.39827328e-02, -6.62722434e-02, -8.60268414e-02, -1.01730306e-01, -9.86277741e-02, -9.82914922e-02, -5.22335876e-02, -1.54622435e-02, -1.57487554e-02, -3.06190808e-03, -4.81481586e-02, -8.92480491e-02, -8.63776477e-02, -9.98130440e-02, -8.95491230e-02, -7.33553695e-02, -5.34401725e-02, -3.11601812e-02, -7.33715103e-03 ], [ 0.00000000e+00, -2.50053614e-02, -5.11695772e-02, -7.65997026e-02, -1.00809054e-01, -1.22877573e-01, -1.18738178e-01, -1.55236782e-01, -7.45388001e-02, 1.92779182e-03, -1.94380016e-02, 1.94922939e-02, -7.66669920e-02, -1.53909722e-01, -1.10846875e-01, -1.19746768e-01, -1.07680300e-01, -8.59905101e-02, -6.22042294e-02, -3.71802472e-02, -1.13867485e-02 ], [ 0.00000000e+00, -2.63645827e-02, -5.37984901e-02, -8.11337022e-02, -1.08298371e-01, -1.35146441e-01, -1.34825430e-01, -1.85836050e-01, -1.10730875e-01, -3.18861095e-02, 4.14395701e-02, -1.52711946e-02, -1.31840763e-01, -1.96794707e-01, -1.33453212e-01, -1.34989129e-01, -1.17922385e-01, -9.21637323e-02, -6.58369237e-02, -3.91646838e-02, -1.22685698e-02 ], [ 0.00000000e+00, -2.64622244e-02, -5.40483999e-02, -8.16190336e-02, -1.09162854e-01, -1.36656677e-01, -1.37081504e-01, -1.89522811e-01, -1.17723634e-01, -4.88765748e-02, -5.04529015e-03, -5.76414497e-02, -1.45712183e-01, -2.03062804e-01, -1.36859828e-01, -1.37107390e-01, -1.19124650e-01, -9.28263279e-02, -6.61800709e-02, -3.93088682e-02, -1.22842049e-02 ], [ 0.00000000e+00, -2.58466495e-02, -5.24858827e-02, -7.86086164e-02, -1.03856343e-01, -1.27529509e-01, -1.23794779e-01, -1.68810613e-01, -8.22602627e-02, 1.74236964e-02, 9.38708725e-02, 4.23208284e-02, -8.46343723e-02, -1.70476759e-01, -1.17547884e-01, -1.24569752e-01, -1.11518670e-01, -8.84736806e-02, -6.38037151e-02, -3.81874381e-02, -1.19867610e-02 ], [ 0.00000000e+00, -2.42186547e-02, -4.84175525e-02, -7.09428614e-02, -9.07754575e-02, -1.06117824e-01, -9.50228292e-02, -1.29781980e-01, -3.08573454e-02, 7.39058739e-02, 1.30478117e-01, 8.28181149e-02, -2.70389535e-02, -1.20837502e-01, -8.02081725e-02, -9.70274506e-02, -9.35853383e-02, -7.77422806e-02, -5.77817530e-02, -3.53067886e-02, -1.12414659e-02 ], [ 0.00000000e+00, -2.16818717e-02, -4.22363856e-02, -5.96909893e-02, -7.24805224e-02, -7.81867829e-02, -6.11838569e-02, -9.05679744e-02, 9.95934969e-03, 1.07503875e-01, 1.52073917e-01, 1.05894634e-01, 8.68652263e-03, -7.98571818e-02, -4.16548658e-02, -6.40511838e-02, -6.99337160e-02, -6.26305633e-02, -4.89098800e-02, -3.09284566e-02, -1.00919381e-02 ], [ 0.00000000e+00, -1.84940182e-02, -3.47054606e-02, -4.65278129e-02, -5.22037664e-02, -4.93977115e-02, -2.95395230e-02, -5.82421092e-02, 3.91025654e-02, 1.29337956e-01, 1.67436703e-01, 1.21969296e-01, 3.20823547e-02, -5.00287386e-02, -9.22993907e-03, -3.27186625e-02, -4.52706958e-02, -4.57409325e-02, -3.84701291e-02, -2.55751405e-02, -8.64950254e-03 ], [ 0.00000000e+00, -1.49431380e-02, -2.65887341e-02, -3.29162158e-02, -3.22994323e-02, -2.29081781e-02, -2.60259636e-03, -3.29856530e-02, 6.02631314e-02, 1.45003704e-01, 1.79361264e-01, 1.34292814e-01, 4.88007115e-02, -2.82328554e-02, 1.64212421e-02, -5.72391847e-03, -2.23438861e-02, -2.90246794e-02, -2.76054402e-02, -1.97779758e-02, -7.03945406e-03 ], [ 0.00000000e+00, -1.12771143e-02, -1.84737590e-02, -1.98228664e-02, -1.40092305e-02, 1.84580818e-04, 1.95817303e-02, -1.32608487e-02, 7.62783168e-02, 1.57076433e-01, 1.89083905e-01, 1.44259188e-01, 6.15722813e-02, -1.17505212e-02, 3.65938109e-02, 1.66937711e-02, -2.18970818e-03, -1.35507683e-02, -1.70890527e-02, -1.39519424e-02, -5.37036892e-03 ], [ 0.00000000e+00, -7.67615215e-03, -1.07348257e-02, -7.75276739e-03, 2.22351695e-03, 1.98662250e-02, 3.77611177e-02, 2.42018661e-03, 8.89036172e-02, 1.66855206e-01, 1.97260700e-01, 1.52590263e-01, 7.17981256e-02, 1.18005972e-03, 5.26852303e-02, 3.51638855e-02, 1.51012176e-02, 2.69654076e-04, -7.33815554e-03, -8.36639665e-03, -3.72176313e-03 ], [ 0.00000000e+00, -4.50552324e-03, -4.32262850e-03, 1.73559158e-03, 1.42670366e-02, 3.35040699e-02, 4.97279358e-02, 1.85410528e-02, 9.39950666e-02, 1.46646579e-01, 9.13474746e-02, 1.37004651e-01, 7.74648339e-02, 1.59777072e-02, 6.25334939e-02, 4.74577418e-02, 2.72155518e-02, 1.06174952e-02, 3.94103899e-04, -3.68465400e-03, -2.19830733e-03 ], [ 0.00000000e+00, -1.74629916e-03, 5.44471813e-04, 8.22933499e-03, 2.15699287e-02, 4.04232250e-02, 5.69678048e-02, 5.52408259e-02, 9.04381272e-02, 1.08204635e-01, 9.14439984e-02, 1.06884511e-01, 8.17241884e-02, 5.55282924e-02, 6.78528399e-02, 5.47188925e-02, 3.35251483e-02, 1.69615982e-02, 5.72048628e-03, -8.81437278e-05, -7.36518436e-04 ], [ 0.00000000e+00, 4.07838765e-05, 3.63933766e-03, 1.20080876e-02, 2.51274691e-02, 4.25687176e-02, 6.25685606e-02, 7.33480475e-02, 8.37515545e-02, 9.52500287e-02, 9.15135660e-02, 9.66442834e-02, 8.66659913e-02, 8.10325633e-02, 7.18836713e-02, 5.45548434e-02, 3.55884875e-02, 2.00142359e-02, 8.71200201e-03, 2.04407846e-03, -6.53680674e-06 ], [ 0.00000000e+00, 2.40054729e-04, 4.44975227e-03, 1.27572519e-02, 2.49362989e-02, 4.03831326e-02, 5.80039988e-02, 7.61280192e-02, 8.37404162e-02, 8.89634569e-02, 9.15651607e-02, 9.13586235e-02, 8.83589144e-02, 8.27804032e-02, 6.75666471e-02, 5.00483249e-02, 3.36733366e-02, 1.96758691e-02, 9.00603204e-03, 2.18370401e-03, 0.00000000e+00 ], [ 0.00000000e+00, 0.00000000e+00, 2.78776980e-03, 1.05086036e-02, 2.13238822e-02, 3.45577738e-02, 4.91570145e-02, 6.36787133e-02, 7.63710088e-02, 8.54072310e-02, 8.92960200e-02, 8.75702197e-02, 8.07095447e-02, 6.97999389e-02, 5.63787286e-02, 4.20734776e-02, 2.83073312e-02, 1.61614525e-02, 6.56194125e-03, 1.00721924e-04, 0.00000000e+00 ], [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 5.49667845e-03, 1.47563319e-02, 2.57955743e-02, 3.76689418e-02, 4.91861917e-02, 5.90108907e-02, 6.58478416e-02, 6.87018515e-02, 6.73174642e-02, 6.20270643e-02, 5.35456385e-02, 4.29400416e-02, 3.14129728e-02, 2.00795162e-02, 9.84001885e-03, 1.53992995e-03, 0.00000000e+00, 0.00000000e+00 ] ]) np.testing.assert_allclose(fd, fd_test, rtol=1e-4)
def test_rv4(): magnitude = 7.0 rake = 90.0 width = np.array([28]) rupx = np.array([0, 0]) rupy = np.array([0, 32]) zp = np.array([0]) dip = np.array([30]) # Convert to lat/lon proj = geo.utils.get_orthographic_projection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) # Dummy Origin origin = Origin({ 'lat': 0, 'lon': 0, 'depth': 0, 'mag': 0, 'eventsourcecode': 'rv4', 'rake': rake }) # Rupture rup = QuadRupture.fromTrace(np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='') L = rup.getLength() # Figure out epicenter tmp = rup.getQuadrilaterals()[0] pp0 = Vector.fromPoint( point.Point(tmp[0].longitude, tmp[0].latitude, tmp[0].depth)) pp1 = Vector.fromPoint( point.Point(tmp[1].longitude, tmp[1].latitude, tmp[1].depth)) pp2 = Vector.fromPoint( point.Point(tmp[2].longitude, tmp[2].latitude, tmp[2].depth)) pp3 = Vector.fromPoint( point.Point(tmp[3].longitude, tmp[3].latitude, tmp[3].depth)) dxp = 6 / L dyp = (width - 8) / width mp0 = pp0 + (pp1 - pp0) * dxp mp1 = pp3 + (pp2 - pp3) * dxp rp = mp0 + (mp1 - mp0) * dyp epilat, epilon, epidepth = ecef2latlon(rp.x, rp.y, rp.z) # Fix Origin: origin = Origin({ 'lat': epilat, 'lon': epilon, 'depth': epidepth, 'mag': magnitude, 'eventsourcecode': 'rv4', 'rake': rake }) x = np.linspace(-50, 50, 11) y = np.linspace(-50, 50, 11) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) deps = np.zeros_like(slon) test1 = Bayless2013(origin, rup, slat, slon, deps, T=2.0) # Test fd fd = test1.getFd() fd_test = np.array( [[ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.72143257e-03, 1.34977260e-03, 4.33616224e-15, 1.24446253e-03, 1.16142357e-03, 2.25464716e-03, 7.05281751e-04, 0.00000000e+00 ], [ 0.00000000e+00, 0.00000000e+00, 7.62610242e-03, 1.25133844e-02, 5.61896104e-03, 7.63126014e-15, 4.52266194e-03, 4.67970900e-03, 1.02820316e-02, 5.13160096e-03, -6.13926251e-03 ], [ 0.00000000e+00, 4.00495234e-03, 2.37608386e-02, 2.37139333e-02, 9.55224050e-03, 5.66364910e-15, 7.70344813e-03, 7.36466362e-03, 1.48239704e-02, 8.40388145e-03, -1.58592485e-02 ], [ 8.08385547e-19, 9.38150101e-03, 3.38610620e-02, 3.85351492e-02, 1.91044918e-02, 3.98697802e-15, 1.54321666e-02, 1.21913760e-02, 2.04435166e-02, 1.04931859e-02, -1.85935894e-02 ], [ 2.12025421e-18, 1.37316085e-02, 4.40193799e-02, 6.16562477e-02, 4.77612496e-02, 2.60257085e-15, 3.86322888e-02, 1.97965887e-02, 2.64882038e-02, 1.23335908e-02, -2.07389932e-02 ], [ 2.64338576e-18, 1.45898292e-02, 4.89104213e-02, 7.70703166e-02, 9.55225258e-02, 1.01875104e-01, 7.73459329e-02, 2.50275508e-02, 2.93537540e-02, 1.30949577e-02, -2.15685454e-02 ], [ 2.64330042e-18, 1.45898262e-02, 4.89104186e-02, 7.70703146e-02, 9.55225248e-02, 1.01910945e-01, 7.74050835e-02, 2.52307946e-02, 2.92970736e-02, 1.30880504e-02, -2.15685424e-02 ], [ 2.64318867e-18, 1.45898259e-02, 4.89104184e-02, 7.70703144e-02, 9.55225247e-02, 1.01933432e-01, 7.74421258e-02, 2.53572923e-02, 2.92615130e-02, 1.30837284e-02, -2.15685422e-02 ], [ 2.64305117e-18, 1.45898284e-02, 4.89104206e-02, 7.70703161e-02, 9.55225256e-02, 1.01942593e-01, 7.74571359e-02, 2.54081640e-02, 2.92472117e-02, 1.30819985e-02, -2.15685446e-02 ], [ 2.30141673e-18, 1.40210825e-02, 4.56205547e-02, 6.63109661e-02, 5.79266964e-02, 2.33044622e-15, 4.69672564e-02, 2.18401553e-02, 2.72864925e-02, 1.25728575e-02, -2.10227772e-02 ], [ 1.10672535e-18, 1.04777076e-02, 3.59041065e-02, 4.24614318e-02, 2.24217216e-02, 3.66914762e-15, 1.81728517e-02, 1.39301504e-02, 2.14956836e-02, 1.08711460e-02, -1.90802849e-02 ]]) np.testing.assert_allclose(fd, fd_test, rtol=2e-4)
def getHypo(self): """ Returns: Hypocenter as OpenQuake Point instance. """ return point.Point(self.lon, self.lat, self.depth)