def get_rx_distance(self, mesh): """ See :meth:`superclass method <.base.BaseSurface.get_rx_distance>` for spec of input and result values. The method extracts the top edge of the surface. For each point in mesh, it then computes the Rx distance to each segment the top edge is made of. The calculation is done by calling the function :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`. The final Rx distance matrix is then constructed by taking, for each point in mesh, the minimum Rx distance value computed. """ top_edge = self.get_mesh()[0:1] dists = [] for i in range(top_edge.lons.shape[1] - 1): p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats ) ) dists = numpy.array(dists) return numpy.min(dists, axis=0)
def iter_ruptures(self): """ See :meth:`openquake.hazardlib.source.base.BaseSeismicSource.iter_ruptures` for description of parameters and return value. Area sources are treated as a collection of point sources (see :mod:`openquake.hazardlib.source.point`) with uniform parameters. Ruptures of area source are just a union of ruptures of those point sources. The actual positions of the implied point sources form a uniformly spaced mesh on the polygon. Polygon's method :meth: `~openquake.hazardlib.geo.polygon.Polygon.discretize` is used for creating a mesh of points on the source's area. Constructor's parameter ``area_discretization`` is used as polygon's discretization spacing (not to be confused with rupture surface's mesh spacing which is as well provided to the constructor). The ruptures' occurrence rates are rescaled with respect to number of points the polygon discretizes to. """ polygon_mesh = self.polygon.discretize(self.area_discretization) rate_scaling_factor = 1.0 / len(polygon_mesh) # take the very first point of the polygon mesh [epicenter0] = polygon_mesh[0:1] # generate "reference ruptures" -- all the ruptures that have the same # epicenter location (first point of the polygon's mesh) but different # magnitudes, nodal planes, hypocenters' depths and occurrence rates ref_ruptures = [] for (mag, mag_occ_rate) in self.get_annual_occurrence_rates(): for (np_prob, np) in self.nodal_plane_distribution.data: for (hc_prob, hc_depth) in self.hypocenter_distribution.data: hypocenter = Point(latitude=epicenter0.latitude, longitude=epicenter0.longitude, depth=hc_depth) occurrence_rate = (mag_occ_rate * float(np_prob) * float(hc_prob)) occurrence_rate *= rate_scaling_factor surface = self._get_rupture_surface(mag, np, hypocenter) ref_ruptures.append((mag, np.rake, hc_depth, surface, occurrence_rate)) # for each of the epicenter positions generate as many ruptures # as we generated "reference" ones: new ruptures differ only # in hypocenter and surface location for epicenter in polygon_mesh: for mag, rake, hc_depth, surface, occ_rate in ref_ruptures: # translate the surface from first epicenter position # to the target one preserving it's geometry surface = surface.translate(epicenter0, epicenter) hypocenter = deepcopy(epicenter) hypocenter.depth = hc_depth rupture = ParametricProbabilisticRupture( mag, rake, self.tectonic_region_type, hypocenter, surface, type(self), occ_rate, self.temporal_occurrence_model ) yield rupture
def filter_sites_by_distance_to_rupture(cls, rupture, integration_distance, sites): """ Filter sites that are closer than rupture's projection radius plus integration distance along the great circle arc from rupture's epicenter location. Overrides the :meth:`base class' method <openquake.hazardlib.source.base.SeismicSource.filter_sites_by_distance_to_rupture>`. """ rup_length, rup_width = rupture.surface.length, rupture.surface.width rup_width = rup_width * math.cos(math.radians(rupture.surface.dip)) radius = math.sqrt(rup_length ** 2 + rup_width ** 2) / 2.0 radius += integration_distance epicenter = Point(rupture.hypocenter.longitude, rupture.hypocenter.latitude) return sites.filter(epicenter.closer_than(sites.mesh, radius))
def _rup_to_point(distance, surface, origin, azimuth, distance_type='rjb', iter_stop=1E-3, maxiter=1000): """ Place a point at a given distance from a rupture along a specified azimuth """ 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 test2_sites_parallel_to_fault_ends(self): surface = self._test1to7surface() sites = Mesh.from_points_list([Point(0.0, 0.05), Point(-0.10, -0.05)]) dists = surface.get_ry0_distance(sites) numpy.testing.assert_allclose(dists, numpy.array([0.0, 0.0]))
def get_rx_distance(self, mesh): """ Compute distance between each point of mesh and surface's great circle arc. Distance is measured perpendicular to the rupture strike, from the surface projection of the updip edge of the rupture, with the down dip direction being positive (this distance is usually called ``Rx``). In other words, is the horizontal distance to top edge of rupture measured perpendicular to the strike. Values on the hanging wall are positive, values on the footwall are negative. :param mesh: :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate Rx-distance to. :returns: Numpy array of distances in km. """ top_edge = self.mesh[0:1] dists = [] ia = 0 ib = top_edge.lons.shape[1] - 2 if (self.__class__.__name__ == 'KiteSurface'): idxs = numpy.nonzero(numpy.isfinite(top_edge.lons[0, :]))[0] ia = min(idxs) ib = sorted(idxs)[-2] if top_edge.lons.shape[1] < 3: i = 0 if ((self.__class__.__name__ == 'KiteSurface') and (numpy.isnan(top_edge.lons[0, i]) or numpy.isnan(top_edge.lons[0, i + 1]))): msg = 'Rx calculation. Top of rupture has less than two points' raise ValueError(msg) p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats)) else: for i in range(top_edge.lons.shape[1] - 1): if ((self.__class__.__name__ == 'KiteSurface') and (numpy.isnan(top_edge.lons[0, i]) or numpy.isnan(top_edge.lons[0, i + 1]))): continue p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == ia or i == ib: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment( numpy.array([p1.longitude, p2.longitude]), numpy.array([p1.latitude, p2.latitude]), mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, list(range(dists.shape[1]))] if numpy.any(numpy.isnan(dst)): raise ValueError('NaN in Rx') return dst
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] aac(dists, expected_dists, rtol=1E-5)
def _test1to7surface(self): corners = [Point(0, 0, 8), Point(-0.1, 0, 8), Point(-0.1, 0, 9), Point(0, 0, 9)] surface = PlanarSurface(270, 90, *corners) return surface
def test_point_outside(self): corners = [Point(0.1, -0.1, 1), Point(-0.1, -0.1, 1), Point(-0.1, 0.1, 2), Point(0.1, 0.1, 2)] surface = PlanarSurface(270, 45, *corners) sites = Mesh.from_points_list([ Point(-0.2, -0.2), Point(1, 1, 1), Point(4, 5), Point(0.8, 0.01), Point(0.2, -0.15), Point(0.02, -0.12), Point(-0.14, 0), Point(-3, 3), 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(0.8, 0.01).distance(Point(0.1, 0.01)), Point(0.2, -0.15).distance(Point(0.1, -0.1)), Point(0.02, -0.12).distance(Point(0.02, -0.1)), Point(-0.14, 0).distance(Point(-0.1, 0)), Point(-3, 3).distance(Point(-0.1, 0.1)), Point(0.05, 0.15).distance(Point(0.05, 0.1)) ] aac(dists, expected_dists, atol=0.5)
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)
class _BaseSeismicSourceTestCase(unittest.TestCase): POLYGON = Polygon( [Point(0, 0), Point(0, 0.001), Point(0.001, 0.001), Point(0.001, 0)]) SITES = [ Site(Point(0.0005, 0.0005, -0.5), 0.1, 3, 4), # inside, middle Site(Point(0.0015, 0.0005), 1, 3, 4), # outside, middle-east Site(Point(-0.0005, 0.0005), 2, 3, 4), # outside, middle-west Site(Point(0.0005, 0.0015), 3, 3, 4), # outside, north-middle Site(Point(0.0005, -0.0005), 4, 3, 4), # outside, south-middle Site(Point(0., 0.), 5, 3, 4), # south-west corner Site(Point(0., 0.001), 6, 3, 4), # north-west corner Site(Point(0.001, 0.001), 7, 3, 4), # north-east corner Site(Point(0.001, 0.), 8, 3, 4), # south-east corner Site(Point(0., -0.01), 9, 3, 4), # 1.1 km away Site(Point(0.3, 0.3), 10, 3, 4), # 47 km away Site(Point(0., -1), 11, 3, 4), # 111.2 km away ] def setUp(self): self.source_class = FakeSource mfd = EvenlyDiscretizedMFD(min_mag=3, bin_width=1, occurrence_rates=[5, 6, 7]) self.source = FakeSource('source_id', 'name', const.TRT.VOLCANIC, mfd=mfd, rupture_mesh_spacing=2, magnitude_scaling_relationship=PeerMSR(), rupture_aspect_ratio=1, temporal_occurrence_model=PoissonTOM(50.)) self.sitecol = SiteCollection(self.SITES)
def test_topo(self): surface = PlanarSurface(2, 3, *tdata.TEST_7_RUPTURE_9_CORNERS) sites = Mesh.from_points_list([Point(-0.3, 0.4, -8)]) self.assertAlmostEqual(55.6159556, surface.get_min_distance(sites)[0], delta=0.6)
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, True, 2, 3), openquake.hazardlib.site.Site(Point(10, 16), 2, True, 2, 3), openquake.hazardlib.site.Site(Point(10, 10.6), 3, True, 2, 3), openquake.hazardlib.site.Site(Point(10, 10.7), 4, True, 2, 3) ] sitecol = openquake.hazardlib.site.SiteCollection(sites) from openquake.hazardlib.gsim.sadigh_1997 import SadighEtAl1997 gsims = {const.TRT.ACTIVE_SHALLOW_CRUST: SadighEtAl1997()} truncation_level = 1 imts = {'PGA': [0.1, 0.5, 1.3]} from openquake.hazardlib.calc import filters source_site_filter = self.SitesCounterSourceSitesFilter( filters.SourceSitesFilter(30)) calc_hazard_curves(sources, sitecol, imts, gsims, truncation_level, source_site_filter=source_site_filter) # 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(source_site_filter.counts, [('point2', [1, 3, 4])])
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, 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, rupture_mesh_spacing=1.0, location=Point(10, 11) ), ] sites = [openquake.hazardlib.site.Site(Point(11, 10), 1, True, 2, 3), openquake.hazardlib.site.Site(Point(10, 16), 2, True, 2, 3), openquake.hazardlib.site.Site(Point(10, 10.6), 3, True, 2, 3), openquake.hazardlib.site.Site(Point(10, 10.7), 4, True, 2, 3)] sitecol = openquake.hazardlib.site.SiteCollection(sites) from openquake.hazardlib.gsim.sadigh_1997 import SadighEtAl1997 gsims = {const.TRT.ACTIVE_SHALLOW_CRUST: SadighEtAl1997()} truncation_level = 1 time_span = 1.0 imts = {openquake.hazardlib.imt.PGA(): [0.1, 0.5, 1.3]} from openquake.hazardlib.calc import filters source_site_filter = self.SitesCounterSourceFilter( filters.source_site_distance_filter(30) ) rupture_site_filter = self.SitesCounterRuptureFilter( filters.rupture_site_distance_filter(30) ) hazard_curves_poissonian( iter(sources), sitecol, imts, time_span, gsims, truncation_level, source_site_filter=source_site_filter, rupture_site_filter=rupture_site_filter ) # there are two sources and four sites. first source should # be filtered completely since it is too far from all the sites. # the second one should take only three sites -- all except (10, 16). # it generates three ruptures with magnitudes 4, 6 and 8, from which # the first one doesn't affect any of sites and should be ignored, # second only affects site (10, 10.7) and the last one affects all # three. self.assertEqual(source_site_filter.counts, [('point2', [1, 3, 4])]) self.assertEqual(rupture_site_filter.counts, [(6, [4]), (8, [1, 3, 4])])
def setUp(self): super(PointSourceRuptureFilterTestCase, self).setUp() self.hypocenter = Point(2, 0, 50) self.sitecol = SiteCollection(self.SITES)
class PointSourceRuptureFilterTestCase(unittest.TestCase): SITES = PointSourceSourceFilterTestCase.SITES def setUp(self): super(PointSourceRuptureFilterTestCase, self).setUp() self.hypocenter = Point(2, 0, 50) self.sitecol = SiteCollection(self.SITES) def _make_rupture(self, width, length, dip): mid_left = self.hypocenter.point_at(length / 2.0, 0, azimuth=270) mid_right = self.hypocenter.point_at(length / 2.0, 0, azimuth=90) hwidth = width * numpy.cos(numpy.radians(dip)) / 2.0 vwidth = width * numpy.sin(numpy.radians(dip)) / 2.0 top_left = mid_left.point_at(hwidth, -vwidth, azimuth=0) bottom_left = mid_left.point_at(hwidth, vwidth, azimuth=180) top_right = mid_right.point_at(hwidth, -vwidth, azimuth=0) bottom_right = mid_right.point_at(hwidth, vwidth, azimuth=180) surface = PlanarSurface(1, 2, dip, top_left, top_right, bottom_right, bottom_left) rupture = ParametricProbabilisticRupture( mag=1, rake=2, tectonic_region_type=TRT.VOLCANIC, hypocenter=self.hypocenter, surface=surface, source_typology=PointSource, occurrence_rate=3, temporal_occurrence_model=PoissonTOM(1)) return rupture def test_zero_integration_distance(self): rup = self._make_rupture(10, 15, 45) # the JB distances are [8.29156163, 5.05971598, 15.13297135, # 495.78630103, 496.89812309], so given that the integration # distance is 0 all sites are filtered out filtered = filters.filter_sites_by_distance_to_rupture( rup, integration_distance=0, sites=self.sitecol) self.assertIs(filtered, None) def test_495_km(self): rup = self._make_rupture(7, 10, 30) # the JB distance area [5.84700762, 6.8290327, 14.53519629, # 496.25926891, 497.37116174] so given that the integration # distance is 495 only the first 3 sites are kept filtered = filters.filter_sites_by_distance_to_rupture( rup, integration_distance=495, sites=self.sitecol) expected_filtered = SiteCollection(self.SITES[:3]) numpy.testing.assert_array_equal(filtered.indices, [0, 1, 2]) numpy.testing.assert_array_equal(filtered.vs30, expected_filtered.vs30) numpy.testing.assert_array_equal(filtered.vs30measured, expected_filtered.vs30measured) numpy.testing.assert_array_equal(filtered.z1pt0, expected_filtered.z1pt0) numpy.testing.assert_array_equal(filtered.z2pt5, expected_filtered.z2pt5) numpy.testing.assert_array_equal(filtered.mesh.lons, expected_filtered.mesh.lons) numpy.testing.assert_array_equal(filtered.mesh.lats, expected_filtered.mesh.lats) numpy.testing.assert_array_equal(filtered.mesh.depths, expected_filtered.mesh.depths) def test_filter_all_out(self): rup = self._make_rupture(50, 80, 9) # the JB distances are [47.0074159, 37.99716685, 40.7944923, # 476.2521365, 477.36015879] for int_dist in (0, 1, 10, 20, 37.99): filtered = filters.filter_sites_by_distance_to_rupture( rup, integration_distance=int_dist, sites=self.sitecol) self.assertIs(filtered, None)
class PointSourceSourceFilterTestCase(unittest.TestCase): SITES = [ Site(Point(2.0, 0.0), 0.1, True, 3, 4), # on epicenter Site(Point(2.1, 0.0), 1, True, 3, 4), # 11.1 km away Site(Point(2.0, -0.15), 2, True, 3, 4), # 16.7 km away Site(Point(2.0, 4.49), 3, True, 3, 4), # 499.3 km away Site(Point(2.0, -4.5), 4, True, 3, 4), # 500.3 km away ] def setUp(self): super(PointSourceSourceFilterTestCase, self).setUp() self.sitecol = SiteCollection(self.SITES) self.source1 = make_point_source( mfd=EvenlyDiscretizedMFD(min_mag=5, bin_width=1, occurrence_rates=[1]), rupture_aspect_ratio=1.9, upper_seismogenic_depth=0, lower_seismogenic_depth=18.5, magnitude_scaling_relationship=PeerMSR(), nodal_plane_distribution=PMF([ (0.5, NodalPlane(strike=1, dip=2, rake=3)), (0.5, NodalPlane(strike=1, dip=20, rake=3)), ]), location=Point(2.0, 0.0), ) self.source2 = make_point_source( mfd=EvenlyDiscretizedMFD(min_mag=6.5, bin_width=1, occurrence_rates=[1]), rupture_aspect_ratio=0.5, upper_seismogenic_depth=0, lower_seismogenic_depth=18.5, magnitude_scaling_relationship=PeerMSR(), nodal_plane_distribution=PMF([ (0.5, NodalPlane(strike=1, dip=10, rake=3)), (0.5, NodalPlane(strike=1, dip=20, rake=3)), ]), location=Point(2.0, 0.0), ) def test_zero_integration_distance(self): filtered = self.source1.filter_sites_by_distance_to_source( integration_distance=0, sites=self.sitecol) self.assertIsInstance(filtered, FilteredSiteCollection) self.assertIsNot(filtered, self.sitecol) numpy.testing.assert_array_equal(filtered.indices, [0]) numpy.testing.assert_array_equal(filtered.vs30, [0.1]) filtered = self.source2.filter_sites_by_distance_to_source( integration_distance=0, sites=self.sitecol) numpy.testing.assert_array_equal(filtered.indices, [0, 1]) def test_fifty_km(self): filtered = self.source1.filter_sites_by_distance_to_source( integration_distance=50, sites=self.sitecol) numpy.testing.assert_array_equal(filtered.indices, [0, 1, 2]) filtered = self.source2.filter_sites_by_distance_to_source( integration_distance=50, sites=self.sitecol) numpy.testing.assert_array_equal(filtered.indices, [0, 1, 2]) def test_495_km(self): filtered = self.source1.filter_sites_by_distance_to_source( integration_distance=495, sites=self.sitecol) numpy.testing.assert_array_equal(filtered.indices, [0, 1, 2]) filtered = self.source2.filter_sites_by_distance_to_source( integration_distance=495, sites=self.sitecol) self.assertIs(filtered, self.sitecol) # nothing filtered def test_filter_all_out(self): self.source1.location.latitude = 13.6 for int_dist in (0, 1, 10, 100, 1000): filtered = self.source1.filter_sites_by_distance_to_source( integration_distance=int_dist, sites=self.sitecol) self.assertIs(filtered, None)
def get_rx_distance(self, mesh): """ See :meth:`superclass method <.base.BaseSurface.get_rx_distance>` for spec of input and result values. The method extracts the top edge of the surface. For each point in mesh it computes the Rx distance to each segment the top edge is made of. The calculation is done by calling the function :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`. The final Rx distance matrix is then constructed by taking, for each point in mesh, the minimum Rx distance value computed. """ top_edge = self.get_mesh()[0:1] dists = [] if top_edge.lons.shape[1] < 3: i = 0 p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats ) ) else: for i in range(top_edge.lons.shape[1] - 1): p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == 0 or i == top_edge.lons.shape[1] - 2: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment([p1.longitude, p2.longitude], [p1.latitude, p2.latitude], mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, list(range(dists.shape[1]))] return dst
def setUp(self): """ Builds a simple dipping/bending fault source with a characteristic source model. Compares the curves for four sites, two on the hanging wall and two on the footwall. The source model is taken from the PEER Tests """ point_order_dipping_east = [ Point(-64.78365, -0.45236), Point(-64.80164, -0.45236), Point(-64.90498, -0.36564), Point(-65.0000, -0.16188), Point(-65.0000, 0.0000) ] trace_dip_east = Line(point_order_dipping_east) site_1 = Site(Point(-64.98651, -0.15738), 760.0, 48.0, 0.607, vs30measured=True) site_2 = Site(Point(-64.77466, -0.45686), 760.0, 48.0, 0.607, vs30measured=True) site_3 = Site(Point(-64.92747, -0.38363), 760.0, 48.0, 0.607, vs30measured=True) site_4 = Site(Point(-65.05396, -0.17088), 760.0, 48.0, 0.607, vs30measured=True) self.sites = SiteCollection([site_1, site_2, site_3, site_4]) self.imtls = { "PGA": [ 0.001, 0.01, 0.05, 0.1, 0.15, 0.2, 0.25, 0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.6, 0.7, 0.8, 0.9, 1.0 ] } fault_surface1 = SimpleFaultSurface.from_fault_data( trace_dip_east, 0.0, 12.0, 60., 0.5) mfd1 = EvenlyDiscretizedMFD(6.75, 0.01, [0.01]) tom = PoissonTOM(1.0) self.sources = [ CharacteristicFaultSource( "PEER_CHAR_FLT_EAST", "Peer Bending Fault Dipping East - Characteristic", "Active Shallow Crust", mfd1, tom, fault_surface1, 90.0) ] # We will check all the GMPEs self.gsim_set = { "ASK": [ NSHMP2014(gmpe_name='AbrahamsonEtAl2014', sgn=0), (0.185, NSHMP2014(gmpe_name='AbrahamsonEtAl2014', sgn=-1)), (0.63, AbrahamsonEtAl2014()), (0.185, NSHMP2014(gmpe_name='AbrahamsonEtAl2014', sgn=1)) ], "BSSA": [ NSHMP2014(gmpe_name='BooreEtAl2014', sgn=0), (0.185, NSHMP2014(gmpe_name='BooreEtAl2014', sgn=-1)), (0.63, BooreEtAl2014()), (0.185, NSHMP2014(gmpe_name='BooreEtAl2014', sgn=1)) ], "CB": [ NSHMP2014(gmpe_name='CampbellBozorgnia2014', sgn=0), (0.185, NSHMP2014(gmpe_name='CampbellBozorgnia2014', sgn=-1)), (0.63, CampbellBozorgnia2014()), (0.185, NSHMP2014(gmpe_name='CampbellBozorgnia2014', sgn=1)) ], "CY": [ NSHMP2014(gmpe_name='ChiouYoungs2014', sgn=0), (0.185, NSHMP2014(gmpe_name='ChiouYoungs2014', sgn=-1)), (0.63, ChiouYoungs2014()), (0.185, NSHMP2014(gmpe_name='ChiouYoungs2014', sgn=1)) ], "ID": [ NSHMP2014(gmpe_name='Idriss2014', sgn=0), (0.185, NSHMP2014(gmpe_name='Idriss2014', sgn=-1)), (0.63, Idriss2014()), (0.185, NSHMP2014(gmpe_name='Idriss2014', sgn=1)) ] }
class JB2009CorrelationMatrixTestCase(unittest.TestCase): SITECOL = SiteCollection([Site(Point(2, -40), 1, True, 1, 1), Site(Point(2, -40.1), 1, True, 1, 1), Site(Point(2, -40), 1, True, 1, 1), Site(Point(2, -39.9), 1, True, 1, 1)]) def test_no_clustering(self): cormo = JB2009CorrelationModel(vs30_clustering=False) imt = SA(period=0.1, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1, 0.03823366, 1, 0.03823366], [0.03823366, 1, 0.03823366, 0.00146181], [1, 0.03823366, 1, 0.03823366], [0.03823366, 0.00146181, 0.03823366, 1]]) imt = SA(period=0.95, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1, 0.26107857, 1, 0.26107857], [0.26107857, 1, 0.26107857, 0.06816202], [1, 0.26107857, 1, 0.26107857], [0.26107857, 0.06816202, 0.26107857, 1]]) def test_clustered(self): cormo = JB2009CorrelationModel(vs30_clustering=True) imt = SA(period=0.001, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1, 0.44046654, 1, 0.44046654], [0.44046654, 1, 0.44046654, 0.19401077], [1, 0.44046654, 1, 0.44046654], [0.44046654, 0.19401077, 0.44046654, 1]]) imt = SA(period=0.5, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1, 0.36612758, 1, 0.36612758], [0.36612758, 1, 0.36612758, 0.1340494], [1, 0.36612758, 1, 0.36612758], [0.36612758, 0.1340494, 0.36612758, 1]]) def test_period_one_and_above(self): cormo = JB2009CorrelationModel(vs30_clustering=False) cormo2 = JB2009CorrelationModel(vs30_clustering=True) imt = SA(period=1.0, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1, 0.2730787, 1, 0.2730787], [0.2730787, 1, 0.2730787, 0.07457198], [1, 0.2730787, 1, 0.2730787], [0.2730787, 0.07457198, 0.2730787, 1]]) corma2 = cormo2._get_correlation_matrix(self.SITECOL, imt) self.assertTrue((corma == corma2).all()) imt = SA(period=10.0, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1, 0.56813402, 1, 0.56813402], [0.56813402, 1, 0.56813402, 0.32277627], [1, 0.56813402, 1, 0.56813402], [0.56813402, 0.32277627, 0.56813402, 1]]) corma2 = cormo2._get_correlation_matrix(self.SITECOL, imt) self.assertTrue((corma == corma2).all()) def test_pga(self): sa = SA(period=1e-50, damping=5) pga = PGA() cormo = JB2009CorrelationModel(vs30_clustering=False) corma = cormo._get_correlation_matrix(self.SITECOL, sa) corma2 = cormo._get_correlation_matrix(self.SITECOL, pga) self.assertTrue((corma == corma2).all()) cormo = JB2009CorrelationModel(vs30_clustering=True) corma = cormo._get_correlation_matrix(self.SITECOL, sa) corma2 = cormo._get_correlation_matrix(self.SITECOL, pga) self.assertTrue((corma == corma2).all())
Generalized coordinate systems require an additional level of testing under a variety of fault conditions - we separate these out away from the main fault surface testing modules """ import os import unittest import numpy from openquake.hazardlib.geo.surface.multi import MultiSurface from openquake.hazardlib.geo import Mesh, Point, Line, PlanarSurface,\ SimpleFaultSurface from openquake.hazardlib.geo.surface.base import (downsample_mesh, downsample_trace) PNT1 = Point(-64.78365, -0.45236, 0.0) PNT2 = Point(-64.80164, -0.45236, 0.0) PNT3 = Point(-64.90498, -0.36564, 0.0) PNT4 = Point(-65.00000, -0.16188, 0.0) PNT5 = Point(-65.00000, 0.00000, 0.0) AS_ARRAY = numpy.array([[pnt.longitude, pnt.latitude, pnt.depth] for pnt in [PNT1, PNT2, PNT3, PNT4, PNT5]]) class CartesianTestingMultiSurface(MultiSurface): """ This test surface is used to verify the values given by Spudich & Chiou in their report. Here, the fault is built directly from the cartesian points so we over-ride the call to the function to render the coordinates to cartesian
def v2p(*vectors): # "vectors to points" return [Point(*coords) for coords in zip(*geo_utils.cartesian_to_spherical( numpy.array(vectors, dtype=float) ))]
def test_7_many_ruptures(self): source_id = name = 'test7-source' trt = TRT.VOLCANIC mag1 = 4.5 mag2 = 5.5 mag1_rate = 9e-3 mag2_rate = 9e-4 hypocenter1 = 9.0 hypocenter2 = 10.0 hypocenter1_weight = 0.8 hypocenter2_weight = 0.2 nodalplane1 = NodalPlane(strike=45, dip=90, rake=0) nodalplane2 = NodalPlane(strike=0, dip=45, rake=10) nodalplane1_weight = 0.3 nodalplane2_weight = 0.7 upper_seismogenic_depth = 2 lower_seismogenic_depth = 16 rupture_aspect_ratio = 2 rupture_mesh_spacing = 0.5 location = Point(0, 0) magnitude_scaling_relationship = PeerMSR() tom = PoissonTOM(time_span=50) mfd = EvenlyDiscretizedMFD(min_mag=mag1, bin_width=(mag2 - mag1), occurrence_rates=[mag1_rate, mag2_rate]) nodal_plane_distribution = PMF([(nodalplane1_weight, nodalplane1), (nodalplane2_weight, nodalplane2)]) hypocenter_distribution = PMF([(hypocenter1_weight, hypocenter1), (hypocenter2_weight, hypocenter2)]) point_source = PointSource( source_id, name, trt, mfd, rupture_mesh_spacing, magnitude_scaling_relationship, rupture_aspect_ratio, tom, upper_seismogenic_depth, lower_seismogenic_depth, location, nodal_plane_distribution, hypocenter_distribution) actual_ruptures = list(point_source.iter_ruptures()) self.assertEqual(len(actual_ruptures), point_source.count_ruptures()) expected_ruptures = { (mag1, nodalplane1.rake, hypocenter1): ( # probabilistic rupture's occurrence rate 9e-3 * 0.3 * 0.8, # rupture surface corners planar_surface_test_data.TEST_7_RUPTURE_1_CORNERS), (mag2, nodalplane1.rake, hypocenter1): (9e-4 * 0.3 * 0.8, planar_surface_test_data.TEST_7_RUPTURE_2_CORNERS), (mag1, nodalplane2.rake, hypocenter1): (9e-3 * 0.7 * 0.8, planar_surface_test_data.TEST_7_RUPTURE_3_CORNERS), (mag2, nodalplane2.rake, hypocenter1): (9e-4 * 0.7 * 0.8, planar_surface_test_data.TEST_7_RUPTURE_4_CORNERS), (mag1, nodalplane1.rake, hypocenter2): (9e-3 * 0.3 * 0.2, planar_surface_test_data.TEST_7_RUPTURE_5_CORNERS), (mag2, nodalplane1.rake, hypocenter2): (9e-4 * 0.3 * 0.2, planar_surface_test_data.TEST_7_RUPTURE_6_CORNERS), (mag1, nodalplane2.rake, hypocenter2): (9e-3 * 0.7 * 0.2, planar_surface_test_data.TEST_7_RUPTURE_7_CORNERS), (mag2, nodalplane2.rake, hypocenter2): (9e-4 * 0.7 * 0.2, planar_surface_test_data.TEST_7_RUPTURE_8_CORNERS) } for actual_rupture in actual_ruptures: expected_occurrence_rate, expected_corners = expected_ruptures[( actual_rupture.mag, actual_rupture.rake, actual_rupture.hypocenter.depth)] self.assertTrue( isinstance(actual_rupture, ParametricProbabilisticRupture)) self.assertAlmostEqual(actual_rupture.occurrence_rate, expected_occurrence_rate) self.assertIs(actual_rupture.temporal_occurrence_model, tom) self.assertEqual(actual_rupture.tectonic_region_type, trt) surface = actual_rupture.surface tl, tr, br, bl = expected_corners self.assertEqual(tl, surface.top_left) self.assertEqual(tr, surface.top_right) self.assertEqual(bl, surface.bottom_left) self.assertEqual(br, surface.bottom_right) # check avg_ruptures avg_ruptures = list(point_source.avg_ruptures()) self.assertEqual([pr.hypocenter.depth for pr in avg_ruptures], [9.2, 9.2]) # weighted mean between 9 and 10
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 aac(dists, expected_dists, rtol=1E-5)
def test_middle_point_single_surface(self): surf = MultiSurface([self.surfaces_mesh2D[0]]) middle_point = surf.get_middle_point() self.assertTrue(Point(0.1, 1.1, 1.1) == middle_point)
def test_bottom_edge_depth_differs(self): corners = [Point(0, -1, 0.3), Point(0, 1, 0.3), Point(0, 1, 0.5), Point(0, -1, 0.499999)] msg = 'top and bottom edges must be parallel to the earth surface' self.assert_failed_creation(0, 90, corners, ValueError, msg)
def get_middle_point(self): return Point(self.lons.flatten()[0], self.lats.flatten()[0], self.depths.flatten()[0])
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] aac(dists, expected_dists, rtol=1E-5)
def get_rx_distance(self, mesh): """ See :meth:`superclass method <.base.BaseSurface.get_rx_distance>` for spec of input and result values. The method extracts the top edge of the surface. For each point in mesh it computes the Rx distance to each segment the top edge is made of. The calculation is done by calling the function :func:`openquake.hazardlib.geo.geodetic.distance_to_arc`. The final Rx distance matrix is then constructed by taking, for each point in mesh, the minimum Rx distance value computed. """ top_edge = self.get_mesh()[0:1] dists = [] if top_edge.lons.shape[1] < 3: i = 0 p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats)) else: for i in range(top_edge.lons.shape[1] - 1): p1 = Point(top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i]) p2 = Point(top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1]) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == 0 or i == top_edge.lons.shape[1] - 2: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment( [p1.longitude, p2.longitude], [p1.latitude, p2.latitude], mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, range(dists.shape[1])] return dst
def test1_sites_within_fault_width(self): surface = self._test1to7surface() sites = Mesh.from_points_list([Point(-0.05, 0.05), Point(-0.05, -0.05)]) dists = surface.get_ry0_distance(sites) numpy.testing.assert_allclose(dists, numpy.array([0.0, 0.0]))
class PointSourceRuptureFilterTestCase(unittest.TestCase): SITES = PointSourceSourceFilterTestCase.SITES def setUp(self): super(PointSourceRuptureFilterTestCase, self).setUp() self.hypocenter = Point(2, 0, 50) self.sitecol = SiteCollection(self.SITES) def _make_rupture(self, width, length, dip): mid_left = self.hypocenter.point_at(length / 2.0, 0, azimuth=270) mid_right = self.hypocenter.point_at(length / 2.0, 0, azimuth=90) hwidth = width * numpy.cos(numpy.radians(dip)) / 2.0 vwidth = width * numpy.sin(numpy.radians(dip)) / 2.0 top_left = mid_left.point_at(hwidth, -vwidth, azimuth=0) bottom_left = mid_left.point_at(hwidth, vwidth, azimuth=180) top_right = mid_right.point_at(hwidth, -vwidth, azimuth=0) bottom_right = mid_right.point_at(hwidth, vwidth, azimuth=180) surface = PlanarSurface(1, 2, dip, top_left, top_right, bottom_right, bottom_left) rupture = ProbabilisticRupture( mag=1, rake=2, tectonic_region_type=TRT.VOLCANIC, hypocenter=self.hypocenter, surface=surface, source_typology=PointSource, occurrence_rate=3, temporal_occurrence_model=PoissonTOM(1) ) return rupture def test_zero_integration_distance(self): rup = self._make_rupture(10, 15, 45) # 8 km radius filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=0, sites=self.sitecol ) self.assertIsInstance(filtered, SiteCollection) self.assertIsNot(filtered, self.sitecol) numpy.testing.assert_array_equal(filtered.indices, [0]) numpy.testing.assert_array_equal(filtered.vs30, [0.1]) rup = self._make_rupture(50, 30, 90) # 14.8 km radius filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=0, sites=self.sitecol ) numpy.testing.assert_array_equal(filtered.indices, [0, 1]) def test_495_km(self): rup = self._make_rupture(5, 8, 5) # 4.68 km radius filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=495, sites=self.sitecol ) numpy.testing.assert_array_equal(filtered.indices, [0, 1, 2, 3]) rup = self._make_rupture(7, 10, 30) # 5.8 km radius filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=495, sites=self.sitecol ) self.assertIs(filtered.indices, None) self.assertIs(filtered, self.sitecol) def test_filter_all_out(self): rup = self._make_rupture(50, 80, 9) # 46.64 km radius self.hypocenter.longitude = 11.515 for int_dist in (0, 1, 10, 100, 1000): filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=int_dist, sites=self.sitecol ) self.assertIs(filtered, None)
def get_rx_distance(self, mesh): """ Compute distance between each point of mesh and surface's great circle arc. Distance is measured perpendicular to the rupture strike, from the surface projection of the updip edge of the rupture, with the down dip direction being positive (this distance is usually called ``Rx``). In other words, is the horizontal distance to top edge of rupture measured perpendicular to the strike. Values on the hanging wall are positive, values on the footwall are negative. :param mesh: :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate Rx-distance to. :returns: Numpy array of distances in km. """ top_edge = self.mesh[0:1] dists = [] if top_edge.lons.shape[1] < 3: i = 0 p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) azimuth = p1.azimuth(p2) dists.append( geodetic.distance_to_arc( p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats ) ) else: for i in range(top_edge.lons.shape[1] - 1): p1 = Point( top_edge.lons[0, i], top_edge.lats[0, i], top_edge.depths[0, i] ) p2 = Point( top_edge.lons[0, i + 1], top_edge.lats[0, i + 1], top_edge.depths[0, i + 1] ) # Swapping if i == 0: pt = p1 p1 = p2 p2 = pt # Computing azimuth and distance if i == 0 or i == top_edge.lons.shape[1] - 2: azimuth = p1.azimuth(p2) tmp = geodetic.distance_to_semi_arc(p1.longitude, p1.latitude, azimuth, mesh.lons, mesh.lats) else: tmp = geodetic.min_distance_to_segment( numpy.array([p1.longitude, p2.longitude]), numpy.array([p1.latitude, p2.latitude]), mesh.lons, mesh.lats) # Correcting the sign of the distance if i == 0: tmp *= -1 dists.append(tmp) # Computing distances dists = numpy.array(dists) iii = abs(dists).argmin(axis=0) dst = dists[iii, list(range(dists.shape[1]))] return dst
def _corners(array): # convert a composite array with fields lon, lat, depth into Points points = [] for p in array: points.append(Point(p['lon'], p['lat'], p['depth'])) return points
class PointSourceRuptureFilterTestCase(unittest.TestCase): SITES = PointSourceSourceFilterTestCase.SITES def setUp(self): super(PointSourceRuptureFilterTestCase, self).setUp() self.hypocenter = Point(2, 0, 50) self.sitecol = SiteCollection(self.SITES) def _make_rupture(self, width, length, dip): mid_left = self.hypocenter.point_at(length / 2.0, 0, azimuth=270) mid_right = self.hypocenter.point_at(length / 2.0, 0, azimuth=90) hwidth = width * numpy.cos(numpy.radians(dip)) / 2.0 vwidth = width * numpy.sin(numpy.radians(dip)) / 2.0 top_left = mid_left.point_at(hwidth, -vwidth, azimuth=0) bottom_left = mid_left.point_at(hwidth, vwidth, azimuth=180) top_right = mid_right.point_at(hwidth, -vwidth, azimuth=0) bottom_right = mid_right.point_at(hwidth, vwidth, azimuth=180) surface = PlanarSurface(1, 2, dip, top_left, top_right, bottom_right, bottom_left) rupture = ProbabilisticRupture( mag=1, rake=2, tectonic_region_type=TRT.VOLCANIC, hypocenter=self.hypocenter, surface=surface, source_typology=PointSource, occurrence_rate=3, temporal_occurrence_model=PoissonTOM(1) ) return rupture def test_zero_integration_distance(self): rup = self._make_rupture(10, 15, 45) # the JB distances are [8.29156163, 5.05971598, 15.13297135, # 495.78630103, 496.89812309], so given that the integration # distance is 0 all sites are filtered out filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=0, sites=self.sitecol ) self.assertIs(filtered, None) def test_495_km(self): rup = self._make_rupture(7, 10, 30) # the JB distance area [5.84700762, 6.8290327, 14.53519629, # 496.25926891, 497.37116174] so given that the integration # distance is 495 only the first 3 sites are kept filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=495, sites=self.sitecol ) expected_filtered = SiteCollection(self.SITES[:3]) numpy.testing.assert_array_equal(filtered.indices, [0, 1, 2]) numpy.testing.assert_array_equal( filtered.vs30, expected_filtered.vs30 ) numpy.testing.assert_array_equal( filtered.vs30measured, expected_filtered.vs30measured ) numpy.testing.assert_array_equal( filtered.z1pt0, expected_filtered.z1pt0 ) numpy.testing.assert_array_equal( filtered.z2pt5, expected_filtered.z2pt5 ) numpy.testing.assert_array_equal( filtered.mesh.lons, expected_filtered.mesh.lons ) numpy.testing.assert_array_equal( filtered.mesh.lats, expected_filtered.mesh.lats ) numpy.testing.assert_array_equal( filtered.mesh.depths, expected_filtered.mesh.depths ) def test_filter_all_out(self): rup = self._make_rupture(50, 80, 9) # the JB distances are [47.0074159, 37.99716685, 40.7944923, # 476.2521365, 477.36015879] for int_dist in (0, 1, 10, 20, 37.99): filtered = PointSource.filter_sites_by_distance_to_rupture( rup, integration_distance=int_dist, sites=self.sitecol ) self.assertIs(filtered, None)
def test_3(self): surface = PlanarSurface(2, 3, *tdata.TEST_7_RUPTURE_2_CORNERS) sites = Mesh.from_points_list([Point(0, 0)]) self.assertAlmostEqual(7.01186304977, surface.get_min_distance(sites)[0], places=2)
def test_edges_differ_in_length_within_tolerance(self): self.assert_successfull_creation( 2, 3, Point(0, -1, 1), Point(0, 1, 1), Point(0, 1.000001, 2), Point(0, -1, 2) )
class HM2018CorrelationMatrixTestCase(unittest.TestCase): SITECOL = SiteCollection([Site(Point(2, -40), 1, True, 1, 1), Site(Point(2, -40.1), 1, True, 1, 1), Site(Point(2, -40), 1, True, 1, 1), Site(Point(2, -39.9), 1, True, 1, 1)]) def test_correlation_no_uncertainty(self): cormo = HM2018CorrelationModel(uncertainty_multiplier=0) imt = SA(period=0.1, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL,imt) aaae(corma, [[1.0000000, 0.3981537, 1.0000000, 0.3981537,], [0.3981537, 1.0000000, 0.3981537, 0.2596809,], [1.0000000, 0.3981537, 1.0000000, 0.3981537,], [0.3981537, 0.2596809, 0.3981537, 1.0000000,]]) imt = SA(period=0.5, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1.0000000, 0.3809173, 1.0000000, 0.3809173,], [0.3809173, 1.0000000, 0.3809173, 0.2433886,], [1.0000000, 0.3809173, 1.0000000, 0.3809173,], [0.3809173, 0.2433886, 0.3809173, 1.0000000,]]) imt = SA(period=1, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1.0000000, 0.3906193, 1.0000000, 0.3906193,], [0.3906193, 1.0000000, 0.3906193, 0.2525181,], [1.0000000, 0.3906193, 1.0000000, 0.3906193,], [0.3906193, 0.2525181, 0.3906193, 1.0000000,]]) imt = SA(period=2, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1.0000000, 0.4011851, 1.0000000, 0.4011851,], [0.4011851, 1.0000000, 0.4011851, 0.2625807,], [1.0000000, 0.4011851, 1.0000000, 0.4011851,], [0.4011851, 0.2625807, 0.4011851, 1.0000000,]]) imt = SA(period=4, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1.0000000, 0.3522765, 1.0000000, 0.3522765,], [0.3522765, 1.0000000, 0.3522765, 0.2170695,], [1.0000000, 0.3522765, 1.0000000, 0.3522765,], [0.3522765, 0.2170695, 0.3522765, 1.0000000,]]) imt = SA(period=6, damping=5) corma = cormo._get_correlation_matrix(self.SITECOL, imt) aaae(corma, [[1.0000000, 0.3159779, 1.0000000, 0.3159779,], [0.3159779, 1.0000000, 0.3159779, 0.1851206,], [1.0000000, 0.3159779, 1.0000000, 0.3159779,], [0.3159779, 0.1851206, 0.3159779, 1.0000000,]]) def test_correlation_small_uncertainty(self): imt = SA(period=1.5, damping=5) cormo = HM2018CorrelationModel(uncertainty_multiplier=0) corma = cormo._get_correlation_matrix(self.SITECOL, imt) cormo2 = HM2018CorrelationModel(uncertainty_multiplier=1E-30) corma2 = cormo2._get_correlation_matrix(self.SITECOL, imt) self.assertTrue((corma == corma2).all()) def test_pga_no_uncertainty(self): sa = SA(period=1e-50, damping=5) pga = PGA() cormo = HM2018CorrelationModel(uncertainty_multiplier=0) corma = cormo._get_correlation_matrix(self.SITECOL, sa) corma2 = cormo._get_correlation_matrix(self.SITECOL, pga) self.assertTrue((corma == corma2).all()) def test_correlation_with_uncertainty(self): Nsim = 100000 cormo = HM2018CorrelationModel(uncertainty_multiplier=1) imt = SA(period=3, damping=5) corma_3d = numpy.zeros((len(self.SITECOL), len(self.SITECOL), Nsim)) # For each simulation, construct a new correlation matrix for isim in range(0, Nsim): corma_3d[0:, 0:, isim] = \ cormo._get_correlation_matrix(self.SITECOL, imt) # Mean and Coefficient of Variation (COV) of correlation matrix MEANcorMa = corma_3d.mean(2) COVcorma = numpy.divide(corma_3d.std(2), MEANcorMa) aaae(MEANcorMa,[[1.0000000, 0.3766436, 1.0000000, 0.3766436,], [0.3766436, 1.0000000, 0.3766436, 0.2534904,], [1.0000000, 0.3766436, 1.0000000, 0.3766436,], [0.3766436, 0.2534904, 0.3766436, 1.00000,]], 2) aaae(COVcorma,[[0.0000000, 0.4102512, 0.0000000, 0.4102512,], [0.4102512, 0.0000000, 0.4102512, 0.5636907,], [0.0000000, 0.4102512, 0.0000000, 0.4102512,], [0.4102512, 0.5636907, 0.4102512, 0.00000,]], 2)
def test_2(self): surface = PlanarSurface(2, 3, *tdata.TEST_7_RUPTURE_6_CORNERS) sites = Mesh.from_points_list([Point(-0.25, 0.25)]) self.assertAlmostEqual(40.1213468, surface.get_min_distance(sites)[0], places=1)