예제 #1
0
    def __init__(self, min_mag: float, max_mag: float, corner_mag: float,
                 bin_width: float, a_val: float, b_val: float):

        self.min_mag = min_mag
        self.max_mag = max_mag
        self.corner_mag = corner_mag
        self.bin_width = bin_width
        self.a_val = a_val
        self.b_val = b_val

        self.beta = 2. / 3. * self.b_val

        # constants from Mfds.java
        self.SMALL_MO_MAG: float = 4.
        self.TAPERED_LARGE_MAG: float = 9.05

        self.min_mo = mag_to_mo(self.SMALL_MO_MAG)
        self.large_mo = mag_to_mo(self.TAPERED_LARGE_MAG)
        self.corner_mo = mag_to_mo(corner_mag)

        # This class uses a Double Truncated GR distribution, and the
        # rates are modified per the tapering.
        self._dt_gr = TruncatedGRMFD(self.min_mag, self.max_mag,
                                     self.bin_width, self.a_val, self.b_val)
        self._get_min_mag_and_num_bins = self._dt_gr._get_min_mag_and_num_bins

        self.check_constraints()
예제 #2
0
파일: hazard_test.py 프로젝트: lcui24/hmtk
 def setUp(self):
     """
     """
     mfd_1 = TruncatedGRMFD(4.5, 8.0, 0.1, 4.0, 1.0)
     mfd_2 = TruncatedGRMFD(4.5, 7.5, 0.1, 3.5, 1.1)
     self.source_model = [
         PointSource('001', 'Point1', 'Active Shallow Crust', mfd_1, 1.0,
                     WC1994(), 1.0, PoissonTOM(50.0), 0.0, 30.0,
                     Point(30.0, 30.5),
                     PMF([(1.0, NodalPlane(0.0, 90.0, 0.0))]),
                     PMF([(1.0, 10.0)])),
         PointSource('002', 'Point2', 'Active Shallow Crust', mfd_2, 1.0,
                     WC1994(), 1.0, PoissonTOM(50.0), 0.0, 30.0,
                     Point(30.0, 30.5),
                     PMF([(1.0, NodalPlane(0.0, 90.0, 0.0))]),
                     PMF([(1.0, 10.0)]))
     ]
     self.sites = SiteCollection([
         Site(Point(30.0, 30.0), 760., True, 1.0, 1.0, 1),
         Site(Point(30.25, 30.25), 760., True, 1.0, 1.0, 2),
         Site(Point(30.4, 30.4), 760., True, 1.0, 1.0, 2)
     ])
     self.gsims = {'Active Shallow Crust': 'AkkarBommer2010'}
     self.imts = ['PGA', 'SA(0.5)']
     self.imls = [[0.01, 0.1, 0.2, 0.5, 0.8]]
예제 #3
0
def example_calc(apply):
    sitecol = SiteCollection([
        Site(Point(30.0, 30.0), 760., 1.0, 1.0),
        Site(Point(30.25, 30.25), 760., 1.0, 1.0),
        Site(Point(30.4, 30.4), 760., 1.0, 1.0)
    ])
    mfd_1 = TruncatedGRMFD(4.5, 8.0, 0.1, 4.0, 1.0)
    mfd_2 = TruncatedGRMFD(4.5, 7.5, 0.1, 3.5, 1.1)
    sources = [
        PointSource('001', 'Point1', 'Active Shallow Crust', mfd_1, 1.0,
                    WC1994(), 1.0, PoissonTOM(50.0), 0.0, 30.0,
                    Point(30.0, 30.5), PMF([(1.0, NodalPlane(0.0, 90.0,
                                                             0.0))]),
                    PMF([(1.0, 10.0)])),
        PointSource('002', 'Point2', 'Active Shallow Crust', mfd_2, 1.0,
                    WC1994(), 1.0, PoissonTOM(50.0), 0.0, 30.0,
                    Point(30.0, 30.5), PMF([(1.0, NodalPlane(0.0, 90.0,
                                                             0.0))]),
                    PMF([(1.0, 10.0)]))
    ]
    imtls = {
        'PGA': [0.01, 0.1, 0.2, 0.5, 0.8],
        'SA(0.5)': [0.01, 0.1, 0.2, 0.5, 0.8]
    }
    gsims = {'Active Shallow Crust': AkkarBommer2010()}
    return calc_hazard_curves(sources,
                              sitecol,
                              imtls,
                              gsims,
                              apply=apply,
                              filter_distance='rrup')
예제 #4
0
파일: hazard_test.py 프로젝트: lcui24/hmtk
def reference_psha_calculation_openquake():
    """
    Sets up the reference PSHA calculation calling OpenQuake directly. All
    subsequent implementations should match this example
    """
    # Site model - 3 Sites
    site_model = SiteCollection([
        Site(Point(30.0, 30.0), 760., True, 1.0, 1.0, 1),
        Site(Point(30.25, 30.25), 760., True, 1.0, 1.0, 2),
        Site(Point(30.4, 30.4), 760., True, 1.0, 1.0, 2)
    ])
    # Source Model Two Point Sources
    mfd_1 = TruncatedGRMFD(4.5, 8.0, 0.1, 4.0, 1.0)
    mfd_2 = TruncatedGRMFD(4.5, 7.5, 0.1, 3.5, 1.1)
    source_model = [
        PointSource('001', 'Point1', 'Active Shallow Crust', mfd_1, 1.0,
                    WC1994(), 1.0, PoissonTOM(50.0), 0.0, 30.0,
                    Point(30.0, 30.5), PMF([(1.0, NodalPlane(0.0, 90.0,
                                                             0.0))]),
                    PMF([(1.0, 10.0)])),
        PointSource('002', 'Point2', 'Active Shallow Crust', mfd_2, 1.0,
                    WC1994(), 1.0, PoissonTOM(50.0), 0.0, 30.0,
                    Point(30.0, 30.5), PMF([(1.0, NodalPlane(0.0, 90.0,
                                                             0.0))]),
                    PMF([(1.0, 10.0)]))
    ]
    imts = {
        'PGA': [0.01, 0.1, 0.2, 0.5, 0.8],
        'SA(0.5)': [0.01, 0.1, 0.2, 0.5, 0.8]
    }
    # Akkar & Bommer (2010) GMPE
    gsims = {'Active Shallow Crust': gsim.akkar_bommer_2010.AkkarBommer2010()}
    truncation_level = None
    return calc_hazard_curves(source_model, site_model, imts, gsims,
                              truncation_level)
예제 #5
0
 def test_create_oq_hazardlib_point_source(self):
     """
     Tests the function to create a point source model
     """
     mfd1 = TruncatedGRMFD(5.0, 8.0, 0.1, 3.0, 1.0)
     self.point_source = mtkPointSource('001',
         'A Point Source',
         trt='Active Shallow Crust',
         geometry = Point(10., 10.),
         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.point_source.create_oqhazardlib_source(TOM,
                                                               2.0,
                                                               True)
     self.assertIsInstance(test_source, PointSource)
     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)
예제 #6
0
 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)
예제 #7
0
def plot_trunc_gr_model(aval, bval, min_mag, max_mag, dmag, catalogue=None,
        completeness=None, figure_size=None, filename=None, filetype='png', 
        dpi=300):
    """
    Plots a Gutenberg-Richter model
    """
    input_model = TruncatedGRMFD(min_mag, max_mag, dmag, aval, bval)
    if not catalogue:
        # Plot only the modelled recurrence
        annual_rates, cumulative_rates = _get_recurrence_model(input_model)
        plt.semilogy(annual_rates[:, 0], annual_rates[:, 1], 'b-')
        plt.semilogy(annual_rates[:, 0], cumulative_rates, 'r-')
        plt.xlabel('Magnitude', fontsize='large')
        plt.ylabel('Annual Rate', fontsize='large')
        plt.legend(['Incremental Rate', 'Cumulative Rate'])
        _save_image(filename, filetype, dpi)
    else:
        completeness = _check_completeness_table(completeness, catalogue)
        plot_recurrence_model(input_model,
                              catalogue,
                              completeness,
                              input_model.bin_width,
                              figure_size,
                              filename,
                              filetype,
              		      dpi)
                    
예제 #8
0
 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.)])
     ]
     mfd1 = TruncatedGRMFD(5.0, 8.0, 0.1, 3.0, 1.0)
     self.fault_source = mtkComplexFaultSource('001',
                                               'A Fault Source',
                                               trt='Active Shallow Crust',
                                               geometry=None,
                                               mag_scale_rel=None,
                                               rupt_aspect_ratio=1.0,
                                               mfd=mfd1,
                                               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)
예제 #9
0
def plot_trunc_gr_model(
        aval, bval, min_mag, max_mag, dmag,
        catalogue=None, completeness=None, filename=None,
        figure_size=(8, 6), filetype='png', dpi=300, ax=None):
    """
    Plots a Gutenberg-Richter model
    """
    input_model = TruncatedGRMFD(min_mag, max_mag, dmag, aval, bval)
    if not catalogue:
        # Plot only the modelled recurrence
        annual_rates, cumulative_rates = _get_recurrence_model(input_model)

        if ax is None:
            fig, ax = plt.subplots(figsize=figure_size)
        else:
            fig = ax.get_figure()

        ax.semilogy(annual_rates[:, 0], annual_rates[:, 1], 'b-')
        ax.semilogy(annual_rates[:, 0], cumulative_rates, 'r-')
        ax.xlabel('Magnitude')
        ax.set_ylabel('Annual Rate')
        ax.set_legend(['Incremental Rate', 'Cumulative Rate'])
        _save_image(fig, filename, filetype, dpi)

    else:
        completeness = _check_completeness_table(completeness, catalogue)
        plot_recurrence_model(
            input_model, catalogue, completeness, dmag, filename=filename,
            figure_size=figure_size, filetype=filetype, dpi=dpi, ax=ax)
예제 #10
0
 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 collapse_sources(source_df, source_tree_symbolic_df, bin_width=0.1):
    '''
    Given a tree dataframe of branches and a source model dataframe of zones,
    for every branch affecting MFDs, collapse all possible MFDs into one
    using those weights, add the combined MFD to the zone in the source model
    and finally remove the corresponding branch from the tree.
    '''
    collapsible = np.array([
        branch['uncertaintyType'] in MODEL_LENGTHS.keys()
        for _, branch in source_tree_symbolic_df.iterrows()
    ])

    source_df = source_df.loc[(source_df['a'] != 0)
                              & (source_df['mmax'] != 0)].copy()

    zone_rates, all_rates, all_weights = [], [], []
    for _, zone in source_df.iterrows():

        mfds = [
            TruncatedGRMFD(min_mag=zone['mmin'],
                           max_mag=zone['mmax'],
                           a_val=zone['a'],
                           b_val=zone['b'],
                           bin_width=bin_width)
        ]
        weights = [1.]
        labels = ['']

        # apply logic tree branches in successsion
        for _, branch in source_tree_symbolic_df.loc[collapsible].iterrows():
            try:
                mfds, weights, labels = branch_mfds(mfds, weights, labels,
                                                    branch, zone)
            except ValueError:
                print(zone)
                mfds, weights, labels = branch_mfds(mfds, weights, labels,
                                                    branch, zone)
        rates = get_rates(mfds)

        # compute the weighted sum of the rates for this zones
        collapsed_rates = (rates * weights.reshape(1, -1)).sum(axis=1)
        zone_rates.append(limit_precision(collapsed_rates, 5))

        # save intermediate results from each zone for diagnostic purposes
        all_rates.append(rates)
        all_weights.append(weights)

    source_df['occurRates'] = zone_rates
    source_df['magBin'] = bin_width
    source_df['all_rates'] = all_rates

    return (source_df,
            source_tree_symbolic_df.loc[np.logical_not(collapsible)],
            all_weights, labels)
예제 #12
0
 def test(self):
     sitecol = SiteCollection([Site(Point(30.0, 30.0), 760., 1.0, 1.0)])
     mfd = TruncatedGRMFD(4.5, 8.0, 0.1, 4.0, 1.0)
     sources = [
         PointSource('001', 'Point1', 'Active Shallow Crust', mfd, 1.0,
                     WC1994(), 1.0, PoissonTOM(50.0), 0.0, 30.0,
                     Point(30.0, 30.5),
                     PMF([(1.0, NodalPlane(0.0, 90.0, 0.0))]),
                     PMF([(1.0, 10.0)]))
     ]
     imtls = {'PGA': [0.01, 0.1, 0.2, 0.5, 0.8]}
     hc1 = calc_hazard_curves(
         sources, sitecol, imtls,
         {'Active Shallow Crust': AkkarBommer2010()})['PGA']
     hc2 = calc_hazard_curves(
         sources, sitecol, imtls,
         {'Active Shallow Crust': SadighEtAl1997()})['PGA']
     hc = .6 * hc1 + .4 * hc2
     ag = AvgGMPE(b1=dict(AkkarBommer2010={'weight': .6}),
                  b2=dict(SadighEtAl1997={'weight': .4}))
     hcm = calc_hazard_curves(sources, sitecol, imtls,
                              {'Active Shallow Crust': ag})['PGA']
     # the AvgGMPE is not producing real means!!
     numpy.testing.assert_almost_equal(hc, hcm, decimal=3)
예제 #13
0
class TaperedGRMFD(BaseMFD):
    """
    Tapered Gutenberg-Richter MFD is defined as a typical Truncated
    Gutenberg-Richter MFD up to a ``corner_mag`` above which an exponential
    taper is applied; see Kagan (2002a, Geophysical Journal International)
    for details. This implementation is based on
    the United States National Seismic Hazard Map Project code 
    (https://github.com/usgs/nshmp-haz).

    :param min_mag:
        The lowest possible magnitude for this MFD. The first bin in the
        :meth:`result histogram <get_annual_occurrence_rates>` will be aligned
        to make its left border match this value.
    :param max_mag:
        The highest possible magnitude. The same as for ``min_mag``: the last
        bin in the histogram will correspond to the magnitude value equal to
        ``max_mag - bin_width / 2``.
    :param corner_mag:
        The magnitude above which the exponential tapering of the earthquake
        frequency (rate) occurs. Rates below this magnitude are identical to 
        a Gutenberg-Richter with the same ``a`` and ``b`` values.
    :param bin_width:
        A positive float value -- the width of a single histogram bin.

    Values for ``min_mag`` and ``max_mag`` don't have to be aligned with
    respect to ``bin_width``. They get rounded accordingly anyway so that
    both are divisible by ``bin_width`` just before converting a function
    to a histogram. See :meth:`_get_min_mag_and_num_bins`.
    """

    MODIFICATIONS = set(())

    def __init__(self, min_mag: float, max_mag: float, corner_mag: float,
                 bin_width: float, a_val: float, b_val: float):

        self.min_mag = min_mag
        self.max_mag = max_mag
        self.corner_mag = corner_mag
        self.bin_width = bin_width
        self.a_val = a_val
        self.b_val = b_val

        self.beta = 2. / 3. * self.b_val

        # constants from Mfds.java
        self.SMALL_MO_MAG: float = 4.
        self.TAPERED_LARGE_MAG: float = 9.05

        self.min_mo = mag_to_mo(self.SMALL_MO_MAG)
        self.large_mo = mag_to_mo(self.TAPERED_LARGE_MAG)
        self.corner_mo = mag_to_mo(corner_mag)

        # This class uses a Double Truncated GR distribution, and the
        # rates are modified per the tapering.
        self._dt_gr = TruncatedGRMFD(self.min_mag, self.max_mag,
                                     self.bin_width, self.a_val, self.b_val)
        self._get_min_mag_and_num_bins = self._dt_gr._get_min_mag_and_num_bins

        self.check_constraints()

    def check_constraints(self):
        """
        Checks the following constraints:

        * Bin width is greater than 0.
        * Minimum magnitude is positive.
        * Maximum magnitude is greater than minimum magnitude
          by at least one bin width (or equal to that value).
        * Corner magnitude is greater than minimum magnitude
          by at least one bin width (or equal to that value).
        * ``b`` value is positive.
        """
        if not self.bin_width > 0:
            raise ValueError('bin width %g must be positive' % self.bin_width)

        if not self.min_mag >= 0:
            raise ValueError('minimum magnitude %g must be non-negative' %
                             self.min_mag)

        if not self.max_mag >= self.min_mag + self.bin_width:
            raise ValueError('maximum magnitude %g must be higher than '
                             'minimum magnitude %g by '
                             'bin width %g at least' %
                             (self.max_mag, self.min_mag, self.bin_width))

        if not self.b_val > 0.:
            raise ValueError('b-value %g must be non-negative' % self.b_val)

        if not self.corner_mag >= self.min_mag + self.bin_width:
            raise ValueError('corner magnitude %g must be higher than '
                             'minimum magnitude %g by '
                             'bin width %g at least' %
                             (self.corner_mag, self.min_mag, self.bin_width))

    def _pareto(self, mo, corner_mo):
        """'pareto' function from nhsmp-haz
        """
        return (self.min_mo / mo)**self.beta * math.exp(
            (self.min_mo - mo) / corner_mo)

    def _scale_mag_bin_rate(self, mag, rate):
        """
        This function scales the TruncatedGRMFD rate for that bin using
        a tapering scheme developed in the NSHM-HAZ function; see
        Mfds.java in the nshmp-haz codebase.
        """

        mag_mo_lo = mag_to_mo(mag - self.bin_width / 2.)
        mag_mo_hi = mag_to_mo(mag + self.bin_width / 2.)

        scale_num = (self._pareto(mag_mo_lo, self.corner_mo) -
                     self._pareto(mag_mo_hi, self.corner_mo))

        scale_denom = (self._pareto(mag_mo_lo, self.large_mo) -
                       self._pareto(mag_mo_hi, self.large_mo))

        scale = scale_num / scale_denom

        return rate * scale

    def _get_rate(self, mag):
        """
        Calculate and return an annual occurrence rate for a specific bin.

        :param mag:
            Magnitude value corresponding to the center of the bin of interest.
        :returns:
            Float number, the annual occurrence rate
        """
        gr_rate = self._dt_gr._get_rate(mag)
        return self._scale_mag_bin_rate(mag, gr_rate)

    def get_min_max_mag(self):
        """
        Return the minimum and maximum magnitudes
        """
        return self._dt_gr.get_min_max_mag()

    def get_annual_occurrence_rates(self):
        """
        Calculate and return the annual occurrence rates histogram.

        The result histogram has only one bin if minimum and maximum magnitude
        values appear equal after rounding.

        :returns:
            See :meth:
            `openquake.hazardlib.mfd.base.BaseMFD.get_annual_occurrence_rates`.
        """
        mag_rates = []

        gr_rates = self._dt_gr.get_annual_occurrence_rates()

        for mag, rate in gr_rates:
            mag_rates.append((mag, self._scale_mag_bin_rate(mag, rate)))

        return mag_rates
예제 #14
0
min_mag = 4.5  # magnitude of earthquake
max_mag = 7.5
a_val = log10(4e4)  # random number
N0 = 10**a_val
b_val = 1.2
beta = bval2beta(b_val)
bin_width = [0.1]  #, 0.01]

fig = plt.figure(1, figsize=(12, 6))

# loop through bin width
for i, bw in enumerate(bin_width):
    plt.subplot(1, 2, i + 1)

    # get oq rates
    gr = TruncatedGRMFD(min_mag, max_mag, bw, a_val, b_val)

    oq_rates = gr.get_annual_occurrence_rates()
    # get cum OQ ratescum_oq_rates = []

    # get cummulative frisk rates (for OQ)
    cum_inc_rates, frisk_mags = get_oq_incrementalMFD(beta, N0, min_mag,
                                                      max_mag, bw)

    # get rates
    inc_rates = []
    for i in range(0, len(cum_inc_rates)):
        if i < len(cum_inc_rates) - 1:
            inc_rates.append(cum_inc_rates[i] - cum_inc_rates[i + 1])
        else:
            inc_rates.append(cum_inc_rates[i])