Example #1
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
Example #2
0
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])

    print 'IncrementalMFD'