def test_sample_number_of_occurrences(self): time_span = 40 rate = 0.05 num_samples = 8000 tom = PoissonTOM(time_span) numpy.random.seed(31) mean = sum(tom.sample_number_of_occurrences(rate) for i in xrange(num_samples)) / float(num_samples) self.assertAlmostEqual(mean, rate * time_span, delta=1e-3)
def test_get_probability_one_or_more_occurrences(self): pdf = PoissonTOM(time_span=50) self.assertEqual(pdf.get_probability_one_or_more_occurrences(10), 1) aae = self.assertAlmostEqual aae(pdf.get_probability_one_or_more_occurrences(0.1), 0.9932621) aae(pdf.get_probability_one_or_more_occurrences(0.01), 0.39346934) pdf = PoissonTOM(time_span=5) self.assertEqual(pdf.get_probability_one_or_more_occurrences(8), 1) aae = self.assertAlmostEqual aae(pdf.get_probability_one_or_more_occurrences(0.1), 0.3934693) aae(pdf.get_probability_one_or_more_occurrences(0.01), 0.0487706)
def test_implied_point_sources(self): source = self.make_area_source(Polygon( [Point(-2, -2), Point(0, -2), Point(0, 0), Point(-2, 0)]), discretization=66.7, rupture_mesh_spacing=5) ruptures = list(source.iter_ruptures(PoissonTOM(50))) self.assertEqual(len(ruptures), 9 * 2) # resulting 3x3 mesh has points in these coordinates: lons = [-1.4, -0.8, -0.2] lats = [-0.6, -1.2, -1.8] ruptures_iter = iter(ruptures) for lat in lats: for lon in lons: r1 = next(ruptures_iter) r2 = next(ruptures_iter) for rupture in [r1, r2]: self.assertAlmostEqual(rupture.hypocenter.longitude, lon, delta=1e-3) self.assertAlmostEqual(rupture.hypocenter.latitude, lat, delta=1e-3) self.assertEqual(rupture.surface.mesh_spacing, 5) self.assertIs(rupture.source_typology, AreaSource) self.assertEqual(r1.mag, 5.5) self.assertEqual(r2.mag, 6.5) self.assertEqual(len(ruptures), 9 * 2)
def stochastic_event_set_poissonian(sources, time_span): """ The Poissonian Stochastic Event Set calculator generates a 'Stochastic Event Set' (that is a collection of earthquake ruptures) by randomly sampling a source model whose rupture follow a Poissonian temporal occurrence model. The Stochastic Event Set represent a possible *realization* of the seismicity as described by the source model, in the given time span. The calculator assumes :class:`Poissonian <nhlib.tom.PoissonTOM>` temporal occurrence model. :param sources: An iterator of seismic sources objects (instances of subclasses of :class:`~nhlib.source.base.SeismicSource`). :param time_span: An investigation period for Poissonian temporal occurrence model, floating point number in years. :returns: Generator of :class:`~nhlib.source.rupture.Rupture` objects that are contained in an event set. Some ruptures can be missing from it, others can appear one or more times in a row. """ tom = PoissonTOM(time_span) for source in sources: for rupture in source.iter_ruptures(tom): for i in xrange(rupture.sample_number_of_occurrences()): yield rupture
def test_get_probability(self): pdf = PoissonTOM(time_span=50) self.assertEqual(pdf.get_probability(occurrence_rate=10), 1) aae = self.assertAlmostEqual aae(pdf.get_probability(occurrence_rate=0.1), 0.9932621) aae(pdf.get_probability(occurrence_rate=0.01), 0.39346934) pdf = PoissonTOM(time_span=5) self.assertEqual(pdf.get_probability(occurrence_rate=8), 1) aae = self.assertAlmostEqual aae(pdf.get_probability(occurrence_rate=0.1), 0.3934693) aae(pdf.get_probability(occurrence_rate=0.01), 0.0487706)
def test_sample_number_of_occurrences(self): time_span = 20 rate = 0.01 num_samples = 2000 tom = PoissonTOM(time_span) rupture = make_rupture(ProbabilisticRupture, occurrence_rate=rate, temporal_occurrence_model=tom) numpy.random.seed(37) mean = sum(rupture.sample_number_of_occurrences() for i in xrange(num_samples)) / float(num_samples) self.assertAlmostEqual(mean, rate * time_span, delta=2e-3)
def test_occurrence_rate_rescaling(self): mfd = EvenlyDiscretizedMFD(min_mag=4, bin_width=1, occurrence_rates=[3]) polygon = Polygon([ Point(0, 0), Point(0, -0.2248), Point(-0.2248, -0.2248), Point(-0.2248, 0) ]) source = self.make_area_source(polygon, discretization=10, mfd=mfd) self.assertIs(source.mfd, mfd) ruptures = list(source.iter_ruptures(PoissonTOM(1))) self.assertEqual(len(ruptures), 4) for rupture in ruptures: self.assertNotEqual(rupture.occurrence_rate, 3) self.assertEqual(rupture.occurrence_rate, 3.0 / 4.0)
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 _get_rupture(self, min_mag, max_mag, hypocenter_depth, aspect_ratio, dip, rupture_mesh_spacing, upper_seismogenic_depth=2, lower_seismogenic_depth=16): source_id = name = 'test-source' trt = TRT.ACTIVE_SHALLOW_CRUST mfd = TruncatedGRMFD(a_val=2, b_val=1, min_mag=min_mag, max_mag=max_mag, bin_width=1) location = Point(0, 0) nodal_plane = NodalPlane(strike=45, dip=dip, rake=-123.23) nodal_plane_distribution = PMF([(1, nodal_plane)]) hypocenter_distribution = PMF([(1, hypocenter_depth)]) magnitude_scaling_relationship = PeerMSR() rupture_aspect_ratio = aspect_ratio point_source = PointSource( source_id, name, trt, mfd, rupture_mesh_spacing, magnitude_scaling_relationship, rupture_aspect_ratio, upper_seismogenic_depth, lower_seismogenic_depth, location, nodal_plane_distribution, hypocenter_distribution) tom = PoissonTOM(time_span=50) ruptures = list(point_source.iter_ruptures(tom)) self.assertEqual(len(ruptures), 1) [rupture] = ruptures self.assertIs(rupture.temporal_occurrence_model, tom) self.assertIs(rupture.tectonic_region_type, trt) self.assertEqual(rupture.rake, nodal_plane.rake) self.assertIsInstance(rupture.surface, PlanarSurface) self.assertEqual(rupture.surface.mesh_spacing, rupture_mesh_spacing) return rupture
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 = Decimal('0.8') hypocenter2_weight = Decimal('0.2') nodalplane1 = NodalPlane(strike=45, dip=90, rake=0) nodalplane2 = NodalPlane(strike=0, dip=45, rake=10) nodalplane1_weight = Decimal('0.3') nodalplane2_weight = Decimal('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, upper_seismogenic_depth, lower_seismogenic_depth, location, nodal_plane_distribution, hypocenter_distribution) actual_ruptures = list(point_source.iter_ruptures(tom)) self.assertEqual(len(actual_ruptures), 8) 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, ProbabilisticRupture)) self.assertEqual(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)
def test_areasource(self): nodalplane = NodalPlane(strike=0.0, dip=90.0, rake=0.0) src = AreaSource(source_id='src_1', name='area source', tectonic_region_type='Active Shallow Crust', mfd=TruncatedGRMFD(a_val=3.5, b_val=1.0, min_mag=5.0, max_mag=6.5, bin_width=0.1), nodal_plane_distribution=PMF([(1.0, nodalplane)]), hypocenter_distribution=PMF([(1.0, 5.0)]), upper_seismogenic_depth=0.0, lower_seismogenic_depth=10.0, magnitude_scaling_relationship=WC1994(), rupture_aspect_ratio=1.0, polygon=Polygon([ Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5), Point(0.5, -0.5) ]), area_discretization=9.0, rupture_mesh_spacing=1.0) site = Site(location=Point(0.0, 0.0), vs30=800.0, vs30measured=True, z1pt0=500.0, z2pt5=2.0) gsims = {'Active Shallow Crust': BooreAtkinson2008()} imt = SA(period=0.1, damping=5.0) iml = 0.2 time_span = 50.0 truncation_level = 3.0 tom = PoissonTOM(time_span) n_epsilons = 3 mag_bin_width = 0.2 # in km dist_bin_width = 10.0 # in decimal degree coord_bin_width = 0.2 # compute disaggregation bin_edges, diss_matrix = disagg.disaggregation( [src], site, imt, iml, gsims, tom, truncation_level, n_epsilons, mag_bin_width, dist_bin_width, coord_bin_width) mag_bins, dist_bins, lon_bins, lat_bins, eps_bins, trt_bins = bin_edges numpy.testing.assert_almost_equal( mag_bins, [5., 5.2, 5.4, 5.6, 5.8, 6., 6.2, 6.4, 6.6]) numpy.testing.assert_almost_equal( dist_bins, [0., 10., 20., 30., 40., 50., 60., 70., 80.]) numpy.testing.assert_almost_equal( lat_bins, [-0.6, -0.4, -0.2, 0., 0.2, 0.4, 0.6]) numpy.testing.assert_almost_equal( lon_bins, [-0.6, -0.4, -0.2, 0., 0.2, 0.4, 0.6]) numpy.testing.assert_almost_equal(eps_bins, [-3., -1., 1., 3.]) self.assertEqual(trt_bins, ['Active Shallow Crust']) expected_matrix = numpy.fromstring("""\ eJzt3Hk01dseAHAnY+EeosI1FIpKmcPF2ZmJDKVMGSLDNVNuhWQKJc4pykuajIlSNB3F5Sqa3HIb ZeqkulEpXnlK5b7VOv3c1X7DzXHOy1vfzz/W+rL2/p7f/n73dn7HDxcXGE/JKwqeLFTzRnH09leM 4RLUsa7pp6kZ6ejz91XL3TWjURLq+hSPQf9prPHUH3bIpLp7F5YPABOR/rF0u5k1W5D70Q0f7G/S iHrOSeiLS3vhyvH+mtHok9WUT0Jrc0pEKH4BxLwXa1IWMcTWcjwfAAAAAAAAAAAAAAAAAGA8bbA8 05jf741USD279t04iGQjB1ZRfROI+96CfVXDgtxJzHgEx+6HJ/FoHJOuzcLyAWAi2vyx+iTdhIoM EqfFpCzLIur5SuyhF3H9ERyv84Gf51nvtQhHC8qCBJ0kthHzjizdtLj0cDRK2cirVOgXD30HAAAA AAAAAAAAAAAAYEKqv7BXVsPcA7UbnLfOmJSDnBSyJaoGo4j73oopnalR2vHMuC/H7oeXiaUvOdJK xfIBYCIyjlGwXFO/A6mo0Ds9140+z+ij3Cn3+tdYlCAVtoxvI+c+b3KZLX8svACft+2Bz7D18QSO 5wPAX9FM8qrIOTgPPdj+LPhs5HKiPrve99rSt9qgxp7JduTjYUR8unzddSWKEdvOr/xUix8XnRDF 8tEhR9rUXaNg836wkZY+SJLEfh4AAAAAAAAAAAAAADD+rk4TDjFc64aErlnN3i+eiaS1K7oS6EHE fbm7l5oUBHQ3MuNuHLtf19E72FLBSMXyAWAi8tGR62423IFSFcvVz7QnEvX8s1Hr4b+Fbka3/Rv8 Z11dx7E6T9ROSVLLisPmLdtf0fu2IoHj+YCJxd5jqkhlXgdljXavu9d2y/95ncQvOUmW3+aHwvr6 b74p2UDk0yu35YfWHGfsHKHydrdbxFDQ70rL+FtHfMY9f4rDjYwBDy+kz8getukLJ8YXWiBh5WZq iZ2n+l1xcqsi57LtnM0nPRaM4DfB8rlOo2eXr1VE38o6AgAAAAAAAAAAAAAwnna4nbSYdMIZSRdk 5lYMJyKBwbhcsc2rkZKrhrLVlrsU/SLXekPfSMT/Ke7Asftjp4wlyBTuBCKfz3HhhtupB+ghHM8H AFYMP67reqqTiYQiav33UaKJuqXl2dspr4lFgp/igRyr53KFLMUPSjHYvDwaIV4mJmFY3wHwZ4a3 K3fWGZhidaKZ9EItKFuNbfvzbhGfoFkH5JGYH3fYkWEKMb7bSOsrG1Iwc97R/9Pr6LBHx+ORF5Zn uB4tZabgSrbVec60O14CqgFYf6GI6EgZewfs+kgFppeWetuyLZ/gaO85VFs3LB/B42T+YtEl0O/f mLeM+7Wl1ZJYnejL0zaOzBfA6n+8DM0nF94akma5f+/WCKf6xsoy87Qd8zjNihHn9Oexng+7kUo2 tkmFv6ewa10AAAAAAAAAAAAwdo7KlYFD4sbofGDcb5Q3/siJq1zhkbg5mrldVKTfyoYZX8+Mr+TY +3rbZ466df74vG6LLoTR7voSeXIqHwBYcfpVmVtqRAJqellol5ISQNTtXMuOzIfOSSiEK0dFJpdz zzluOqrZKm0Yw+wjP2JePReNxZ1cQRzvdzCxPFlpc4FGR9g+/N41JXi3oB3b6qfR+e7k15MskEQt 9WZwmx0xfk3A62AXy0D0RKTqH0YFo89ziVpWfhwUCUQxv9btcvb0JuJzZMxDnPis0cIttN9P5439 uSfzbbvcubnUUHxMk6dohiYxTiGPNf+pWA/sOvB+9/yqTrs7elZDr393w3H0ubCoJvliJzOW8/l3 zEiKDB6qFzLiqpcq++fXz/EiSfV2L77l0O/fmMgPzzXulCxGOl37YpSHXIl1OZnx7sf6Ul10Na9M Ep10Gff1qpJKlr5xXwub92sN7JjaS1E3x+rtayUVLLxJpuqzXJ806RSPtqVa2L7xtYqa0lybpF5T vuz3MIl2N9M9JujES7r5UtLo/nP/lzOFs6nqWL/H79HiVnvBx+x3Xeg7AAAAAAAAAACAjYo16pRi HQ1RcfP8vf58oaghurGG1GmNLlzeqVwbb4mk8ooDTJZEIr/QzSiDh/1/f5tTJeZr+5CMfE/7GGVG +aLAA98flJQyRfaPHmcY75NCaYnCk3QNRvNkdz4AjAfdhhbNhYz16FKZt2zm3z2Iun0csiBqxDEe TW13tE14soZj9RximlyuURqBaq3muUddcibmLZHZtT5oKALNEO4/JvzeCfoL/EunlFYJRLXaYvvw 0Sq1FodZ9mzbnyP5lnI/DViOjd8wXeiOYrcXEi47++L1jdFzqovWpnRg2Ber840Hwkm3yBbE+TLW fHrCDLY+rVqCjbO/SLHF3sGKmac+Eff3ezO37zmep2ZHVFH3SlWkkMbg8SlXHvfrZhC+JXdQzBk7 x/dcTd/kaufB3H8cod85TEN70/1ny2WxOrHr9f9eVtUYW5d7Wpe/402zR9VCedPrA0ef19Oy4k3L b5jMcv2U5v4ywqNszfL+f44kVJ8fYspyXdmuODRlFTLC+uVr6SVGeVovMmV5HPMjW1Sfi8zF1muu OI936gUrbJ9JVGXcml/pgJ37Wbz6Ax1G+LoDzhgprkmlTeLB+kVOcu/p3q5BypfxIP/+cONbDRSf kLKfDpJVx7xeQSdCjtq+/EBh9dx5WtCWWtjJz3L9IDPujnA5BvZ6v3qcIg8ZMWF+lvefE7oCHmc6 P6/L6OfCvHOGsvSv3aN8GSe7qK1wqvzI8vUEAAAAAAAA/P9bdpfPPs9dFSV16KnXm6xAz6IHKv32 aCKXgadOrQVayPTancuHHnui1WeDhKT8DNn+/uJculeoX5kkNm9DRkaR2mleZp5mzDwV4P0OmBAy rLVkS9f6ohLJCs+6zaPPdxxXTpIIcAtG1PnZ7XpzOPf/na7w91g9d/Jk9pEJMW8+Sfy233QvLA7A n3m+X/hbYp8BcV58jrfHuvHLhZmx7bzwUuG7o1VgjY1/MTzjdKCCBZZP1eohgRnGZlh8x/nlcgLC Rlj8a7Xk3PMRcjDGxtkpypiySVEXO6fobXYqQTraWLxOwHx/i4g62861Kc8vOza6OWB9/WxKevSm RtavAxibnbSH8bX+0ti61yadMihL0MfWKy509zv/ADxenWyar3d2Gsv1Qw8xzNu61IDl/s22D3WZ oY5YPkcYmjdq6M0aLNfnslnNO3db/MDy67o04+F1cq483r9Uq25u48XY661w3KZ/Od0Iix8a5LlF dZGB32PZTMFz7ZOwbSJ/uX50ll2J5FUUxNalx8w6RvvMWwqrddjTa5fcki7HsfdT/w2lsy9ffFD8 m9n/LZN5Yl8lyWDXpzn+QfuH1zOwPjrrWX1RO3kK9vMS9omuUw+LfjOvCwAAAAAAgLH4A6tzO/E=\ """.decode('base64').decode('zip')).reshape((8, 8, 6, 6, 3, 1)) numpy.testing.assert_almost_equal(diss_matrix, expected_matrix)
def test_get_probability_one_occurrence(self): pdf = PoissonTOM(time_span=30) aae = self.assertAlmostEqual aae(pdf.get_probability_one_occurrence(10), 0) aae(pdf.get_probability_one_occurrence(0.1), 0.1493612) aae(pdf.get_probability_one_occurrence(0.01), 0.2222455)
def test_get_probability_one_occurrence(self): rupture = make_rupture(ProbabilisticRupture, occurrence_rate=0.4, temporal_occurrence_model=PoissonTOM(10)) self.assertAlmostEqual(rupture.get_probability_one_occurrence(), 0.0732626)
def test_probabilistic_rupture_zero_occurrence_rate(self): self.assert_failed_creation(ProbabilisticRupture, ValueError, 'occurrence rate must be positive', occurrence_rate=0, temporal_occurrence_model=PoissonTOM(10))
def hazard_curves_poissonian( sources, sites, imts, time_span, gsims, truncation_level, source_site_filter=filters.source_site_noop_filter, rupture_site_filter=filters.rupture_site_noop_filter): """ Compute hazard curves on a list of sites, given a set of seismic sources and a set of ground shaking intensity models (one per tectonic region type considered in the seismic sources). The calculator assumes :class:`Poissonian <nhlib.tom.PoissonTOM>` temporal occurrence model. The calculator computes probability of ground motion exceedance according to the equation as described in pag. 419 of "OpenSHA: A Developing Community-modeling Environment for Seismic Hazard Analysis, Edward H. Field, Thomas H. Jordan and C. Allin Cornell. Seismological Research Letters July/August 2003 v. 74 no. 4 p. 406-419". :param sources: An iterator of seismic sources objects (instances of subclasses of :class:`~nhlib.source.base.SeismicSource`). :param sites: Instance of :class:`~nhlib.site.SiteCollection` object, representing sites of interest. :param imts: Dictionary mapping intensity measure type objects (see :mod:`nhlib.imt`) to lists of intensity measure levels. :param time_span: An investigation period for Poissonian temporal occurrence model, floating point number in years. :param gsims: Dictionary mapping tectonic region types (members of :class:`nhlib.const.TRT`) to :class:`~nhlib.gsim.base.GMPE` or :class:`~nhlib.gsim.base.IPE` objects. :param trunctation_level: Float, number of standard deviations for truncation of the intensity distribution. :param source_site_filter: Optional source-site filter function. See :mod:`nhlib.calc.filters`. :param rupture_site_filter: Optional rupture-site filter function. See :mod:`nhlib.calc.filters`. :returns: Dictionary mapping intensity measure type objects (same keys as in parameter ``imts``) to 2d numpy arrays of float, where first dimension differentiates sites (the order and length are the same as in ``sites`` parameter) and the second one differentiates IMLs (the order and length are the same as corresponding value in ``imts`` dict). """ curves = dict( (imt, numpy.ones([len(sites), len(imts[imt])])) for imt in imts) tom = PoissonTOM(time_span) total_sites = len(sites) sources_sites = ((source, sites) for source in sources) for source, s_sites in source_site_filter(sources_sites): ruptures_sites = ((rupture, s_sites) for rupture in source.iter_ruptures(tom)) for rupture, r_sites in rupture_site_filter(ruptures_sites): prob = rupture.get_probability_one_or_more_occurrences() gsim = gsims[rupture.tectonic_region_type] sctx, rctx, dctx = gsim.make_contexts(r_sites, rupture) for imt in imts: poes = gsim.get_poes(sctx, rctx, dctx, imt, imts[imt], truncation_level) curves[imt] *= r_sites.expand((1 - prob)**poes, total_sites, placeholder=1) for imt in imts: curves[imt] = 1 - curves[imt] return curves