Esempio n. 1
0
def stochastic_event_set(
        sources,
        sites=None,
        source_site_filter=filters.source_site_noop_filter,
        rupture_site_filter=filters.rupture_site_noop_filter):
    """
    Generates a 'Stochastic Event Set' (that is a collection of earthquake
    ruptures) representing a possible *realization* of the seismicity as
    described by a source model.

    The calculator loops over sources. For each source, it loops over ruptures.
    For each rupture, the number of occurrence is randomly sampled by
    calling
    :meth:`openquake.hazardlib.source.rupture.BaseProbabilisticRupture.sample_number_of_occurrences`

    .. note::
        This calculator is using random numbers. In order to reproduce the
        same results numpy random numbers generator needs to be seeded, see
        http://docs.scipy.org/doc/numpy/reference/generated/numpy.random.seed.html

    :param sources:
        An iterator of seismic sources objects (instances of subclasses
        of :class:`~openquake.hazardlib.source.base.BaseSeismicSource`).
    :param sites:
        A list of sites to consider (or None)
    :param source_site_filter:
        The source filter to use (only meaningful is sites is not None)
    :param source_site_filter:
        The rupture filter to use (only meaningful is sites is not None)
    :returns:
        Generator of :class:`~openquake.hazardlib.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.
    """
    if sites is None:  # no filtering
        for source in sources:
            try:
                for rupture in source.iter_ruptures():
                    for i in range(rupture.sample_number_of_occurrences()):
                        yield rupture
            except Exception as err:
                etype, err, tb = sys.exc_info()
                msg = 'An error occurred with source id=%s. Error: %s'
                msg %= (source.source_id, err.message)
                raise_(etype, msg, tb)
        return
    # else apply filtering
    sources_sites = source_site_filter((source, sites) for source in sources)
    for source, r_sites in sources_sites:
        try:
            ruptures_sites = rupture_site_filter(
                (rupture, r_sites) for rupture in source.iter_ruptures())
            for rupture, _sites in ruptures_sites:
                for i in range(rupture.sample_number_of_occurrences()):
                    yield rupture
        except Exception as err:
            etype, err, tb = sys.exc_info()
            msg = 'An error occurred with source id=%s. Error: %s'
            msg %= (source.source_id, err.message)
            raise_(etype, msg, tb)
Esempio n. 2
0
def stochastic_event_set(
        sources,
        sites=None,
        source_site_filter=filters.source_site_noop_filter,
        rupture_site_filter=filters.rupture_site_noop_filter):
    """
    Generates a 'Stochastic Event Set' (that is a collection of earthquake
    ruptures) representing a possible *realization* of the seismicity as
    described by a source model.

    The calculator loops over sources. For each source, it loops over ruptures.
    For each rupture, the number of occurrence is randomly sampled by
    calling
    :meth:`openquake.hazardlib.source.rupture.BaseProbabilisticRupture.sample_number_of_occurrences`

    .. note::
        This calculator is using random numbers. In order to reproduce the
        same results numpy random numbers generator needs to be seeded, see
        http://docs.scipy.org/doc/numpy/reference/generated/numpy.random.seed.html

    :param sources:
        An iterator of seismic sources objects (instances of subclasses
        of :class:`~openquake.hazardlib.source.base.BaseSeismicSource`).
    :param sites:
        A list of sites to consider (or None)
    :param source_site_filter:
        The source filter to use (only meaningful is sites is not None)
    :param source_site_filter:
        The rupture filter to use (only meaningful is sites is not None)
    :returns:
        Generator of :class:`~openquake.hazardlib.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.
    """
    if sites is None:  # no filtering
        for source in sources:
            try:
                for rupture in source.iter_ruptures():
                    for i in range(rupture.sample_number_of_occurrences()):
                        yield rupture
            except Exception as err:
                etype, err, tb = sys.exc_info()
                msg = 'An error occurred with source id=%s. Error: %s'
                msg %= (source.source_id, str(err))
                raise_(etype, msg, tb)
        return
    # else apply filtering
    sources_sites = source_site_filter((source, sites) for source in sources)
    for source, r_sites in sources_sites:
        try:
            ruptures_sites = rupture_site_filter(
                (rupture, r_sites) for rupture in source.iter_ruptures())
            for rupture, _sites in ruptures_sites:
                for i in range(rupture.sample_number_of_occurrences()):
                    yield rupture
        except Exception as err:
            etype, err, tb = sys.exc_info()
            msg = 'An error occurred with source id=%s. Error: %s'
            msg %= (source.source_id, str(err))
            raise_(etype, msg, tb)
Esempio n. 3
0
def trt_pmf(matrix):
    """
    Fold full disaggregation matrix to tectonic region type PMF.

    :returns:
        a scalar
    """
    nmags, ndists, nlons, nlats, neps = matrix.shape
    return 1. - numpy.prod(
        [1. - matrix[i][j][k][l][m]
         for i in range(nmags)
         for j in range(ndists)
         for k in range(nlons)
         for l in range(nlats)
         for m in range(neps)])
Esempio n. 4
0
def hazard_curves_per_trt(
        sources, sites, imtls, gsims, truncation_level=None,
        source_site_filter=filters.source_site_noop_filter,
        rupture_site_filter=filters.rupture_site_noop_filter,
        monitor=DummyMonitor()):
    """
    Compute the hazard curves for a set of sources belonging to the same
    tectonic region type for all the GSIMs associated to that TRT.
    The arguments are the same as in :func:`calc_hazard_curves`, except
    for ``gsims``, which is a list of GSIM instances.

    :returns:
        A list of G arrays of size N, where N is the number of sites and
        G the number of gsims. Each array contains records with fields given
        by the intensity measure types; the size of each field is given by the
        number of levels in ``imtls``.
    """
    gnames = list(map(str, gsims))
    imt_dt = numpy.dtype([(imt, float, len(imtls[imt]))
                          for imt in sorted(imtls)])
    imts = {from_string(imt): imls for imt, imls in imtls.items()}
    curves = [numpy.ones(len(sites), imt_dt) for gname in gnames]
    sources_sites = ((source, sites) for source in sources)
    ctx_mon = monitor('making contexts', measuremem=False)
    rup_mon = monitor('getting ruptures', measuremem=False)
    pne_mon = monitor('computing poes', measuremem=False)
    monitor.calc_times = []  # pairs (src_id, delta_t)
    for source, s_sites in source_site_filter(sources_sites):
        t0 = time.time()
        try:
            with rup_mon:
                rupture_sites = list(rupture_site_filter(
                    (rupture, s_sites) for rupture in source.iter_ruptures()))
            for rupture, r_sites in rupture_sites:
                for i, gsim in enumerate(gsims):
                    with ctx_mon:
                        sctx, rctx, dctx = gsim.make_contexts(r_sites, rupture)
                    with pne_mon:
                        for imt in imts:
                            poes = gsim.get_poes(
                                sctx, rctx, dctx, imt, imts[imt],
                                truncation_level)
                            pno = rupture.get_probability_no_exceedance(poes)
                            expanded_pno = r_sites.expand(pno, placeholder=1)
                            curves[i][str(imt)] *= expanded_pno
        except Exception as err:
            etype, err, tb = sys.exc_info()
            msg = 'An error occurred with source id=%s. Error: %s'
            msg %= (source.source_id, str(err))
            raise_(etype, msg, tb)

        # we are attaching the calculation times to the monitor
        # so that oq-lite (and the engine) can store them
        monitor.calc_times.append((source.id, time.time() - t0))
        # NB: source.id is an integer; it should not be confused
        # with source.source_id, which is a string
    for i in range(len(gnames)):
        for imt in imtls:
            curves[i][imt] = 1. - curves[i][imt]
    return curves
Esempio n. 5
0
    def expand(self, data, placeholder):
        """
        Expand a short array `data` over a filtered site collection of the
        same length and return a long array of size `total_sites` filled
        with the placeholder.

        The typical workflow is the following: there is a whole site
        collection, the one that has an information about all the sites.
        Then it gets filtered for performing some calculation on a limited
        set of sites (like for instance filtering sites by their proximity
        to a rupture). That filtering process can be repeated arbitrary
        number of times, i.e. a collection that is already filtered can
        be filtered for further limiting the set of sites to compute on.
        Then the (supposedly expensive) computation is done on a limited
        set of sites which still appears as just a :class:`SiteCollection`
        instance, so that computation code doesn't need to worry about
        filtering, it just needs to handle site collection objects. The
        calculation result comes in a form of 1d or 2d numpy array (that
        is, either one value per site or one 1d array per site) with length
        equal to number of sites in a filtered collection. That result
        needs to be expanded to an array of similar structure but the one
        that holds values for all the sites in the original (unfiltered)
        collection. This is what :meth:`expand` is for. It creates a result
        array of ``total_sites`` length and puts values from ``data`` into
        appropriate places in it remembering indices of sites that were
        chosen for actual calculation and leaving ``placeholder`` value
        everywhere else.

        :param data:
            1d or 2d numpy array with first dimension representing values
            computed for site from this collection.
        :param placeholder:
            A scalar value to be put in result array for those sites that
            were filtered out and no real calculation was performed for them.
        :returns:
            Array of length ``total_sites`` with values from ``data``
            distributed in the appropriate places.
        """
        len_data = data.shape[0]
        assert len_data == len(self), (len_data, len(self))

        assert len_data <= self.total_sites
        assert self.indices[-1] < self.total_sites, (self.indices[-1],
                                                     self.total_sites)

        if data.ndim == 1:
            # single-dimensional array
            result = numpy.empty(self.total_sites)
            result.fill(placeholder)
            result.put(self.indices, data)
            return result

        assert data.ndim == 2
        # two-dimensional array
        num_values = data.shape[1]
        result = numpy.empty((self.total_sites, num_values))
        result.fill(placeholder)
        for i in range(num_values):
            result[:, i].put(self.indices, data[:, i])
        return result
Esempio n. 6
0
    def __init__(self, sites):
        """
        Build a complete SiteCollection from a list of Site objects
        """
        self.indices = None
        if hasattr(sites, 'sids'):
            numpy.testing.assert_equal(sites.sids, numpy.arange(len(sites)))
        self.array = arr = numpy.zeros(len(sites), self.dtype)
        for i in range(len(arr)):
            arr['sids'][i] = i
            arr['lons'][i] = sites[i].location.longitude
            arr['lats'][i] = sites[i].location.latitude
            arr['depths'][i] = sites[i].location.depth
            arr['vs30'][i] = sites[i].vs30
            arr['vs30measured'][i] = sites[i].vs30measured
            arr['z1pt0'][i] = sites[i].z1pt0
            arr['z2pt5'][i] = sites[i].z2pt5
            arr['backarc'][i] = sites[i].backarc

        # protect arrays from being accidentally changed. it is useful
        # because we pass these arrays directly to a GMPE through
        # a SiteContext object and if a GMPE is implemented poorly it could
        # modify the site values, thereby corrupting site and all the
        # subsequent calculation. note that this doesn't protect arrays from
        # being changed by calling itemset()
        arr.flags.writeable = False
Esempio n. 7
0
    def __init__(self, sites):
        self.complete = self
        self.total_sites = n = len(sites)
        self.sids = numpy.zeros(n, dtype=int)
        self.lons = numpy.zeros(n, dtype=float)
        self.lats = numpy.zeros(n, dtype=float)
        self._vs30 = numpy.zeros(n, dtype=float)
        self._vs30measured = numpy.zeros(n, dtype=bool)
        self._z1pt0 = numpy.zeros(n, dtype=float)
        self._z2pt5 = numpy.zeros(n, dtype=float)
        self._backarc = numpy.zeros(n, dtype=bool)

        for i in range(n):
            self.sids[i] = i
            self.lons[i] = sites[i].location.longitude
            self.lats[i] = sites[i].location.latitude
            self._vs30[i] = sites[i].vs30
            self._vs30measured[i] = sites[i].vs30measured
            self._z1pt0[i] = sites[i].z1pt0
            self._z2pt5[i] = sites[i].z2pt5
            self._backarc[i] = sites[i].backarc

        # protect arrays from being accidentally changed. it is useful
        # because we pass these arrays directly to a GMPE through
        # a SiteContext object and if a GMPE is implemented poorly it could
        # modify the site values, thereby corrupting site and all the
        # subsequent calculation. note that this doesn't protect arrays from
        # being changed by calling itemset()
        for arr in (self._vs30, self._vs30measured, self._z1pt0, self._z2pt5,
                    self.lons, self.lats, self._backarc, self.sids):
            arr.flags.writeable = False
Esempio n. 8
0
    def expand(self, data, placeholder):
        """
        Expand a short array `data` over a filtered site collection of the
        same length and return a long array of size `total_sites` filled
        with the placeholder.

        The typical workflow is the following: there is a whole site
        collection, the one that has an information about all the sites.
        Then it gets filtered for performing some calculation on a limited
        set of sites (like for instance filtering sites by their proximity
        to a rupture). That filtering process can be repeated arbitrary
        number of times, i.e. a collection that is already filtered can
        be filtered for further limiting the set of sites to compute on.
        Then the (supposedly expensive) computation is done on a limited
        set of sites which still appears as just a :class:`SiteCollection`
        instance, so that computation code doesn't need to worry about
        filtering, it just needs to handle site collection objects. The
        calculation result comes in a form of 1d or 2d numpy array (that
        is, either one value per site or one 1d array per site) with length
        equal to number of sites in a filtered collection. That result
        needs to be expanded to an array of similar structure but the one
        that holds values for all the sites in the original (unfiltered)
        collection. This is what :meth:`expand` is for. It creates a result
        array of ``total_sites`` length and puts values from ``data`` into
        appropriate places in it remembering indices of sites that were
        chosen for actual calculation and leaving ``placeholder`` value
        everywhere else.

        :param data:
            1d or 2d numpy array with first dimension representing values
            computed for site from this collection.
        :param placeholder:
            A scalar value to be put in result array for those sites that
            were filtered out and no real calculation was performed for them.
        :returns:
            Array of length ``total_sites`` with values from ``data``
            distributed in the appropriate places.
        """
        len_data = data.shape[0]
        assert len_data == len(self), (len_data, len(self))

        assert len_data <= self.total_sites
        assert self.indices[-1] < self.total_sites, (
            self.indices[-1], self.total_sites)

        if data.ndim == 1:
            # single-dimensional array
            result = numpy.empty(self.total_sites)
            result.fill(placeholder)
            result.put(self.indices, data)
            return result

        assert data.ndim == 2
        # two-dimensional array
        num_values = data.shape[1]
        result = numpy.empty((self.total_sites, num_values))
        result.fill(placeholder)
        for i in range(num_values):
            result[:, i].put(self.indices, data[:, i])
        return result
Esempio n. 9
0
    def __init__(self, sites):
        self.complete = self
        self.total_sites = n = len(sites)
        self.sids = numpy.zeros(n, dtype=int)
        self.lons = numpy.zeros(n, dtype=float)
        self.lats = numpy.zeros(n, dtype=float)
        self._vs30 = numpy.zeros(n, dtype=float)
        self._vs30measured = numpy.zeros(n, dtype=bool)
        self._z1pt0 = numpy.zeros(n, dtype=float)
        self._z2pt5 = numpy.zeros(n, dtype=float)
        self._backarc = numpy.zeros(n, dtype=bool)

        for i in range(n):
            self.sids[i] = i
            self.lons[i] = sites[i].location.longitude
            self.lats[i] = sites[i].location.latitude
            self._vs30[i] = sites[i].vs30
            self._vs30measured[i] = sites[i].vs30measured
            self._z1pt0[i] = sites[i].z1pt0
            self._z2pt5[i] = sites[i].z2pt5
            self._backarc[i] = sites[i].backarc

        # protect arrays from being accidentally changed. it is useful
        # because we pass these arrays directly to a GMPE through
        # a SiteContext object and if a GMPE is implemented poorly it could
        # modify the site values, thereby corrupting site and all the
        # subsequent calculation. note that this doesn't protect arrays from
        # being changed by calling itemset()
        for arr in (self._vs30, self._vs30measured, self._z1pt0, self._z2pt5,
                    self.lons, self.lats, self._backarc, self.sids):
            arr.flags.writeable = False
Esempio n. 10
0
 def _test_ruptures(self, expected_ruptures, source):
     ruptures = list(source.iter_ruptures())
     for rupture in ruptures:
         self.assertIsInstance(rupture, ParametricProbabilisticRupture)
         self.assertIs(rupture.temporal_occurrence_model, self.TOM)
         self.assertIs(rupture.tectonic_region_type, self.TRT)
         self.assertEqual(rupture.rake, self.RAKE)
     self.assertEqual(len(expected_ruptures), source.count_ruptures())
     for i in range(len(expected_ruptures)):
         expected_rupture, rupture = expected_ruptures[i], ruptures[i]
         self.assertAlmostEqual(rupture.mag, expected_rupture['mag'])
         self.assertAlmostEqual(rupture.rake, expected_rupture['rake'])
         self.assertAlmostEqual(rupture.occurrence_rate,
                                expected_rupture['occurrence_rate'])
         assert_mesh_is(self, rupture.surface, expected_rupture['surface'])
         self.assertEqual(rupture.hypocenter,
                          Point(*expected_rupture['hypocenter']))
         assert_angles_equal(self,
                             rupture.surface.get_strike(),
                             expected_rupture['strike'],
                             delta=0.5)
         assert_angles_equal(self,
                             rupture.surface.get_dip(),
                             expected_rupture['dip'],
                             delta=3)
Esempio n. 11
0
def min_geodetic_distance(mlons, mlats, slons, slats):
    """
    Same as :func:`min_distance`, but calculates only minimum geodetic distance
    (doesn't accept depth values) and doesn't support ``indices=True`` mode.

    This is an optimized version of :meth:`min_distance` that is suitable
    for calculating the minimum distance between first mesh and each point
    of the second mesh when both are defined on the earth surface.
    """
    mlons, mlats, slons, slats = _prepare_coords(mlons, mlats, slons, slats)
    orig_shape = slons.shape
    if slons.ndim == 0:
        slons = slons.reshape((1, ))
        slats = slats.reshape((1, ))
    cos_mlats = numpy.cos(mlats)
    cos_slats = numpy.cos(slats)

    result = numpy.fromiter(
        (
            # next five lines are the same as in geodetic_distance()
            numpy.arcsin(
                numpy.sqrt(
                    numpy.sin((mlats - slats[i]) / 2.0)**2.0 +
                    cos_mlats * cos_slats[i] * numpy.sin(
                        (mlons - slons[i]) / 2.0)**2.0).clip(-1., 1.)).min()
            for i in range(len(slats))),
        dtype=float,
        count=len(slats)) * (2 * EARTH_RADIUS)

    if not orig_shape:
        # original target point was a scalar, so return scalar as well
        [result] = result
        return result
    else:
        return result.reshape(orig_shape)
Esempio n. 12
0
def dist_pmf(matrix):
    """
    Fold full disaggregation matrix to distance PMF.

    :returns:
        1d array, a histogram representing distance PMF.
    """
    nmags, ndists, nlons, nlats, neps = matrix.shape
    dist_pmf = numpy.zeros(ndists)
    for j in range(ndists):
        dist_pmf[j] = numpy.prod(
            [1. - matrix[i][j][k][l][m]
             for i in range(nmags)
             for k in range(nlons)
             for l in range(nlats)
             for m in range(neps)])
    return 1. - dist_pmf
Esempio n. 13
0
def lon_lat_pmf(matrix):
    """
    Fold full disaggregation matrix to longitude / latitude PMF.

    :returns:
        2d array. First dimension represents longitude histogram bins,
        second one -- latitude histogram bins.
    """
    nmags, ndists, nlons, nlats, neps = matrix.shape
    lon_lat_pmf = numpy.zeros((nlons, nlats))
    for k in range(nlons):
        for l in range(nlats):
            lon_lat_pmf[k][l] = numpy.prod(
                [1. - matrix[i][j][k][l][m]
                 for i in range(nmags)
                 for j in range(ndists)
                 for m in range(neps)])
    return 1. - lon_lat_pmf
Esempio n. 14
0
def lon_lat_trt_pmf(matrix):
    """
    Fold full disaggregation matrix to longitude / latitude / tectonic region
    type PMF.

    :returns:
        3d array. Dimension represent longitude, latitude and tectonic region
        type histogram bins respectively.
    """
    nmags, ndists, nlons, nlats, neps, ntrts = matrix.shape
    lon_lat_trt_pmf = numpy.zeros((nlons, nlats, ntrts))
    for k in range(nlons):
        for l in range(nlats):
            for n in range(ntrts):
                lon_lat_trt_pmf[k][l][n] = numpy.prod(
                    [1 - matrix[i][j][k][l][m][n] for i in range(nmags) for j in range(ndists) for m in range(neps)]
                )
    return 1 - lon_lat_trt_pmf
Esempio n. 15
0
def mag_lon_lat_pmf(matrix):
    """
    Fold full disaggregation matrix to magnitude / longitude / latitude PMF.

    :returns:
        3d array. First dimension represents magnitude histogram bins,
        second one -- longitude histogram bins, third one -- latitude
        histogram bins.
    """
    nmags, ndists, nlons, nlats, neps, ntrts = matrix.shape
    mag_lon_lat_pmf = numpy.zeros((nmags, nlons, nlats))
    for i in range(nmags):
        for k in range(nlons):
            for l in range(nlats):
                mag_lon_lat_pmf[i][k][l] = numpy.prod(
                    [1 - matrix[i][j][k][l][m][n] for j in range(ndists) for m in range(neps) for n in range(ntrts)]
                )
    return 1 - mag_lon_lat_pmf
Esempio n. 16
0
def mag_dist_eps_pmf(matrix):
    """
    Fold full disaggregation matrix to magnitude / distance / epsilon PMF.

    :returns:
        3d array. First dimension represents magnitude histogram bins,
        second one -- distance histogram bins, third one -- epsilon
        histogram bins.
    """
    nmags, ndists, nlons, nlats, neps = matrix.shape
    mag_dist_eps_pmf = numpy.zeros((nmags, ndists, neps))
    for i in range(nmags):
        for j in range(ndists):
            for m in range(neps):
                mag_dist_eps_pmf[i][j][m] = numpy.prod(
                    [1. - matrix[i][j][k][l][m]
                     for k in range(nlons)
                     for l in range(nlats)])
    return 1. - mag_dist_eps_pmf
Esempio n. 17
0
    def split_in_tiles(self, hint):
        """
        Split a SiteCollection into a set of tiles (SiteCollection instances).

        :param hint: hint for how many tiles to generate
        """
        tiles = []
        for seq in split_in_blocks(range(len(self)), hint or 1):
            sc = SiteCollection.__new__(SiteCollection)
            sc.indices = None
            sc.array = self.array[numpy.array(seq, int)]
            tiles.append(sc)
        return tiles
Esempio n. 18
0
    def check_surface_validity(cls, edges):
        """
        Check validity of the surface.

        Project edge points to vertical plane anchored to surface upper left
        edge and with strike equal to top edge strike. Check that resulting
        polygon is valid.

        This method doesn't have to be called by hands before creating the
        surface object, because it is called from :meth:`from_fault_data`.
        """
        # extract coordinates of surface boundary (as defined from edges)
        full_boundary = []
        left_boundary = []
        right_boundary = []

        for i in range(1, len(edges) - 1):
            left_boundary.append(edges[i].points[0])
            right_boundary.append(edges[i].points[-1])

        full_boundary.extend(edges[0].points)
        full_boundary.extend(right_boundary)
        full_boundary.extend(edges[-1].points[::-1])
        full_boundary.extend(left_boundary[::-1])

        lons = [p.longitude for p in full_boundary]
        lats = [p.latitude for p in full_boundary]
        depths = [p.depth for p in full_boundary]

        # define reference plane. Corner points are separated by an arbitrary
        # distance of 10 km. The mesh spacing is set to 2 km. Both corner
        # distance and mesh spacing values do not affect the algorithm results.
        ul = edges[0].points[0]
        strike = ul.azimuth(edges[0].points[-1])
        dist = 10.
        mesh_spacing = 2.

        ur = ul.point_at(dist, 0, strike)
        bl = Point(ul.longitude, ul.latitude, ul.depth + dist)
        br = bl.point_at(dist, 0, strike)

        # project surface boundary to reference plane and check for
        # validity.
        ref_plane = PlanarSurface.from_corner_points(
            mesh_spacing, ul, ur, br, bl
        )
        _, xx, yy = ref_plane._project(lons, lats, depths)
        coords = [(x, y) for x, y in zip(xx, yy)]
        p = shapely.geometry.Polygon(coords)
        if not p.is_valid:
            raise ValueError('Edges points are not in the right order')
Esempio n. 19
0
    def check_surface_validity(cls, edges):
        """
        Check validity of the surface.

        Project edge points to vertical plane anchored to surface upper left
        edge and with strike equal to top edge strike. Check that resulting
        polygon is valid.

        This method doesn't have to be called by hands before creating the
        surface object, because it is called from :meth:`from_fault_data`.
        """
        # extract coordinates of surface boundary (as defined from edges)
        full_boundary = []
        left_boundary = []
        right_boundary = []

        for i in range(1, len(edges) - 1):
            left_boundary.append(edges[i].points[0])
            right_boundary.append(edges[i].points[-1])

        full_boundary.extend(edges[0].points)
        full_boundary.extend(right_boundary)
        full_boundary.extend(edges[-1].points[::-1])
        full_boundary.extend(left_boundary[::-1])

        lons = [p.longitude for p in full_boundary]
        lats = [p.latitude for p in full_boundary]
        depths = [p.depth for p in full_boundary]

        # define reference plane. Corner points are separated by an arbitrary
        # distance of 10 km. The mesh spacing is set to 2 km. Both corner
        # distance and mesh spacing values do not affect the algorithm results.
        ul = edges[0].points[0]
        strike = ul.azimuth(edges[0].points[-1])
        dist = 10.
        mesh_spacing = 2.

        ur = ul.point_at(dist, 0, strike)
        bl = Point(ul.longitude, ul.latitude, ul.depth + dist)
        br = bl.point_at(dist, 0, strike)

        # project surface boundary to reference plane and check for
        # validity.
        ref_plane = PlanarSurface.from_corner_points(mesh_spacing, ul, ur, br,
                                                     bl)
        _, xx, yy = ref_plane._project(lons, lats, depths)
        coords = [(x, y) for x, y in zip(xx, yy)]
        p = shapely.geometry.Polygon(coords)
        if not p.is_valid:
            raise ValueError('Edges points are not in the right order')
Esempio n. 20
0
    def test_hypoloc_multisegment_rupture_test(self):
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 1.]])
        self.mesh_spacing = 5.
        self.fault_trace_nodes = [
            self.fault_trace_start,
            Point(0.3, 0.3), self.fault_trace_end
        ]
        self.fault_trace = Line(self.fault_trace_nodes)
        src = SimpleFaultSource(source_id, name, trt, self.src_mfd,
                                self.mesh_spacing, self.sarea, 1.,
                                self.src_tom, self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth, self.fault_trace,
                                self.dip, self.rake, hypo_list, slip_list)

        lon = [
            0.0954, 0.2544, 0.1272, 0.2862, 0.159, 0.3279, 0.1908, 0.3696,
            0.2226, 0.4114, 0.2544, 0.4531, 0.2862, 0.4949, 0.3279, 0.5366,
            0.3696, 0.5783, 0.4114, 0.6201, 0.4531, 0.6618, 0.4949, 0.7035,
            0.5366, 0.7453, 0.5783, 0.787, 0.6201, 0.8288, 0.6618, 0.8705
        ]

        lat = [
            0.0954, 0.2544, 0.1272, 0.2862, 0.159, 0.2694, 0.1908, 0.2527,
            0.2226, 0.236, 0.2544, 0.2192, 0.2862, 0.2025, 0.2694, 0.1858,
            0.2527, 0.169, 0.236, 0.1523, 0.2192, 0.1356, 0.2025, 0.1188,
            0.1858, 0.1021, 0.169, 0.0854, 0.1523, 0.0687, 0.1356, 0.0519
        ]

        dep = [
            10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0,
            30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
            10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0
        ]

        rate = [
            0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025,
            0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375,
            0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025,
            0.0375, 0.025, 0.0375, 0.025, 0.0375
        ]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(rup.hypocenter.longitude, lon[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.latitude, lat[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.depth, dep[i], delta=0.1)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
Esempio n. 21
0
def pure_distances(mlons, mlats, slons, slats):
    """
    :param mlons: array of m longitudes (for the rupture)
    :param mlats: array of m latitudes (for the rupture)
    :param slons: array of s longitudes (for the sites)
    :param slats: array of s latitudes (for the sites)
    :returns: array of (m, s) distances to be multiplied by the Earth diameter
    """
    cos_mlats = numpy.cos(mlats)
    cos_slats = numpy.cos(slats)
    result = numpy.zeros((len(mlons), len(slons)))
    if len(mlons) < len(slons):  # lots of sites
        for i in range(len(mlons)):
            a = numpy.sin((mlats[i] - slats) / 2.0)
            b = numpy.sin((mlons[i] - slons) / 2.0)
            result[i, :] = numpy.arcsin(
                numpy.sqrt(a * a + cos_mlats[i] * cos_slats * b * b))
    else:  # few sites
        for j in range(len(slons)):
            a = numpy.sin((mlats - slats[j]) / 2.0)
            b = numpy.sin((mlons - slons[j]) / 2.0)
            result[:, j] = numpy.arcsin(
                numpy.sqrt(a * a + cos_mlats * cos_slats[j] * b * b))
    return result
Esempio n. 22
0
def make_iml4(R, imtls, iml_disagg, poes_disagg=(None,), curves=()):
    """
    :returns: an ArrayWrapper over a 4D array of shape (N, R, M, P)
    """
    N = len(curves) or 1
    M = len(imtls)
    P = len(poes_disagg)
    arr = numpy.zeros((N, R, M, P))
    imts = [from_string(imt) for imt in imtls]
    for m, imt in enumerate(imtls):
        imls = imtls[imt]
        for p, poe in enumerate(poes_disagg):
            for r in range(R):
                arr[:, r, m, p] = _imls(curves, poe, imt, imls, r)
    return ArrayWrapper(arr, dict(poes_disagg=poes_disagg, imts=imts))
    def get_annual_occurrence_rates(self):
        """
        Calculate and return the annual occurrence rates histogram.

        :returns:
            See :meth:
            `openquake.hazardlib.mfd.base.BaseMFD.get_annual_occurrence_rates`.
        """
        mag, num_bins = self._get_min_mag_and_num_bins()
        rates = []
        for i in range(num_bins):
            rate = self._get_rate(mag)
            rates.append((mag, rate))
            mag += self.bin_width
        return rates
Esempio n. 24
0
def pure_distances(mlons, mlats, slons, slats):
    """
    :param mlons: array of m longitudes (for the rupture)
    :param mlats: array of m latitudes (for the rupture)
    :param slons: array of s longitudes (for the sites)
    :param slats: array of s latitudes (for the sites)
    :returns: array of (m, s) distances to be multiplied by the Earth diameter
    """
    cos_mlats = numpy.cos(mlats)
    cos_slats = numpy.cos(slats)
    result = numpy.zeros((len(mlons), len(slons)))
    if len(mlons) < len(slons):  # lots of sites
        for i in range(len(mlons)):
            a = numpy.sin((mlats[i] - slats) / 2.0)
            b = numpy.sin((mlons[i] - slons) / 2.0)
            result[i, :] = numpy.arcsin(
                numpy.sqrt(a * a + cos_mlats[i] * cos_slats * b * b))
    else:  # few sites
        for j in range(len(slons)):
            a = numpy.sin((mlats - slats[j]) / 2.0)
            b = numpy.sin((mlons - slons[j]) / 2.0)
            result[:, j] = numpy.arcsin(
                numpy.sqrt(a * a + cos_mlats * cos_slats[j] * b * b))
    return result
Esempio n. 25
0
def _digitize_lons(lons, lon_bins):
    """
    Return indices of the bins to which each value in lons belongs.
    Takes into account the case in which longitude values cross the
    international date line.
    """
    if cross_idl(lon_bins[0], lon_bins[-1]):
        idx = []
        for i_lon in range(len(lon_bins) - 1):
            extents = get_longitudinal_extent(lons, lon_bins[i_lon + 1])
            lon_idx = extents > 0
            if i_lon != 0:
                extents = get_longitudinal_extent(lon_bins[i_lon], lons)
                lon_idx &= extents >= 0
            idx.append(lon_idx)
        return numpy.array(idx)
    else:
        return numpy.digitize(lons, lon_bins) - 1
Esempio n. 26
0
    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, num_bins = self._get_min_mag_and_num_bins()
        rates = []
        for i in range(num_bins):
            rate = self._get_rate(mag)
            rates.append((mag, rate))
            mag += self.bin_width
        return rates
Esempio n. 27
0
    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, num_bins = self._get_min_mag_and_num_bins()
        rates = []
        for i in range(num_bins):
            rate = self._get_rate(mag)
            rates.append((mag, rate))
            mag += self.bin_width
        return rates
Esempio n. 28
0
 def test_modify_set_geometry_trace(self):
     new_fault = deepcopy(self.fault) 
     new_trace = Line([Point(30.0, 30.0), Point(30.2, 32.25)])
     new_fault.modify_set_geometry(new_trace, 0., 10., 45., 1.)
     exp_lons = [30.0, 30.2]
     exp_lats = [30.0, 32.25]
     for iloc in range(len(new_fault.fault_trace)):
         self.assertAlmostEqual(
             new_fault.fault_trace.points[iloc].longitude,
             exp_lons[iloc]
             )
         self.assertAlmostEqual(
             new_fault.fault_trace.points[iloc].latitude,
             exp_lats[iloc]
             )
     # Verify that the dip and seismogenic depths were not modified
     self.assertAlmostEqual(new_fault.dip, 45.0)
     self.assertAlmostEqual(new_fault.upper_seismogenic_depth, 0.0)
     self.assertAlmostEqual(new_fault.lower_seismogenic_depth, 10.0)
 def test_modify_set_geometry_trace(self):
     new_fault = deepcopy(self.fault) 
     new_trace = Line([Point(30.0, 30.0), Point(30.2, 32.25)])
     new_fault.modify_set_geometry(new_trace, 0., 10., 45., 1.)
     exp_lons = [30.0, 30.2]
     exp_lats = [30.0, 32.25]
     for iloc in range(len(new_fault.fault_trace)):
         self.assertAlmostEqual(
             new_fault.fault_trace.points[iloc].longitude,
             exp_lons[iloc]
             )
         self.assertAlmostEqual(
             new_fault.fault_trace.points[iloc].latitude,
             exp_lats[iloc]
             )
     # Verify that the dip and seismogenic depths were not modified
     self.assertAlmostEqual(new_fault.dip, 45.0)
     self.assertAlmostEqual(new_fault.upper_seismogenic_depth, 0.0)
     self.assertAlmostEqual(new_fault.lower_seismogenic_depth, 10.0)
    def test_hypoloc_multisegment_rupture_test(self):
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 1.]])
        self.mesh_spacing = 5.
        self.fault_trace_nodes = [
            self.fault_trace_start, Point(0.3, 0.3), self.fault_trace_end]
        self.fault_trace = Line(self.fault_trace_nodes)
        src = SimpleFaultSource(source_id, name, trt,
                                self.src_mfd, self.mesh_spacing,
                                self.sarea, 1., self.src_tom,
                                self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth,
                                self.fault_trace, self.dip, self.rake,
                                hypo_list, slip_list)

        lon = [0.0954, 0.2544, 0.1272, 0.2862, 0.159, 0.3279, 0.1908, 0.3696,
               0.2226, 0.4114, 0.2544, 0.4531, 0.2862, 0.4949, 0.3279, 0.5366,
               0.3696, 0.5783, 0.4114, 0.6201, 0.4531, 0.6618, 0.4949, 0.7035,
               0.5366, 0.7453, 0.5783, 0.787, 0.6201, 0.8288, 0.6618, 0.8705]

        lat = [0.0954, 0.2544, 0.1272, 0.2862, 0.159, 0.2694, 0.1908, 0.2527,
               0.2226, 0.236, 0.2544, 0.2192, 0.2862, 0.2025, 0.2694, 0.1858,
               0.2527, 0.169, 0.236, 0.1523, 0.2192, 0.1356, 0.2025, 0.1188,
               0.1858, 0.1021, 0.169, 0.0854, 0.1523, 0.0687, 0.1356, 0.0519]

        dep = [10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0]

        rate = [0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375,
                0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375,
                0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375,
                0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375, 0.025, 0.0375]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(rup.hypocenter.longitude, lon[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.latitude, lat[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.depth, dep[i], delta=0.1)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
Esempio n. 31
0
    def test_slip_vertical_rupture(self):
        self.src_mfd = mfdeven.EvenlyDiscretizedMFD(8.5, 1., [1.])
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 0.25], [0., 0.75]])
        src = SimpleFaultSource(source_id, name, trt, self.src_mfd,
                                self.mesh_spacing, self.sarea, 1.,
                                self.src_tom, self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth, self.fault_trace,
                                self.dip, self.rake, hypo_list, slip_list)

        slip = [90., 0., 90., 0.]
        rate = [0.1, 0.3, 0.15, 0.45]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(rup.rupture_slip_direction,
                                   slip[i],
                                   delta=0.1)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
    def test_slip_vertical_rupture(self):
        self.src_mfd = mfdeven.EvenlyDiscretizedMFD(8.5, 1., [1.])
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 0.25], [0., 0.75]])
        src = SimpleFaultSource(source_id, name, trt,
                                self.src_mfd, self.mesh_spacing,
                                self.sarea, 1., self.src_tom,
                                self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth,
                                self.fault_trace, self.dip,
                                self.rake, hypo_list, slip_list)

        slip = [90., 0., 90., 0.]
        rate = [0.1, 0.3, 0.15, 0.45]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(rup.rupture_slip_direction,
                                   slip[i], delta=0.1)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
Esempio n. 33
0
def trt_pmf(matrix):
    """
    Fold full disaggregation matrix to tectonic region type PMF.

    :returns:
        1d array, a histogram representing tectonic region type PMF.
    """
    nmags, ndists, nlons, nlats, neps, ntrts = matrix.shape
    trt_pmf = numpy.zeros(ntrts)
    for n in range(ntrts):
        trt_pmf[n] = numpy.prod([
            1 - matrix[i][j][k][l][m][n] for i in range(nmags)
            for j in range(ndists) for k in range(nlons) for l in range(nlats)
            for m in range(neps)
        ])
    return 1 - trt_pmf
 def _test_ruptures(self, expected_ruptures, source):
     ruptures = list(source.iter_ruptures())
     for rupture in ruptures:
         self.assertIsInstance(rupture, ParametricProbabilisticRupture)
         self.assertIs(rupture.temporal_occurrence_model, self.TOM)
         self.assertIs(rupture.tectonic_region_type, self.TRT)
         self.assertEqual(rupture.rake, self.RAKE)
     self.assertEqual(len(expected_ruptures), source.count_ruptures())
     for i in range(len(expected_ruptures)):
         expected_rupture, rupture = expected_ruptures[i], ruptures[i]
         self.assertAlmostEqual(rupture.mag, expected_rupture['mag'])
         self.assertAlmostEqual(rupture.rake, expected_rupture['rake'])
         self.assertAlmostEqual(rupture.occurrence_rate,
                                expected_rupture['occurrence_rate'])
         assert_mesh_is(self, rupture.surface,
                        expected_rupture['surface'])
         self.assertEqual(rupture.hypocenter,
                          Point(*expected_rupture['hypocenter']))
         assert_angles_equal(self, rupture.surface.get_strike(),
                             expected_rupture['strike'], delta=0.5)
         assert_angles_equal(self, rupture.surface.get_dip(),
                             expected_rupture['dip'], delta=3)
Esempio n. 35
0
    def split_in_tiles(self, hint):
        """
        Split a SiteCollection into a set of tiles (SiteCollection instances).

        :param hint: hint for how many tiles to generate
        """
        tiles = []
        for seq in split_in_blocks(range(len(self)), hint or 1):
            indices = numpy.array(seq, int)
            sc = SiteCollection.__new__(SiteCollection)
            sc.complete = sc
            sc.total_sites = len(indices)
            sc.sids = self.sids[indices]
            sc.lons = self.lons[indices]
            sc.lats = self.lats[indices]
            sc._vs30 = _extract(self._vs30, indices)
            sc._vs30measured = _extract(self._vs30measured, indices)
            sc._z1pt0 = _extract(self._z1pt0, indices)
            sc._z2pt5 = _extract(self._z2pt5, indices)
            sc._backarc = _extract(self._backarc, indices)
            tiles.append(sc)
        return tiles
Esempio n. 36
0
    def split_in_tiles(self, hint):
        """
        Split a SiteCollection into a set of tiles (SiteCollection instances).

        :param hint: hint for how many tiles to generate
        """
        tiles = []
        for seq in split_in_blocks(range(len(self)), hint or 1):
            indices = numpy.array(seq, int)
            sc = SiteCollection.__new__(SiteCollection)
            sc.complete = sc
            sc.total_sites = len(indices)
            sc.sids = self.sids[indices]
            sc.lons = self.lons[indices]
            sc.lats = self.lats[indices]
            sc._vs30 = _extract(self._vs30, indices)
            sc._vs30measured = _extract(self._vs30measured, indices)
            sc._z1pt0 = _extract(self._z1pt0, indices)
            sc._z2pt5 = _extract(self._z2pt5, indices)
            sc._backarc = _extract(self._backarc, indices)
            tiles.append(sc)
        return tiles
Esempio n. 37
0
def _digitize_lons(lons, lon_bins):
    """
    Return indices of the bins to which each value in lons belongs.
    Takes into account the case in which longitude values cross the
    international date line.

    :parameter lons:
        An instance of :mod:`numpy.array`. 
    :parameter lons_bins:
        An instance of :mod:`numpy.array`. 
    """
    if cross_idl(lon_bins[0], lon_bins[-1]):
        idx = numpy.zeros_like(lons, dtype=numpy.int)
        for i_lon in range(len(lon_bins) - 1):
            extents = get_longitudinal_extent(lons, lon_bins[i_lon + 1])
            lon_idx = extents > 0
            if i_lon != 0:
                extents = get_longitudinal_extent(lon_bins[i_lon], lons)
                lon_idx &= extents >= 0
            idx[lon_idx] = i_lon
        return numpy.array(idx)
    else:
        return numpy.digitize(lons, lon_bins) - 1
Esempio n. 38
0
def _digitize_lons(lons, lon_bins):
    """
    Return indices of the bins to which each value in lons belongs.
    Takes into account the case in which longitude values cross the
    international date line.

    :parameter lons:
        An instance of `numpy.ndarray`.
    :parameter lons_bins:
        An instance of `numpy.ndarray`.
    """
    if cross_idl(lon_bins[0], lon_bins[-1]):
        idx = numpy.zeros_like(lons, dtype=numpy.int)
        for i_lon in range(len(lon_bins) - 1):
            extents = get_longitudinal_extent(lons, lon_bins[i_lon + 1])
            lon_idx = extents > 0
            if i_lon != 0:
                extents = get_longitudinal_extent(lon_bins[i_lon], lons)
                lon_idx &= extents >= 0
            idx[lon_idx] = i_lon
        return numpy.array(idx)
    else:
        return numpy.digitize(lons, lon_bins) - 1
Esempio n. 39
0
def min_geodetic_distance(mlons, mlats, slons, slats):
    """
    Same as :func:`min_distance`, but calculates only minimum geodetic distance
    (doesn't accept depth values) and doesn't support ``indices=True`` mode.

    This is an optimized version of :meth:`min_distance` that is suitable
    for calculating the minimum distance between first mesh and each point
    of the second mesh when both are defined on the earth surface.
    """
    mlons, mlats, slons, slats = _prepare_coords(mlons, mlats, slons, slats)
    orig_shape = slons.shape
    if slons.ndim == 0:
        slons = slons.reshape((1, ))
        slats = slats.reshape((1, ))
    cos_mlats = numpy.cos(mlats)
    cos_slats = numpy.cos(slats)

    result = numpy.fromiter(
        (
            # next five lines are the same as in geodetic_distance()
            numpy.arcsin(numpy.sqrt(
                numpy.sin((mlats - slats[i]) / 2.0) ** 2.0
                + cos_mlats * cos_slats[i]
                * numpy.sin((mlons - slons[i]) / 2.0) ** 2.0
            ).clip(-1., 1.)).min()
            for i in range(len(slats))
        ),
        dtype=float, count=len(slats)
    ) * (2 * EARTH_RADIUS)

    if not orig_shape:
        # original target point was a scalar, so return scalar as well
        [result] = result
        return result
    else:
        return result.reshape(orig_shape)
Esempio n. 40
0
def trt_pmf(matrix):
    """
    Fold full disaggregation matrix to tectonic region type PMF.

    :returns:
        1d array, a histogram representing tectonic region type PMF.
    """
    nmags, ndists, nlons, nlats, neps, ntrts = matrix.shape
    trt_pmf = numpy.zeros(ntrts)
    for n in range(ntrts):
        trt_pmf[n] = numpy.prod(
            [1 - matrix[i][j][k][l][m][n]
             for i in range(nmags)
             for j in range(ndists)
             for k in range(nlons)
             for l in range(nlats)
             for m in range(neps)]
        )
    return 1 - trt_pmf
Esempio n. 41
0
def lon_lat_trt_pmf(matrix):
    """
    Fold full disaggregation matrix to longitude / latitude / tectonic region
    type PMF.

    :returns:
        3d array. Dimension represent longitude, latitude and tectonic region
        type histogram bins respectively.
    """
    nmags, ndists, nlons, nlats, neps, ntrts = matrix.shape
    lon_lat_trt_pmf = numpy.zeros((nlons, nlats, ntrts))
    for k in range(nlons):
        for l in range(nlats):
            for n in range(ntrts):
                lon_lat_trt_pmf[k][l][n] = numpy.prod([
                    1 - matrix[i][j][k][l][m][n] for i in range(nmags)
                    for j in range(ndists) for m in range(neps)
                ])
    return 1 - lon_lat_trt_pmf
Esempio n. 42
0
def mag_lon_lat_pmf(matrix):
    """
    Fold full disaggregation matrix to magnitude / longitude / latitude PMF.

    :returns:
        3d array. First dimension represents magnitude histogram bins,
        second one -- longitude histogram bins, third one -- latitude
        histogram bins.
    """
    nmags, ndists, nlons, nlats, neps, ntrts = matrix.shape
    mag_lon_lat_pmf = numpy.zeros((nmags, nlons, nlats))
    for i in range(nmags):
        for k in range(nlons):
            for l in range(nlats):
                mag_lon_lat_pmf[i][k][l] = numpy.prod([
                    1 - matrix[i][j][k][l][m][n] for j in range(ndists)
                    for m in range(neps) for n in range(ntrts)
                ])
    return 1 - mag_lon_lat_pmf
Esempio n. 43
0
    def iter_ruptures(self):
        """
        See :meth:
        `openquake.hazardlib.source.base.BaseSeismicSource.iter_ruptures`.

        Generates a ruptures using the "floating" algorithm: for all the
        magnitude values of assigned MFD calculates the rupture size with
        respect to MSR and aspect ratio and then places ruptures of that
        size on the surface of the whole fault source. The occurrence
        rate of each of those ruptures is the magnitude occurrence rate
        divided by the number of ruptures that can be placed in a fault.
        """
        whole_fault_surface = SimpleFaultSurface.from_fault_data(
            self.fault_trace, self.upper_seismogenic_depth,
            self.lower_seismogenic_depth, self.dip, self.rupture_mesh_spacing)
        whole_fault_mesh = whole_fault_surface.get_mesh()
        mesh_rows, mesh_cols = whole_fault_mesh.shape
        fault_length = float((mesh_cols - 1) * self.rupture_mesh_spacing)
        fault_width = float((mesh_rows - 1) * self.rupture_mesh_spacing)

        for (mag, mag_occ_rate) in self.get_annual_occurrence_rates():
            rup_cols, rup_rows = self._get_rupture_dimensions(
                fault_length, fault_width, mag)
            num_rup_along_length = mesh_cols - rup_cols + 1
            num_rup_along_width = mesh_rows - rup_rows + 1
            num_rup = num_rup_along_length * num_rup_along_width

            occurrence_rate = mag_occ_rate / float(num_rup)

            for first_row in range(num_rup_along_width):
                for first_col in range(num_rup_along_length):
                    mesh = whole_fault_mesh[first_row:first_row + rup_rows,
                                            first_col:first_col + rup_cols]

                    if not len(self.hypo_list) and not len(self.slip_list):

                        hypocenter = mesh.get_middle_point()
                        occurrence_rate_hypo = occurrence_rate
                        surface = SimpleFaultSurface(mesh)

                        yield ParametricProbabilisticRupture(
                            mag, self.rake,
                            self.tectonic_region_type, hypocenter, surface,
                            type(self), occurrence_rate_hypo,
                            self.temporal_occurrence_model)
                    else:
                        for hypo in self.hypo_list:
                            for slip in self.slip_list:
                                surface = SimpleFaultSurface(mesh)
                                hypocenter = surface.get_hypo_location(
                                    self.rupture_mesh_spacing, hypo[:2])
                                occurrence_rate_hypo = occurrence_rate * \
                                    hypo[2] * slip[1]
                                rupture_slip_direction = slip[0]

                                yield ParametricProbabilisticRupture(
                                    mag, self.rake, self.tectonic_region_type,
                                    hypocenter, surface, type(self),
                                    occurrence_rate_hypo,
                                    self.temporal_occurrence_model,
                                    rupture_slip_direction)
Esempio n. 44
0
def hazard_curves_per_trt(
        sources, sites, imtls, gsims, truncation_level=None,
        source_site_filter=filters.source_site_noop_filter,
        rupture_site_filter=filters.rupture_site_noop_filter,
        maximum_distance=None, bbs=(), monitor=DummyMonitor()):
    """
    Compute the hazard curves for a set of sources belonging to the same
    tectonic region type for all the GSIMs associated to that TRT.
    The arguments are the same as in :func:`calc_hazard_curves`, except
    for ``gsims``, which is a list of GSIM instances.

    :returns:
        A list of G arrays of size N, where N is the number of sites and
        G the number of gsims. Each array contains records with fields given
        by the intensity measure types; the size of each field is given by the
        number of levels in ``imtls``.
    """
    cmaker = ContextMaker(gsims, maximum_distance)
    gnames = list(map(str, gsims))
    imt_dt = numpy.dtype([(imt, float, len(imtls[imt]))
                          for imt in sorted(imtls)])
    imts = {from_string(imt): imls for imt, imls in imtls.items()}
    curves = [numpy.ones(len(sites), imt_dt) for gname in gnames]
    sources_sites = ((source, sites) for source in sources)
    ctx_mon = monitor('making contexts', measuremem=False)
    rup_mon = monitor('getting ruptures', measuremem=False)
    pne_mon = monitor('computing poes', measuremem=False)
    monitor.calc_times = []  # pairs (src_id, delta_t)
    for source, s_sites in source_site_filter(sources_sites):
        t0 = time.time()
        try:
            with rup_mon:
                rupture_sites = list(rupture_site_filter(
                    (rupture, s_sites) for rupture in source.iter_ruptures()))
            for rupture, r_sites in rupture_sites:
                with ctx_mon:
                    try:
                        sctx, rctx, dctx = cmaker.make_contexts(
                            r_sites, rupture)
                    except FarAwayRupture:
                        continue

                    # add optional disaggregation information (bounding boxes)
                    if bbs:
                        sids = set(sctx.sites.sids)
                        jb_dists = dctx.rjb
                        closest_points = rupture.surface.get_closest_points(
                            sctx.sites.mesh)
                        bs = [bb for bb in bbs if bb.site_id in sids]
                        # NB: the assert below is always true; we are
                        # protecting against possible refactoring errors
                        assert len(bs) == len(jb_dists) == len(closest_points)
                        for bb, dist, p in zip(bs, jb_dists, closest_points):
                            if dist < maximum_distance:
                                # ruptures too far away are ignored
                                bb.update([dist], [p.longitude], [p.latitude])

                for i, gsim in enumerate(gsims):
                    with pne_mon:
                        for imt in imts:
                            poes = gsim.get_poes(
                                sctx, rctx, dctx, imt, imts[imt],
                                truncation_level)
                            pno = rupture.get_probability_no_exceedance(poes)
                            expanded_pno = sctx.sites.expand(pno, 1.0)
                            curves[i][str(imt)] *= expanded_pno
        except Exception as err:
            etype, err, tb = sys.exc_info()
            msg = 'An error occurred with source id=%s. Error: %s'
            msg %= (source.source_id, str(err))
            raise_(etype, msg, tb)

        # we are attaching the calculation times to the monitor
        # so that oq-lite (and the engine) can store them
        monitor.calc_times.append((source.id, time.time() - t0))
        # NB: source.id is an integer; it should not be confused
        # with source.source_id, which is a string
    for i in range(len(gnames)):
        for imt in imtls:
            curves[i][imt] = 1. - curves[i][imt]
    return curves
Esempio n. 45
0
def min_distance(mlons, mlats, mdepths, slons, slats, sdepths, indices=False):
    """
    Calculate the minimum distance between a collection of points and a point.

    This function allows to calculate a closest distance to a collection
    of points for each point in another collection. Both collection can be
    of any shape, although it doesn't make sense to use scalars for the first
    one.

    Implements the same formula as in :func:`geodetic_distance` for distance
    along great circle arc and the same approach as in :func:`distance`
    for combining it with depth distance.

    :param array mlons, mlats, mdepths:
        Numpy arrays of the same shape representing a first collection
        of points, the one distance to which is of interest -- longitudes,
        latitudes (both in decimal degrees) and depths (in km).
    :param array slons, slats, sdepths:
        Scalars, python lists or tuples or numpy arrays of the same shape,
        representing a second collection: a list of points to find a minimum
        distance from for.
    :param indices:
        If ``True`` -- return indices of closest points from first triple
        of coordinates instead of the actual distances. Indices are always
        scalar integers -- they represent indices of a point from flattened
        form of ``mlons``, ``mlats`` and ``mdepths`` that is closest to a
        point from ``slons``, ``slats`` and ``sdepths``. There is one integer
        index per point in second triple of coordinates.
    :returns:
        Minimum distance in km or indices of closest points, depending on
        ``indices`` parameter. Result value is a scalar if ``slons``, ``slats``
        and ``sdepths`` are scalars and numpy array of the same shape
        of those three otherwise.
    """
    assert not indices or mlons.ndim > 0
    mlons, mlats, slons, slats = _prepare_coords(mlons, mlats, slons, slats)
    mdepths = numpy.array(mdepths, float)
    sdepths = numpy.array(sdepths, float)
    assert mlons.shape == mdepths.shape
    assert slons.shape == sdepths.shape

    orig_shape = slons.shape

    mlons = mlons.reshape(-1)
    mlats = mlats.reshape(-1)
    mdepths = mdepths.reshape(-1)
    slons = slons.reshape(-1)
    slats = slats.reshape(-1)
    sdepths = sdepths.reshape(-1)

    cos_mlats = numpy.cos(mlats)
    cos_slats = numpy.cos(slats)

    dist_squares = (
        # next five lines are the same as in geodetic_distance()
        (numpy.arcsin(numpy.sqrt(
            numpy.sin((mlats - slats[i]) / 2.0) ** 2.0
            + cos_mlats * cos_slats[i]
            * numpy.sin((mlons - slons[i]) / 2.0) ** 2.0
        ).clip(-1., 1.)) * (2 * EARTH_RADIUS)) ** 2
        + (mdepths - sdepths[i]) ** 2
        for i in range(len(slats))
    )
    if not indices:
        result = numpy.fromiter((numpy.sqrt(numpy.min(dist_sq))
                                 for dist_sq in dist_squares),
                                dtype=float, count=len(slats))
    else:
        result = numpy.fromiter((numpy.argmin(dsq, axis=-1)
                                 for dsq in dist_squares),
                                dtype=int, count=len(slats))

    if not orig_shape:
        # original target point was a scalar, so return scalar as well
        [result] = result
        return result
    else:
        return result.reshape(orig_shape)
Esempio n. 46
0
def _float_ruptures(rupture_area, rupture_length, cell_area, cell_length):
    """
    Get all possible unique rupture placements on the fault surface.

    :param rupture_area:
        The area of the rupture to float on the fault surface, in squared km.
    :param rupture_length:
        The target length (spatial extension along fault trace) of the rupture,
        in km.
    :param cell_area:
        2d numpy array representing area of mesh cells in squared km.
    :param cell_length:
        2d numpy array of the shape as ``cell_area`` representing cells'
        length in km.
    :returns:
        A list of slice objects. Number of items in the list is equal to number
        of possible locations of the requested rupture on the fault surface.
        Each slice can be used to get a portion of the whole fault surface mesh
        that would represent the location of the rupture.
    """
    nrows, ncols = cell_length.shape

    if rupture_area >= numpy.sum(cell_area):
        # requested rupture area exceeds the total surface area.
        # return the single slice that doesn't cut anything out.
        return [slice(None)]

    rupture_slices = []

    dead_ends = set()
    for row in range(nrows):
        for col in range(ncols):
            if col in dead_ends:
                continue
            # find the lengths of all possible subsurfaces containing
            # only the current row and from the current column till
            # the last one.
            lengths_acc = numpy.add.accumulate(cell_length[row, col:])
            # find the "best match" number of columns, the one that gives
            # the least difference between actual and requested rupture
            # length (note that we only consider top row here, mainly
            # for simplicity: it's not yet clear how many rows will we
            # end up with).
            rup_cols = numpy.argmin(numpy.abs(lengths_acc - rupture_length))
            last_col = rup_cols + col + 1
            if last_col == ncols and lengths_acc[rup_cols] < rupture_length:
                # rupture doesn't fit along length (the requested rupture
                # length is greater than the length of the part of current
                # row that starts from the current column).
                if col != 0:
                    # if we are not in the first column, it means that we
                    # hit the right border, so we need to go to the next
                    # row.
                    break

            # now try to find the optimum (the one providing the closest
            # to requested area) number of rows.
            areas_acc = numpy.sum(cell_area[row:, col:last_col], axis=1)
            areas_acc = numpy.add.accumulate(areas_acc, axis=0)
            rup_rows = numpy.argmin(numpy.abs(areas_acc - rupture_area))
            last_row = rup_rows + row + 1
            if last_row == nrows and areas_acc[rup_rows] < rupture_area:
                # rupture doesn't fit along width.
                # we can try to extend it along length but only if we are
                # at the first row
                if row == 0:
                    if last_col == ncols:
                        # there is no place to extend, exiting
                        return rupture_slices
                    else:
                        # try to extend along length
                        areas_acc = numpy.sum(cell_area[:, col:], axis=0)
                        areas_acc = numpy.add.accumulate(areas_acc, axis=0)
                        rup_cols = numpy.argmin(
                            numpy.abs(areas_acc - rupture_area))
                        last_col = rup_cols + col + 1
                        if last_col == ncols \
                                and areas_acc[rup_cols] < rupture_area:
                            # still doesn't fit, return
                            return rupture_slices
                else:
                    # row is not the first and the required area exceeds
                    # available area starting from target row and column.
                    # mark the column as "dead end" so we don't create
                    # one more rupture from the same column on all
                    # subsequent rows.
                    dead_ends.add(col)

            # here we add 1 to last row and column numbers because we want
            # to return slices for cutting the mesh of vertices, not the cell
            # data (like cell_area or cell_length).
            rupture_slices.append(
                (slice(row, last_row + 1), slice(col, last_col + 1)))
    return rupture_slices
Esempio n. 47
0
def min_distance(mlons, mlats, mdepths, slons, slats, sdepths, indices=False):
    """
    Calculate the minimum distance between a collection of points and a point.

    This function allows to calculate a closest distance to a collection
    of points for each point in another collection. Both collection can be
    of any shape, although it doesn't make sense to use scalars for the first
    one.

    Implements the same formula as in :func:`geodetic_distance` for distance
    along great circle arc and the same approach as in :func:`distance`
    for combining it with depth distance.

    :param array mlons, mlats, mdepths:
        Numpy arrays of the same shape representing a first collection
        of points, the one distance to which is of interest -- longitudes,
        latitudes (both in decimal degrees) and depths (in km).
    :param array slons, slats, sdepths:
        Scalars, python lists or tuples or numpy arrays of the same shape,
        representing a second collection: a list of points to find a minimum
        distance from for.
    :param indices:
        If ``True`` -- return indices of closest points from first triple
        of coordinates instead of the actual distances. Indices are always
        scalar integers -- they represent indices of a point from flattened
        form of ``mlons``, ``mlats`` and ``mdepths`` that is closest to a
        point from ``slons``, ``slats`` and ``sdepths``. There is one integer
        index per point in second triple of coordinates.
    :returns:
        Minimum distance in km or indices of closest points, depending on
        ``indices`` parameter. Result value is a scalar if ``slons``, ``slats``
        and ``sdepths`` are scalars and numpy array of the same shape
        of those three otherwise.
    """
    assert not indices or mlons.ndim > 0
    mlons, mlats, slons, slats = _prepare_coords(mlons, mlats, slons, slats)
    mdepths = numpy.array(mdepths, float)
    sdepths = numpy.array(sdepths, float)
    assert mlons.shape == mdepths.shape
    assert slons.shape == sdepths.shape

    orig_shape = slons.shape

    mlons = mlons.reshape(-1)
    mlats = mlats.reshape(-1)
    mdepths = mdepths.reshape(-1)
    slons = slons.reshape(-1)
    slats = slats.reshape(-1)
    sdepths = sdepths.reshape(-1)

    cos_mlats = numpy.cos(mlats)
    cos_slats = numpy.cos(slats)

    dist_squares = (
        # next five lines are the same as in geodetic_distance()
        (numpy.arcsin(
            numpy.sqrt(
                numpy.sin((mlats - slats[i]) / 2.0)**2.0 +
                cos_mlats * cos_slats[i] * numpy.sin(
                    (mlons - slons[i]) / 2.0)**2.0).clip(-1., 1.)) *
         (2 * EARTH_RADIUS))**2 + (mdepths - sdepths[i])**2
        for i in range(len(slats)))
    if not indices:
        result = numpy.fromiter(
            (numpy.sqrt(numpy.min(dist_sq)) for dist_sq in dist_squares),
            dtype=float,
            count=len(slats))
    else:
        result = numpy.fromiter(
            (numpy.argmin(dsq, axis=-1) for dsq in dist_squares),
            dtype=int,
            count=len(slats))

    if not orig_shape:
        # original target point was a scalar, so return scalar as well
        [result] = result
        return result
    else:
        return result.reshape(orig_shape)
    def test_hypoloc_vertical_rupture(self):
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 1.]])
        src = SimpleFaultSource(source_id, name, trt,
                                self.src_mfd, self.mesh_spacing,
                                self.sarea, 1., self.src_tom,
                                self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth,
                                self.fault_trace, self.dip,
                                self.rake, hypo_list, slip_list)

        lon = [0.11691180881629422, 0.35972864251163345, 0.12590502487907043,
               0.36872185857443507, 0.13489824094187208, 0.37771507463723675,
               0.14389145700464828, 0.38670829070001295, 0.15288467306744993,
               0.39570150676281457, 0.16187788913025158, 0.40469472282559077,
               0.17087110519302778, 0.41368793888839245, 0.17986432125582943,
               0.42268115495119407, 0.18885753731860563, 0.43167437101397027,
               0.19785075338140728, 0.44066758707677195, 0.20684396944418348,
               0.44966080313954815, 0.21583718550698514, 0.45865401920234977,
               0.22483040156978679, 0.46764723526512603, 0.23382361763256301,
               0.47664045132792765, 0.24281683369536466, 0.48563366739072933,
               0.25181004975814086, 0.49462688345350553, 0.26080326582094249,
               0.50362009951630715, 0.26979648188374417, 0.51261331557908341,
               0.27878969794652037, 0.52160653164188497, 0.28778291400932199,
               0.53059974770468665, 0.29677613007209824, 0.53959296376746291,
               0.30576934613489987, 0.54858617983026448, 0.31476256219770149,
               0.55757939589304073, 0.32375577826047774, 0.56657261195584241,
               0.33274899432327937, 0.57556582801864398, 0.34174221038605557,
               0.58455904408142023, 0.35073542644885725, 0.59355226014422191,
               0.35972864251163345, 0.60254547620699805, 0.36872185857443507,
               0.61153869226979973, 0.37771507463723675, 0.62053190833257599,
               0.38670829070001295, 0.62952512439537756, 0.39570150676281457,
               0.63851834045817923, 0.40469472282559077, 0.64751155652095549,
               0.41368793888839245, 0.65650477258375706, 0.42268115495119407,
               0.66549798864653331, 0.43167437101397027, 0.67449120470933499,
               0.44066758707677195, 0.68348442077213656, 0.44966080313954815,
               0.69247763683491281, 0.45865401920234977, 0.70147085289771449,
               0.46764723526512603, 0.71046406896049064, 0.47664045132792765,
               0.71945728502329231, 0.48563366739072933, 0.72845050108606846,
               0.49462688345350553, 0.73744371714887014, 0.50362009951630715,
               0.74643693321167182, 0.51261331557908341, 0.75543014927444796,
               0.52160653164188497, 0.76442336533724964, 0.53059974770468665,
               0.77341658140002589, 0.53959296376746291, 0.78240979746282757,
               0.54858617983026448, 0.79140301352562914, 0.55757939589304073,
               0.80039622958840539, 0.56657261195584241, 0.80938944565120707,
               0.57556582801864398, 0.81838266171398322, 0.58455904408142023,
               0.82737587777678498, 0.59355226014422191, 0.83636909383958657,
               0.60254547620699805, 0.84536230990236272, 0.61153869226979973,
               0.85435552596516445, 0.62053190833257599, 0.86334874202794054,
               0.62952512439537756, 0.87234195809074222, 0.63851834045817923,
               0.88133517415351847]
        lat = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0]
        dep = [10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0]

        rate = [0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(
                rup.hypocenter.longitude, lon[i], delta=0.01)
            self.assertAlmostEqual(rup.hypocenter.latitude, lat[i], delta=0.01)
            self.assertAlmostEqual(rup.hypocenter.depth, dep[i], delta=0.01)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
    def test_hypoloc_dip_rupture(self):
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        dip = 30.
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 1.]])
        self.mesh_spacing = 5.
        src = SimpleFaultSource(source_id, name, trt,
                                self.src_mfd, self.mesh_spacing, self.sarea,
                                1., self.src_tom, self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth,
                                self.fault_trace, dip, self.rake, hypo_list,
                                slip_list)

        lon = [0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993]

        lat = [-0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726,
               -0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726, -0.0779,
               -0.2726, -0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726,
               -0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726, -0.0779,
               -0.2726, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115,
               -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168,
               -0.3115, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115,
               -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168,
               -0.3115, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505,
               -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558,
               -0.3505, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505,
               -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558,
               -0.3505, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894,
               -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947,
               -0.3894, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894,
               -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947,
               -0.3894, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337,
               -0.4284, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337, -0.4284,
               -0.2337, -0.4284, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337,
               -0.4284, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337, -0.4284,
               -0.2337, -0.4284, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726,
               -0.4673, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726, -0.4673,
               -0.2726, -0.4673, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726,
               -0.4673, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726, -0.4673,
               -0.2726, -0.4673, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115,
               -0.5062, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115, -0.5062,
               -0.3115, -0.5062, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115,
               -0.5062, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115, -0.5062,
               -0.3115, -0.5062, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505,
               -0.5452, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505, -0.5452,
               -0.3505, -0.5452, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505,
               -0.5452, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505, -0.5452,
               -0.3505, -0.5452]

        dep = [5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0,
               17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5,
               5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 7.5,
               20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0,
               7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5,
               20.0, 7.5, 20.0, 7.5, 20.0, 10.0, 22.5, 10.0, 22.5, 10.0,
               22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0,
               22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0,
               22.5, 10.0, 22.5, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5,
               25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5,
               25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5,
               25.0, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5,
               15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5,
               15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5,
               17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0,
               17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0,
               17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 20.0, 32.5,
               20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5,
               20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5,
               20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 22.5, 35.0, 22.5, 35.0,
               22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0,
               22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0,
               22.5, 35.0, 22.5, 35.0]

        rate = [0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(rup.hypocenter.longitude, lon[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.latitude, lat[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.depth, dep[i], delta=0.1)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
Esempio n. 50
0
def _float_ruptures(rupture_area, rupture_length, cell_area, cell_length):
    """
    Get all possible unique rupture placements on the fault surface.

    :param rupture_area:
        The area of the rupture to float on the fault surface, in squared km.
    :param rupture_length:
        The target length (spatial extension along fault trace) of the rupture,
        in km.
    :param cell_area:
        2d numpy array representing area of mesh cells in squared km.
    :param cell_length:
        2d numpy array of the shape as ``cell_area`` representing cells'
        length in km.
    :returns:
        A list of slice objects. Number of items in the list is equal to number
        of possible locations of the requested rupture on the fault surface.
        Each slice can be used to get a portion of the whole fault surface mesh
        that would represent the location of the rupture.
    """
    nrows, ncols = cell_length.shape

    if rupture_area >= numpy.sum(cell_area):
        # requested rupture area exceeds the total surface area.
        # return the single slice that doesn't cut anything out.
        return [slice(None)]

    rupture_slices = []

    dead_ends = set()
    for row in range(nrows):
        for col in range(ncols):
            if col in dead_ends:
                continue
            # find the lengths of all possible subsurfaces containing
            # only the current row and from the current column till
            # the last one.
            lengths_acc = numpy.add.accumulate(cell_length[row, col:])
            # find the "best match" number of columns, the one that gives
            # the least difference between actual and requested rupture
            # length (note that we only consider top row here, mainly
            # for simplicity: it's not yet clear how many rows will we
            # end up with).
            rup_cols = numpy.argmin(numpy.abs(lengths_acc - rupture_length))
            last_col = rup_cols + col + 1
            if last_col == ncols and lengths_acc[rup_cols] < rupture_length:
                # rupture doesn't fit along length (the requested rupture
                # length is greater than the length of the part of current
                # row that starts from the current column).
                if col != 0:
                    # if we are not in the first column, it means that we
                    # hit the right border, so we need to go to the next
                    # row.
                    break

            # now try to find the optimum (the one providing the closest
            # to requested area) number of rows.
            areas_acc = numpy.sum(cell_area[row:, col:last_col], axis=1)
            areas_acc = numpy.add.accumulate(areas_acc, axis=0)
            rup_rows = numpy.argmin(numpy.abs(areas_acc - rupture_area))
            last_row = rup_rows + row + 1
            if last_row == nrows and areas_acc[rup_rows] < rupture_area:
                # rupture doesn't fit along width.
                # we can try to extend it along length but only if we are
                # at the first row
                if row == 0:
                    if last_col == ncols:
                        # there is no place to extend, exiting
                        return rupture_slices
                    else:
                        # try to extend along length
                        areas_acc = numpy.sum(cell_area[:, col:], axis=0)
                        areas_acc = numpy.add.accumulate(areas_acc, axis=0)
                        rup_cols = numpy.argmin(numpy.abs(areas_acc
                                                          - rupture_area))
                        last_col = rup_cols + col + 1
                        if last_col == ncols \
                                and areas_acc[rup_cols] < rupture_area:
                            # still doesn't fit, return
                            return rupture_slices
                else:
                    # row is not the first and the required area exceeds
                    # available area starting from target row and column.
                    # mark the column as "dead end" so we don't create
                    # one more rupture from the same column on all
                    # subsequent rows.
                    dead_ends.add(col)

            # here we add 1 to last row and column numbers because we want
            # to return slices for cutting the mesh of vertices, not the cell
            # data (like cell_area or cell_length).
            rupture_slices.append((slice(row, last_row + 1),
                                   slice(col, last_col + 1)))
    return rupture_slices
Esempio n. 51
0
    def test_hypoloc_dip_rupture(self):
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        dip = 30.
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 1.]])
        self.mesh_spacing = 5.
        src = SimpleFaultSource(source_id, name, trt,
                                self.src_mfd, self.mesh_spacing, self.sarea,
                                1., self.src_tom, self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth,
                                self.fault_trace, dip, self.rake, hypo_list,
                                slip_list)

        lon = [0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993,
               0.0899, 0.3148, 0.1349, 0.3597, 0.1799, 0.4047, 0.2248,
               0.4497, 0.2698, 0.4946, 0.3148, 0.5396, 0.3597, 0.5846,
               0.4047, 0.6295, 0.4497, 0.6745, 0.4946, 0.7195, 0.5396,
               0.7644, 0.5846, 0.8094, 0.6295, 0.8544, 0.6745, 0.8993]

        lat = [-0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726,
               -0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726, -0.0779,
               -0.2726, -0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726,
               -0.0779, -0.2726, -0.0779, -0.2726, -0.0779, -0.2726, -0.0779,
               -0.2726, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115,
               -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168,
               -0.3115, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115,
               -0.1168, -0.3115, -0.1168, -0.3115, -0.1168, -0.3115, -0.1168,
               -0.3115, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505,
               -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558,
               -0.3505, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505,
               -0.1558, -0.3505, -0.1558, -0.3505, -0.1558, -0.3505, -0.1558,
               -0.3505, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894,
               -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947,
               -0.3894, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894,
               -0.1947, -0.3894, -0.1947, -0.3894, -0.1947, -0.3894, -0.1947,
               -0.3894, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337,
               -0.4284, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337, -0.4284,
               -0.2337, -0.4284, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337,
               -0.4284, -0.2337, -0.4284, -0.2337, -0.4284, -0.2337, -0.4284,
               -0.2337, -0.4284, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726,
               -0.4673, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726, -0.4673,
               -0.2726, -0.4673, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726,
               -0.4673, -0.2726, -0.4673, -0.2726, -0.4673, -0.2726, -0.4673,
               -0.2726, -0.4673, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115,
               -0.5062, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115, -0.5062,
               -0.3115, -0.5062, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115,
               -0.5062, -0.3115, -0.5062, -0.3115, -0.5062, -0.3115, -0.5062,
               -0.3115, -0.5062, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505,
               -0.5452, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505, -0.5452,
               -0.3505, -0.5452, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505,
               -0.5452, -0.3505, -0.5452, -0.3505, -0.5452, -0.3505, -0.5452,
               -0.3505, -0.5452]

        dep = [5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0,
               17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5,
               5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 5.0, 17.5, 7.5,
               20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0,
               7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5, 20.0, 7.5,
               20.0, 7.5, 20.0, 7.5, 20.0, 10.0, 22.5, 10.0, 22.5, 10.0,
               22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0,
               22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0, 22.5, 10.0,
               22.5, 10.0, 22.5, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5,
               25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5,
               25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5, 25.0, 12.5,
               25.0, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5,
               15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5,
               15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5, 15.0, 27.5,
               17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0,
               17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0,
               17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 17.5, 30.0, 20.0, 32.5,
               20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5,
               20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 20.0, 32.5,
               20.0, 32.5, 20.0, 32.5, 20.0, 32.5, 22.5, 35.0, 22.5, 35.0,
               22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0,
               22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0, 22.5, 35.0,
               22.5, 35.0, 22.5, 35.0]

        rate = [0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036,
                0.0054, 0.0036, 0.0054, 0.0036, 0.0054, 0.0036, 0.0054,
                0.0036, 0.0054, 0.0036, 0.0054]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(rup.hypocenter.longitude, lon[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.latitude, lat[i], delta=0.1)
            self.assertAlmostEqual(rup.hypocenter.depth, dep[i], delta=0.1)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
Esempio n. 52
0
    def test_hypoloc_vertical_rupture(self):
        source_id = name = 'test-source'
        trt = TRT.ACTIVE_SHALLOW_CRUST
        hypo_list = numpy.array([[0.25, 0.25, 0.4], [0.75, 0.75, 0.6]])
        slip_list = numpy.array([[90., 1.]])
        src = SimpleFaultSource(source_id, name, trt,
                                self.src_mfd, self.mesh_spacing,
                                self.sarea, 1., self.src_tom,
                                self.upper_seismogenic_depth,
                                self.lower_seismogenic_depth,
                                self.fault_trace, self.dip,
                                self.rake, hypo_list, slip_list)

        lon = [0.11691180881629422, 0.35972864251163345, 0.12590502487907043,
               0.36872185857443507, 0.13489824094187208, 0.37771507463723675,
               0.14389145700464828, 0.38670829070001295, 0.15288467306744993,
               0.39570150676281457, 0.16187788913025158, 0.40469472282559077,
               0.17087110519302778, 0.41368793888839245, 0.17986432125582943,
               0.42268115495119407, 0.18885753731860563, 0.43167437101397027,
               0.19785075338140728, 0.44066758707677195, 0.20684396944418348,
               0.44966080313954815, 0.21583718550698514, 0.45865401920234977,
               0.22483040156978679, 0.46764723526512603, 0.23382361763256301,
               0.47664045132792765, 0.24281683369536466, 0.48563366739072933,
               0.25181004975814086, 0.49462688345350553, 0.26080326582094249,
               0.50362009951630715, 0.26979648188374417, 0.51261331557908341,
               0.27878969794652037, 0.52160653164188497, 0.28778291400932199,
               0.53059974770468665, 0.29677613007209824, 0.53959296376746291,
               0.30576934613489987, 0.54858617983026448, 0.31476256219770149,
               0.55757939589304073, 0.32375577826047774, 0.56657261195584241,
               0.33274899432327937, 0.57556582801864398, 0.34174221038605557,
               0.58455904408142023, 0.35073542644885725, 0.59355226014422191,
               0.35972864251163345, 0.60254547620699805, 0.36872185857443507,
               0.61153869226979973, 0.37771507463723675, 0.62053190833257599,
               0.38670829070001295, 0.62952512439537756, 0.39570150676281457,
               0.63851834045817923, 0.40469472282559077, 0.64751155652095549,
               0.41368793888839245, 0.65650477258375706, 0.42268115495119407,
               0.66549798864653331, 0.43167437101397027, 0.67449120470933499,
               0.44066758707677195, 0.68348442077213656, 0.44966080313954815,
               0.69247763683491281, 0.45865401920234977, 0.70147085289771449,
               0.46764723526512603, 0.71046406896049064, 0.47664045132792765,
               0.71945728502329231, 0.48563366739072933, 0.72845050108606846,
               0.49462688345350553, 0.73744371714887014, 0.50362009951630715,
               0.74643693321167182, 0.51261331557908341, 0.75543014927444796,
               0.52160653164188497, 0.76442336533724964, 0.53059974770468665,
               0.77341658140002589, 0.53959296376746291, 0.78240979746282757,
               0.54858617983026448, 0.79140301352562914, 0.55757939589304073,
               0.80039622958840539, 0.56657261195584241, 0.80938944565120707,
               0.57556582801864398, 0.81838266171398322, 0.58455904408142023,
               0.82737587777678498, 0.59355226014422191, 0.83636909383958657,
               0.60254547620699805, 0.84536230990236272, 0.61153869226979973,
               0.85435552596516445, 0.62053190833257599, 0.86334874202794054,
               0.62952512439537756, 0.87234195809074222, 0.63851834045817923,
               0.88133517415351847]
        lat = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
               0.0]
        dep = [10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0,
               10.0, 30.0, 10.0, 30.0, 10.0, 30.0, 10.0, 30.0]

        rate = [0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728,
                0.0067796610169491532, 0.010169491525423728]

        for rup, i in zip(src.iter_ruptures(), range(1000)):
            self.assertAlmostEqual(
                rup.hypocenter.longitude, lon[i], delta=0.01)
            self.assertAlmostEqual(rup.hypocenter.latitude, lat[i], delta=0.01)
            self.assertAlmostEqual(rup.hypocenter.depth, dep[i], delta=0.01)
            self.assertAlmostEqual(rup.occurrence_rate, rate[i], delta=0.01)
Esempio n. 53
0
    def iter_ruptures(self):
        """
        See :meth:
        `openquake.hazardlib.source.base.BaseSeismicSource.iter_ruptures`.

        Generates a ruptures using the "floating" algorithm: for all the
        magnitude values of assigned MFD calculates the rupture size with
        respect to MSR and aspect ratio and then places ruptures of that
        size on the surface of the whole fault source. The occurrence
        rate of each of those ruptures is the magnitude occurrence rate
        divided by the number of ruptures that can be placed in a fault.
        """
        whole_fault_surface = SimpleFaultSurface.from_fault_data(
            self.fault_trace, self.upper_seismogenic_depth,
            self.lower_seismogenic_depth, self.dip, self.rupture_mesh_spacing
        )
        whole_fault_mesh = whole_fault_surface.get_mesh()
        mesh_rows, mesh_cols = whole_fault_mesh.shape
        fault_length = float((mesh_cols - 1) * self.rupture_mesh_spacing)
        fault_width = float((mesh_rows - 1) * self.rupture_mesh_spacing)

        for (mag, mag_occ_rate) in self.get_annual_occurrence_rates():
            rup_cols, rup_rows = self._get_rupture_dimensions(
                fault_length, fault_width, mag
            )
            num_rup_along_length = mesh_cols - rup_cols + 1
            num_rup_along_width = mesh_rows - rup_rows + 1
            num_rup = num_rup_along_length * num_rup_along_width

            occurrence_rate = mag_occ_rate / float(num_rup)

            for first_row in range(num_rup_along_width):
                for first_col in range(num_rup_along_length):
                    mesh = whole_fault_mesh[first_row: first_row + rup_rows,
                                            first_col: first_col + rup_cols]

                    if not len(self.hypo_list) and not len(self.slip_list):

                        hypocenter = mesh.get_middle_point()
                        occurrence_rate_hypo = occurrence_rate
                        surface = SimpleFaultSurface(mesh)

                        yield ParametricProbabilisticRupture(
                            mag, self.rake, self.tectonic_region_type,
                            hypocenter, surface, type(self),
                            occurrence_rate_hypo,
                            self.temporal_occurrence_model
                        )
                    else:
                        for hypo in self.hypo_list:
                            for slip in self.slip_list:
                                surface = SimpleFaultSurface(mesh)
                                hypocenter = surface.get_hypo_location(
                                    self.rupture_mesh_spacing, hypo[:2])
                                occurrence_rate_hypo = occurrence_rate * \
                                    hypo[2] * slip[1]
                                rupture_slip_direction = slip[0]

                                yield ParametricProbabilisticRupture(
                                    mag, self.rake, self.tectonic_region_type,
                                    hypocenter, surface, type(self),
                                    occurrence_rate_hypo,
                                    self.temporal_occurrence_model,
                                    rupture_slip_direction
                                )
Esempio n. 54
0
def hazard_curves_per_trt(
        sources, sites, imtls, gsims, truncation_level=None,
        source_site_filter=filters.source_site_noop_filter,
        rupture_site_filter=filters.rupture_site_noop_filter,
        maximum_distance=None, bbs=(), monitor=Monitor()):
    """
    Compute the hazard curves for a set of sources belonging to the same
    tectonic region type for all the GSIMs associated to that TRT.
    The arguments are the same as in :func:`calc_hazard_curves`, except
    for ``gsims``, which is a list of GSIM instances.

    :returns:
        A list of G arrays of size N, where N is the number of sites and
        G the number of gsims. Each array contains records with fields given
        by the intensity measure types; the size of each field is given by the
        number of levels in ``imtls``.
    """
    cmaker = ContextMaker(gsims, maximum_distance)
    gnames = list(map(str, gsims))
    imt_dt = numpy.dtype([(imt, float, len(imtls[imt]))
                          for imt in sorted(imtls)])
    imts = {from_string(imt): imls for imt, imls in imtls.items()}
    curves = [numpy.ones(len(sites), imt_dt) for gname in gnames]
    sources_sites = ((source, sites) for source in sources)
    ctx_mon = monitor('making contexts', measuremem=False)
    pne_mon = monitor('computing poes', measuremem=False)
    monitor.calc_times = []  # pairs (src_id, delta_t)
    monitor.eff_ruptures = 0  # effective number of contributing ruptures
    for source, s_sites in source_site_filter(sources_sites):
        t0 = time.time()
        try:
            rupture_sites = rupture_site_filter(
                (rupture, s_sites) for rupture in source.iter_ruptures())
            for rupture, r_sites in rupture_sites:
                with ctx_mon:
                    try:
                        sctx, rctx, dctx = cmaker.make_contexts(
                            r_sites, rupture)
                    except FarAwayRupture:
                        continue

                    monitor.eff_ruptures += 1

                    # add optional disaggregation information (bounding boxes)
                    if bbs:
                        sids = set(sctx.sites.sids)
                        jb_dists = dctx.rjb
                        closest_points = rupture.surface.get_closest_points(
                            sctx.sites.mesh)
                        bs = [bb for bb in bbs if bb.site_id in sids]
                        # NB: the assert below is always true; we are
                        # protecting against possible refactoring errors
                        assert len(bs) == len(jb_dists) == len(closest_points)
                        for bb, dist, p in zip(bs, jb_dists, closest_points):
                            if dist < maximum_distance:
                                # ruptures too far away are ignored
                                bb.update([dist], [p.longitude], [p.latitude])

                for i, gsim in enumerate(gsims):
                    with pne_mon:
                        for imt in imts:
                            poes = gsim.get_poes(
                                sctx, rctx, dctx, imt, imts[imt],
                                truncation_level)
                            pno = rupture.get_probability_no_exceedance(poes)
                            expanded_pno = sctx.sites.expand(pno, 1.0)
                            curves[i][str(imt)] *= expanded_pno
        except Exception as err:
            etype, err, tb = sys.exc_info()
            msg = 'An error occurred with source id=%s. Error: %s'
            msg %= (source.source_id, str(err))
            raise_(etype, msg, tb)

        # we are attaching the calculation times to the monitor
        # so that oq-lite (and the engine) can store them
        monitor.calc_times.append((source.id, time.time() - t0))
        # NB: source.id is an integer; it should not be confused
        # with source.source_id, which is a string
    for i in range(len(gnames)):
        for imt in imtls:
            curves[i][imt] = 1. - curves[i][imt]
    return curves