def _test(self, expected_rates, rate_tolerance, **kwargs): mfd = TruncatedGRMFD(**kwargs) actual_rates = mfd.get_annual_occurrence_rates() self.assertEqual(len(actual_rates), len(expected_rates)) for i, (mag, rate) in enumerate(actual_rates): expected_mag, expected_rate = expected_rates[i] self.assertAlmostEqual(mag, expected_mag, delta=1e-14) self.assertAlmostEqual(rate, expected_rate, delta=rate_tolerance) if i == 0: self.assertEqual((mag, mag + 2), mfd.get_min_max_mag())
def mergeinv(agr, bgr, magchar, mfdchar, mwdt): """ """ mmin = 6.0 mupp = min(magchar) # get dt mfd dtmfd = TruncatedGRMFD(6.0, mupp+mwdt, mwdt, agr, bgr) occ = dtmfd.get_annual_occurrence_rates() # madt = numpy.array([d[0] for d in occ]) ocdt = numpy.array([d[1] for d in occ]) # compute moment modt = sum(mag_to_mo(madt)*ocdt) return modt
def sliprate2GR_incremental(sliprate, fault_area, b_value, max_mag, min_mag=0.0, bin_width=0.1): """Converts a sliprate and b-value into a Gutenberg- Richter distribution, then converts this to an OpenQuake incremental MFD (to facilitate collapsing of rates with other MFDs) """ a_value, moment_rate = fault_slip_rate_GR_conversion.slip2GR( sliprate, fault_area, float(b_value), float(max_mag), M_min=min_mag) mfd = TruncatedGRMFD(min_mag, max_mag, bin_width, a_value, b_value) mags, rates = zip(*mfd.get_annual_occurrence_rates()) mags = np.array(mags) rates = np.array(rates) return mags, rates, moment_rate
def _get_mfds(srcs): """ Return sources' magnitude frequency distributions. """ mfds = {} tot_occur_rate = 0 for src in srcs: mfd = {} if isinstance(src.mfd, IncrementalMFD): mfd['min_mag'] = float(src.mfd.min_mag) mfd['bin_width'] = float(src.mfd.bin_width) mfd['occur_rates'] = map(float, src.mfd.occur_rates) elif isinstance(src.mfd, TGRMFD): bin_width = 0.1 mfd = TruncatedGRMFD( src.mfd.min_mag, src.mfd.max_mag, bin_width, src.mfd.a_val, src.mfd.b_val ) mags_rates = mfd.get_annual_occurrence_rates() mags = [m for m, _ in mags_rates] occur_rates = [r for _, r in mags_rates] mfd['min_mag'] = mags[0] mfd['bin_width'] = bin_width mfd['occur_rates'] = occur_rates else: raise ValueError( 'MFD %s not recognized' % src.mfd.__class__.__name__ ) tot_occur_rate += sum(mfd['occur_rates']) assert src.id not in mfds mfds[src.id] = mfd return mfds, tot_occur_rate
class TestCCumulativeInterpolation(unittest.TestCase): def setUp(self): min_mag = 6.5 max_mag = 7.0 bin_width = 0.1 a_val = 3.0 b_val = 1.0 self.mfd = TruncatedGRMFD(min_mag, max_mag, bin_width, a_val, b_val) self.ms = [] self.os = [] # # loading information for the original MFD for mag, occ in self.mfd.get_annual_occurrence_rates(): self.ms.append(mag) self.os.append(occ) self.os = np.array(self.os) def test_interpolate_01(self): """ Test calculation of exceedance rate for magnitude equal to bin limit """ exrate = interpolate_ccumul(self.mfd, 6.8) self.assertAlmostEqual(exrate, sum(self.os[-2:])) def test_interpolate_02(self): """ Test calculation of exceedance rate for a given magnitude """ exrate = interpolate_ccumul(self.mfd, 6.84) # rate computed by hand self.assertAlmostEqual(exrate, 4.5450608e-05) def test_interpolate_03(self): """ Test calculation of exceedance rate within the last bin """ exrate = interpolate_ccumul(self.mfd, 6.94) # rate computed by hand self.assertAlmostEqual(exrate, 1.285383e-05)
class StochasticEventSetTestCase(unittest.TestCase): def setUp(self): # time span of 10 million years self.time_span = 10e6 nodalplane = NodalPlane(strike=0.0, dip=90.0, rake=0.0) self.mfd = TruncatedGRMFD(a_val=3.5, b_val=1.0, min_mag=5.0, max_mag=6.5, bin_width=0.1) # area source of circular shape with radius of 100 km # centered at 0., 0. self.area1 = AreaSource( source_id='src_1', name='area source', tectonic_region_type='Active Shallow Crust', mfd=self.mfd, 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=Point(0., 0.).to_polygon(100.), area_discretization=9.0, rupture_mesh_spacing=1.0, temporal_occurrence_model=PoissonTOM(self.time_span)) # area source of circular shape with radius of 100 km # centered at 1., 1. self.area2 = AreaSource( source_id='src_1', name='area source', tectonic_region_type='Active Shallow Crust', mfd=self.mfd, 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=Point(5., 5.).to_polygon(100.), area_discretization=9.0, rupture_mesh_spacing=1.0, temporal_occurrence_model=PoissonTOM(self.time_span)) # non-parametric source self.np_src, _ = make_non_parametric_source() def _extract_rates(self, ses, time_span, bins): """ Extract annual rates of occurence from stochastic event set """ rates, _ = numpy.histogram([r.mag for r in ses], bins=bins) return rates / time_span def test_ses_generation_from_parametric_source(self): # generate stochastic event set (SES) from area source with given # magnitude frequency distribution (MFD). Check that the MFD as # obtained from the SES (by making an histogram of the magnitude values # and normalizing by the total duration of the event set) is # approximately equal to the original MFD. numpy.random.seed(123) ses = stochastic_event_set([self.area1]) rates = self._extract_rates(ses, time_span=self.time_span, bins=numpy.arange(5., 6.6, 0.1)) expect_rates = numpy.array( [r for m, r in self.mfd.get_annual_occurrence_rates()]) numpy.testing.assert_allclose(rates, expect_rates, rtol=0, atol=1e-4) def test_ses_generation_from_parametric_source_with_filtering(self): # generate stochastic event set (SES) from 2 area sources (area1, # area2). However, by including a single site co-located with the # area1 center, and with source site filtering of 100 km (exactly # the radius of area1), the second source (area2), which is centered # at 5., 5. (that is about 500 km from center of area1), will be # excluded. the MFD from the SES will be therefore approximately equal # to the one of area1 only. numpy.random.seed(123) sites = SiteCollection([ Site(location=Point(0., 0.), vs30=760, vs30measured=True, z1pt0=40., z2pt5=2.) ]) ses = stochastic_event_set([self.area1, self.area2], filters.SourceFilter( sites, filters.MagDepDistance.new('100'))) rates = self._extract_rates(ses, time_span=self.time_span, bins=numpy.arange(5., 6.6, 0.1)) expect_rates = numpy.array( [r for m, r in self.mfd.get_annual_occurrence_rates()]) numpy.testing.assert_allclose(rates, expect_rates, rtol=0, atol=1e-4) def test_ses_generation_from_non_parametric_source(self): # np_src contains two ruptures: rup1 (of magnitude 5) and rup2 (of # magnitude 6) # rup1 has probability of zero occurences of 0.7 and of one # occurrence of 0.3 # rup2 has probability of zero occurrence of 0.7, of one occurrence of # 0.2 and of two occurrences of 0.1 # the test generate multiple SESs. From the ensamble of SES the # probability of 0, 1, and 2, rupture occurrences is computed and # compared with the expected value numpy.random.seed(123) num_sess = 10000 sess = [stochastic_event_set([self.np_src]) for i in range(num_sess)] # loop over ses. For each ses count number of rupture # occurrences (for each magnitude) n_rups1 = {} n_rups2 = {} for i, ses in enumerate(sess): n_rups1[i] = 0 n_rups2[i] = 0 for rup in ses: if rup.mag == 5.: n_rups1[i] += 1 elif rup.mag == 6.: n_rups2[i] += 1 # count how many SESs have 0,1 or 2 occurrences, and then normalize # by the total number of SESs generated. This gives the probability # of having 0, 1 or 2 occurrences n_occs1 = numpy.fromiter(n_rups1.values(), int) n_occs2 = numpy.fromiter(n_rups2.values(), int) p_occs1_0 = (n_occs1 == 0).sum() / num_sess p_occs1_1 = (n_occs1 == 1).sum() / num_sess p_occs2_0 = (n_occs2 == 0).sum() / num_sess p_occs2_1 = (n_occs2 == 1).sum() / num_sess p_occs2_2 = (n_occs2 == 2).sum() / num_sess self.assertAlmostEqual(p_occs1_0, 0.70, places=2) self.assertAlmostEqual(p_occs1_1, 0.30, places=2) self.assertAlmostEqual(p_occs2_0, 0.70, places=2) self.assertAlmostEqual(p_occs2_1, 0.20, places=2) self.assertAlmostEqual(p_occs2_2, 0.10, places=2)
class StochasticEventSetTestCase(unittest.TestCase): def setUp(self): # time span of 10 million years self.time_span = 10e6 nodalplane = NodalPlane(strike=0.0, dip=90.0, rake=0.0) self.mfd = TruncatedGRMFD(a_val=3.5, b_val=1.0, min_mag=5.0, max_mag=6.5, bin_width=0.1) # area source of circular shape with radius of 100 km # centered at 0., 0. self.area1 = AreaSource( source_id='src_1', name='area source', tectonic_region_type='Active Shallow Crust', mfd=self.mfd, 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=Point(0., 0.).to_polygon(100.), area_discretization=9.0, rupture_mesh_spacing=1.0, temporal_occurrence_model=PoissonTOM(self.time_span) ) # area source of circular shape with radius of 100 km # centered at 1., 1. self.area2 = AreaSource( source_id='src_1', name='area source', tectonic_region_type='Active Shallow Crust', mfd=self.mfd, 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=Point(5., 5.).to_polygon(100.), area_discretization=9.0, rupture_mesh_spacing=1.0, temporal_occurrence_model=PoissonTOM(self.time_span) ) # non-parametric source self.np_src, _ = make_non_parametric_source() def _extract_rates(self, ses, time_span, bins): """ Extract annual rates of occurence from stochastic event set """ mags = [] for r in ses: mags.append(r.mag) rates, _ = numpy.histogram(mags, bins=bins) rates = rates / time_span return rates def test_ses_generation_from_parametric_source(self): # generate stochastic event set (SES) from area source with given # magnitude frequency distribution (MFD). Check that the MFD as # obtained from the SES (by making an histogram of the magnitude values # and normalizing by the total duration of the event set) is # approximately equal to the original MFD. numpy.random.seed(123) ses = stochastic_event_set([self.area1]) rates = self._extract_rates(ses, time_span=self.time_span, bins=numpy.arange(5., 6.6, 0.1)) expect_rates = numpy.array( [r for m, r in self.mfd.get_annual_occurrence_rates()] ) numpy.testing.assert_allclose(rates, expect_rates, rtol=0, atol=1e-4) def test_ses_generation_from_parametric_source_with_filtering(self): # generate stochastic event set (SES) from 2 area sources (area1, # area2). However, by including a single site co-located with the # area1 center, and with source site filtering of 100 km (exactly # the radius of area1), the second source (area2), which is centered # at 5., 5. (that is about 500 km from center of area1), will be # excluded. the MFD from the SES will be therefore approximately equal # to the one of area1 only. numpy.random.seed(123) sites = SiteCollection([ Site( location=Point(0., 0.), vs30=760, vs30measured=True, z1pt0=40., z2pt5=2. ) ]) ses = stochastic_event_set( [self.area1, self.area2], sites=sites, source_site_filter=filters.SourceFilter(sites, 100.) ) rates = self._extract_rates(ses, time_span=self.time_span, bins=numpy.arange(5., 6.6, 0.1)) expect_rates = numpy.array( [r for m, r in self.mfd.get_annual_occurrence_rates()] ) numpy.testing.assert_allclose(rates, expect_rates, rtol=0, atol=1e-4) def test_ses_generation_from_non_parametric_source(self): # np_src contains two ruptures: rup1 (of magnitude 5) and rup2 (of # magnitude 6) # rup1 has probability of zero occurences of 0.7 and of one # occurrence of 0.3 # rup2 has probability of zero occurrence of 0.7, of one occurrence of # 0.2 and of two occurrences of 0.1 # the test generate multiple SESs. From the ensamble of SES the # probability of 0, 1, and 2, rupture occurrences is computed and # compared with the expected value numpy.random.seed(123) num_sess = 10000 sess = [stochastic_event_set([self.np_src]) for i in range(num_sess)] # loop over ses. For each ses count number of rupture # occurrences (for each magnitude) n_rups1 = {} n_rups2 = {} for i, ses in enumerate(sess): n_rups1[i] = 0 n_rups2[i] = 0 for rup in ses: if rup.mag == 5.: n_rups1[i] += 1 if rup.mag == 6.: n_rups2[i] += 1 # count how many SESs have 0,1 or 2 occurrences, and then normalize # by the total number of SESs generated. This gives the probability # of having 0, 1 or 2 occurrences n_occs1 = numpy.array(list(n_rups1.values())) n_occs2 = numpy.array(list(n_rups2.values())) p_occs1_0 = float(len(n_occs1[n_occs1 == 0])) / num_sess p_occs1_1 = float(len(n_occs1[n_occs1 == 1])) / num_sess p_occs2_0 = float(len(n_occs2[n_occs2 == 0])) / num_sess p_occs2_1 = float(len(n_occs2[n_occs2 == 1])) / num_sess p_occs2_2 = float(len(n_occs2[n_occs2 == 2])) / num_sess self.assertAlmostEqual(p_occs1_0, 0.7, places=2) self.assertAlmostEqual(p_occs1_1, 0.3, places=2) self.assertAlmostEqual(p_occs2_0, 0.7, places=2) self.assertAlmostEqual(p_occs2_1, 0.2, places=2) self.assertAlmostEqual(p_occs2_2, 0.1, places=2)