Пример #1
0
    def filter_sites_by_distance_from_rupture_set(
            self, rupset_idx, sites, max_dist):
        """
        Filter sites by distances from a set of ruptures
        """
        with h5py.File(self.source_file, "r") as hdf5:
            rup_index_key = "/".join([self.idx_set["geol_idx"],
                                      "RuptureIndex"])

            # Find the combination of rupture sections used in this model
            rupture_set = set()
            # Determine which of the rupture sections used in this set
            # of indices
            for i in rupset_idx:
                rupture_set.update(hdf5[rup_index_key][i])
            centroids = np.empty([1, 3])
            # For each of the identified rupture sections, retreive the
            # centroids
            for ridx in rupture_set:
                trace_idx = "{:s}/{:s}".format(self.idx_set["sec_idx"],
                                               str(ridx))
                centroids = np.vstack([
                    centroids,
                    hdf5[trace_idx + "/Centroids"][:].astype("float64")])
            distance = min_geodetic_distance(centroids[1:, 0],
                                             centroids[1:, 1],
                                             sites.lons, sites.lats)
            idx = distance <= max_dist
            if np.any(idx):
                return rupset_idx, sites.filter(idx)
            else:
                return [], []
Пример #2
0
    def _test(self, mlons, mlats, mdepths, slons, slats, sdepths,
              expected_mpoint_indices):
        mlons, mlats, mdepths = [numpy.array(arr, float)
                                 for arr in (mlons, mlats, mdepths)]
        slons, slats, sdepths = [numpy.array(arr, float)
                                 for arr in (slons, slats, sdepths)]
        actual_indices = geodetic.min_distance(mlons, mlats, mdepths,
                                               slons, slats, sdepths,
                                               indices=True)
        numpy.testing.assert_equal(actual_indices, expected_mpoint_indices)
        dists = geodetic.min_distance(mlons, mlats, mdepths,
                                      slons, slats, sdepths)
        expected_closest_mlons = mlons.flat[expected_mpoint_indices]
        expected_closest_mlats = mlats.flat[expected_mpoint_indices]
        expected_closest_mdepths = mdepths.flat[expected_mpoint_indices]
        expected_distances = geodetic.distance(
            expected_closest_mlons, expected_closest_mlats,
            expected_closest_mdepths,
            slons, slats, sdepths
        )
        self.assertTrue((dists == expected_distances).all())

        # testing min_geodetic_distance with the same lons and lats
        min_geod_distance = geodetic.min_geodetic_distance(mlons, mlats,
                                                           slons, slats)
        min_geo_distance2 = geodetic.min_distance(mlons, mlats, mdepths * 0,
                                                  slons, slats, sdepths * 0)
        numpy.testing.assert_almost_equal(min_geod_distance, min_geo_distance2)
Пример #3
0
def prefilter_ruptures(hdf5, ridx, idx_set, sites, integration_distance):
    """
    Determines if a rupture is likely to be inside the integration distance
    by considering the set of fault plane centroids.

    :param hdf5:
        Source of UCERF file as h5py.File object
    :param list ridx:
        List of indices composing the rupture sections
    :param dict idx_set:
        Set of indices for the branch
    :param sites:
        Sites for consideration (can be None!)
    :param float integration_distance:
        Maximum distance from rupture to site for consideration
    """
    # Generate array of sites
    if not sites:
        return True
    centroids = numpy.array([[0., 0., 0.]], dtype="f")
    for idx in ridx:
        trace_idx = "{:s}/{:s}".format(idx_set["sec_idx"], str(idx))
        centroids = numpy.vstack([
            centroids,
            hdf5[trace_idx + "/Centroids"][:].astype("float64")])
    centroids = centroids[1:, :]
    distance = min_geodetic_distance(centroids[:, 0], centroids[:, 1],
                                     sites.lons, sites.lats)
    #logging.info("%s  -  %s", str(ridx), str(numpy.min(distance)))
    return numpy.any(distance <= integration_distance)
Пример #4
0
	def gaussian(self, radius, sigma):
		# Values
		values = numpy.zeros((len(self.mesh)))
		# Compute the number of expected nodes
		numpnts = consts.pi*radius**2/(self.cellsize**2)
		# Smoothing the catalogue
		for lon, lat, mag in zip(self.catalogue.data['longitude'],
								 self.catalogue.data['latitude'],
								 self.catalogue.data['magnitude']):
			# set the bounding box
			minlon, minlat = point_at(lon, lat, 225, radius*2**0.5)
			maxlon, maxlat = point_at(lon, lat, 45, radius*2**0.5) 
			# find nodes within the bounding box
			idxs = list(self.rtree.intersection((minlon, 
					                             minlat, 
			                                     maxlon, 
			                                     maxlat)))
			# get distances
			dsts = min_geodetic_distance(lon, lat, 
			                             self.mesh.lons[idxs],
			                             self.mesh.lats[idxs])   
			jjj = numpy.nonzero(dsts < 50)[0]
			idxs = numpy.array(idxs)
			iii = idxs[jjj]
			# set values
			tmpvalues= numpy.exp(-dsts[jjj]/sigma**2)
			normfact = sum(tmpvalues)
			values[iii] += tmpvalues/normfact
		return values
Пример #5
0
 def get_indices(self, src, ridx, mag):
     """
     :param src: an UCERF source
     :param ridx: a set of rupture indices
     :param mag: magnitude to use to compute the integration distance
     :returns: array with the IDs of the sites close to the ruptures
     """
     centroids = src.get_centroids(ridx)
     mindistance = min_geodetic_distance(
         (centroids[:, 0], centroids[:, 1]), self.sitecol.xyz)
     idist = self.integration_distance(DEFAULT_TRT, mag)
     indices, = (mindistance <= idist).nonzero()
     return indices
Пример #6
0
 def get_background_sids(self, src_filter):
     """
     We can apply the filtering of the background sites as a pre-processing
     step - this is done here rather than in the sampling of the ruptures
     themselves
     """
     branch_key = self.idx_set["grid_key"]
     idist = src_filter.integration_distance(DEFAULT_TRT)
     with h5py.File(self.source_file, 'r') as hdf5:
         bg_locations = hdf5["Grid/Locations"].value
         distances = min_geodetic_distance(
             src_filter.sitecol.xyz,
             (bg_locations[:, 0], bg_locations[:, 1]))
         # Add buffer equal to half of length of median area from Mmax
         mmax_areas = self.msr.get_median_area(
             hdf5["/".join(["Grid", branch_key, "MMax"])].value, 0.0)
         # for instance hdf5['Grid/FM0_0_MEANFS_MEANMSR/MMax']
         mmax_lengths = numpy.sqrt(mmax_areas / self.aspect)
         ok = distances <= (0.5 * mmax_lengths + idist)
         # get list of indices from array of booleans
         return numpy.where(ok)[0].tolist()
Пример #7
0
    def get_joyner_boore_distance(self, mesh):
        """
        See :meth:`superclass' method
        <openquake.hazardlib.geo.surface.base.BaseQuadrilateralSurface.get_joyner_boore_distance>`.

        This is an optimized version specific to planar surface that doesn't
        make use of the mesh.
        """
        # we define four great circle arcs that contain four sides
        # of projected planar surface:
        #
        #       ↓     II    ↓
        #    I  ↓           ↓  I
        #       ↓     +     ↓
        #  →→→→→TL→→→→1→→→→TR→→→→→     → azimuth direction →
        #       ↓     -     ↓
        #       ↓           ↓
        # III  -3+   IV    -4+  III             ↓
        #       ↓           ↓            downdip direction
        #       ↓     +     ↓                   ↓
        #  →→→→→BL→→→→2→→→→BR→→→→→
        #       ↓     -     ↓
        #    I  ↓           ↓  I
        #       ↓     II    ↓
        #
        # arcs 1 and 2 are directed from left corners to right ones (the
        # direction has an effect on the sign of the distance to an arc,
        # as it shown on the figure), arcs 3 and 4 are directed from top
        # corners to bottom ones.
        #
        # then we measure distance from each of the points in a mesh
        # to each of those arcs and compare signs of distances in order
        # to find a relative positions of projections of points and
        # projection of a surface.
        #
        # then we consider four special cases (labeled with Roman numerals)
        # and either pick one of distances to arcs or a closest distance
        # to corner.
        #
        # indices 0, 2 and 1 represent corners TL, BL and TR respectively.
        arcs_lons = self.corner_lons.take([0, 2, 0, 1])
        arcs_lats = self.corner_lats.take([0, 2, 0, 1])
        downdip_azimuth = (self.strike + 90) % 360
        arcs_azimuths = [self.strike, self.strike,
                         downdip_azimuth, downdip_azimuth]
        mesh_lons = mesh.lons.reshape((-1, 1))
        mesh_lats = mesh.lats.reshape((-1, 1))
        # calculate distances from all the target points to all four arcs
        dists_to_arcs = geodetic.distance_to_arc(
            arcs_lons, arcs_lats, arcs_azimuths, mesh_lons, mesh_lats
        )
        # ... and distances from all the target points to each of surface's
        # corners' projections (we might not need all of those but it's
        # better to do that calculation once for all).
        dists_to_corners = geodetic.min_geodetic_distance(
            self.corner_lons, self.corner_lats,
            mesh.lons.flatten(), mesh.lats.flatten()
        )

        # extract from ``dists_to_arcs`` signs (represent relative positions
        # of an arc and a point: +1 means on the left hand side, 0 means
        # on arc and -1 means on the right hand side) and minimum absolute
        # values of distances to each pair of parallel arcs.
        ds1, ds2, ds3, ds4 = numpy.sign(dists_to_arcs).transpose()
        dists_to_arcs = numpy.abs(dists_to_arcs).reshape(-1, 2, 2).min(axis=-1)

        jb_dists = numpy.select(
            # consider four possible relative positions of point and arcs:
            condlist=[
                # signs of distances to both parallel arcs are the same
                # in both pairs, case "I" on a figure above
                (ds1 == ds2) & (ds3 == ds4),
                # sign of distances to two parallels is the same only
                # in one pair, case "II"
                ds1 == ds2,
                # ... or another (case "III")
                ds3 == ds4
                # signs are different in both pairs (this is a "default"),
                # case "IV"
            ],

            choicelist=[
                # case "I": closest distance is the closest distance to corners
                dists_to_corners,
                # case "II": closest distance is distance to arc "1" or "2",
                # whichever is closer
                dists_to_arcs[:, 0],
                # case "III": closest distance is distance to either
                # arc "3" or "4"
                dists_to_arcs[:, 1]
            ],

            # default -- case "IV"
            default=0
        )

        return jb_dists.reshape(mesh.lons.shape)
Пример #8
0
    def get_joyner_boore_distance(self, mesh):
        """
        Compute and return Joyner-Boore distance to each point of ``mesh``.
        Point's depth is ignored.

        See
        :meth:`openquake.hazardlib.geo.surface.base.BaseSurface.get_joyner_boore_distance`
        for definition of this distance.

        :returns:
            numpy array of distances in km of the same shape as ``mesh``.
            Distance value is considered to be zero if a point
            lies inside the polygon enveloping the projection of the mesh
            or on one of its edges.
        """
        # we perform a hybrid calculation (geodetic mesh-to-mesh distance
        # and distance on the projection plane for close points). first,
        # we find the closest geodetic distance for each point of target
        # mesh to this one. in general that distance is greater than
        # the exact distance to enclosing polygon of this mesh and it
        # depends on mesh spacing. but the difference can be neglected
        # if calculated geodetic distance is over some threshold.
        # get the highest slice from the 3D mesh
        distances = geodetic.min_geodetic_distance(
            (self.lons, self.lats), (mesh.lons, mesh.lats))
        # here we find the points for which calculated mesh-to-mesh
        # distance is below a threshold. this threshold is arbitrary:
        # lower values increase the maximum possible error, higher
        # values reduce the efficiency of that filtering. the maximum
        # error is equal to the maximum difference between a distance
        # from site to two adjacent points of the mesh and distance
        # from site to the line connecting them. thus the error is
        # a function of distance threshold and mesh spacing. the error
        # is maximum when the site lies on a perpendicular to the line
        # connecting points of the mesh and that passes the middle
        # point between them. the error then can be calculated as
        # ``err = trsh - d = trsh - \sqrt(trsh^2 - (ms/2)^2)``, where
        # ``trsh`` and ``d`` are distance to mesh points (the one
        # we found on the previous step) and distance to the line
        # connecting them (the actual distance) and ``ms`` is mesh
        # spacing. the threshold of 40 km gives maximum error of 314
        # meters for meshes with spacing of 10 km and 5.36 km for
        # meshes with spacing of 40 km. if mesh spacing is over
        # ``(trsh / \sqrt(2)) * 2`` then points lying in the middle
        # of mesh cells (that is inside the polygon) will be filtered
        # out by the threshold and have positive distance instead of 0.
        # so for threshold of 40 km mesh spacing should not be more
        # than 56 km (typical values are 5 to 10 km).
        idxs = (distances < 40).nonzero()[0]  # indices on the first dimension
        if not len(idxs):
            # no point is close enough, return distances as they are
            return distances

        # for all the points that are closer than the threshold we need
        # to recalculate the distance and set it to zero, if point falls
        # inside the enclosing polygon of the mesh. for doing that we
        # project both this mesh and the points of the second mesh--selected
        # by distance threshold--to the same Cartesian space, define
        # minimum shapely polygon enclosing the mesh and calculate point
        # to polygon distance, which gives the most accurate value
        # of distance in km (and that value is zero for points inside
        # the polygon).
        proj, polygon = self._get_proj_enclosing_polygon()
        if not isinstance(polygon, shapely.geometry.Polygon):
            # either line or point is our enclosing polygon. draw
            # a square with side of 10 m around in order to have
            # a proper polygon instead.
            polygon = polygon.buffer(self.DIST_TOLERANCE, 1)
        mesh_xx, mesh_yy = proj(mesh.lons[idxs], mesh.lats[idxs])
        # replace geodetic distance values for points-closer-than-the-threshold
        # by more accurate point-to-polygon distance values.
        distances[idxs] = geo_utils.point_to_polygon_distance(
            polygon, mesh_xx, mesh_yy)

        return distances