def _arrange_data_in_bins(bins_data, bin_edges): """ Given bins data, as it comes from :func:`_collect_bins_data`, and bin edges from :func:`_define_bins`, create a normalized 6d disaggregation matrix. """ (mags, dists, lons, lats, tect_reg_types, trt_bins, probs_one_or_more, probs_exceed_given_rup, src_idxs) = bins_data mag_bins, dist_bins, lon_bins, lat_bins, eps_bins, trt_bins = bin_edges shape = (len(mag_bins) - 1, len(dist_bins) - 1, len(lon_bins) - 1, len(lat_bins) - 1, len(eps_bins) - 1, len(trt_bins)) diss_matrix = numpy.zeros(shape) src_indices = numpy.unique(src_idxs) for i_mag in xrange(len(mag_bins) - 1): mag_idx = mags <= mag_bins[i_mag + 1] if i_mag != 0: mag_idx &= mags > mag_bins[i_mag] for i_dist in xrange(len(dist_bins) - 1): dist_idx = dists <= dist_bins[i_dist + 1] if i_dist != 0: dist_idx &= dists > dist_bins[i_dist] for i_lon in xrange(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 for i_lat in xrange(len(lat_bins) - 1): lat_idx = lats <= lat_bins[i_lat + 1] if i_lat != 0: lat_idx &= lats > lat_bins[i_lat] for i_eps in xrange(len(eps_bins) - 1): for i_trt in xrange(len(trt_bins)): trt_idx = tect_reg_types == i_trt diss_idx = (i_mag, i_dist, i_lon, i_lat, i_eps, i_trt) prob_idx = (mag_idx & dist_idx & lon_idx & lat_idx & trt_idx) poe = numpy.prod( (1 - probs_one_or_more[prob_idx]) ** probs_exceed_given_rup[prob_idx, i_eps] ) poe = 1 - poe diss_matrix[diss_idx] = poe return diss_matrix
def _arrange_data_in_bins(bins_data, bin_edges): """ Given bins data, as it comes from :func:`_collect_bins_data`, and bin edges from :func:`_define_bins`, create a normalized 6d disaggregation matrix. """ (mags, dists, lons, lats, tect_reg_types, trt_bins, probs_one_or_more, probs_exceed_given_rup, src_idxs) = bins_data mag_bins, dist_bins, lon_bins, lat_bins, eps_bins, trt_bins = bin_edges shape = (len(mag_bins) - 1, len(dist_bins) - 1, len(lon_bins) - 1, len(lat_bins) - 1, len(eps_bins) - 1, len(trt_bins)) diss_matrix = numpy.zeros(shape) src_indices = numpy.unique(src_idxs) for i_mag in xrange(len(mag_bins) - 1): mag_idx = mags <= mag_bins[i_mag + 1] if i_mag != 0: mag_idx &= mags > mag_bins[i_mag] for i_dist in xrange(len(dist_bins) - 1): dist_idx = dists <= dist_bins[i_dist + 1] if i_dist != 0: dist_idx &= dists > dist_bins[i_dist] for i_lon in xrange(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 for i_lat in xrange(len(lat_bins) - 1): lat_idx = lats <= lat_bins[i_lat + 1] if i_lat != 0: lat_idx &= lats > lat_bins[i_lat] for i_eps in xrange(len(eps_bins) - 1): for i_trt in xrange(len(trt_bins)): trt_idx = tect_reg_types == i_trt diss_idx = (i_mag, i_dist, i_lon, i_lat, i_eps, i_trt) prob_idx = (mag_idx & dist_idx & lon_idx & lat_idx & trt_idx) poe = numpy.prod( (1 - probs_one_or_more[prob_idx] )**probs_exceed_given_rup[prob_idx, i_eps]) poe = 1 - poe diss_matrix[diss_idx] = poe return diss_matrix
def _arrange_data_in_bins(bins_data, bin_edges): """ Given bins data, as it comes from :func:`_collect_bins_data`, and bin edges from :func:`_define_bins`, create a normalized 6d disaggregation matrix. """ mags, dists, lons, lats, joint_probs, tect_reg_types, trt_bins = bins_data mag_bins, dist_bins, lon_bins, lat_bins, eps_bins, trt_bins = bin_edges shape = (len(mag_bins) - 1, len(dist_bins) - 1, len(lon_bins) - 1, len(lat_bins) - 1, len(eps_bins) - 1, len(trt_bins)) diss_matrix = numpy.zeros(shape) for i_mag in xrange(len(mag_bins) - 1): mag_idx = mags <= mag_bins[i_mag + 1] if i_mag != 0: mag_idx &= mags > mag_bins[i_mag] for i_dist in xrange(len(dist_bins) - 1): dist_idx = dists <= dist_bins[i_dist + 1] if i_dist != 0: dist_idx &= dists > dist_bins[i_dist] for i_lon in xrange(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 for i_lat in xrange(len(lat_bins) - 1): lat_idx = lats <= lat_bins[i_lat + 1] if i_lat != 0: lat_idx &= lats > lat_bins[i_lat] for i_eps in xrange(len(eps_bins) - 1): for i_trt in xrange(len(trt_bins)): trt_idx = tect_reg_types == i_trt prob_idx = (mag_idx & dist_idx & lon_idx & lat_idx & trt_idx) diss_idx = (i_mag, i_dist, i_lon, i_lat, i_eps, i_trt) diss_matrix[diss_idx] = numpy.sum( joint_probs[prob_idx, i_eps] ) diss_matrix /= numpy.sum(diss_matrix) return diss_matrix
def _define_bins(bins_data, mag_bin_width, dist_bin_width, coord_bin_width, truncation_level, n_epsilons): """ Define bin edges for disaggregation histograms. Given bins data as provided by :func:`_collect_bins_data`, this function finds edges of histograms, taking into account maximum and minimum values of magnitude, distance and coordinates as well as requested sizes/numbers of bins. """ mags, dists, lons, lats, tect_reg_types, trt_bins, _ = bins_data mag_bins = mag_bin_width * numpy.arange( int(numpy.floor(mags.min() / mag_bin_width)), int(numpy.ceil(mags.max() / mag_bin_width) + 1) ) dist_bins = dist_bin_width * numpy.arange( int(numpy.floor(dists.min() / dist_bin_width)), int(numpy.ceil(dists.max() / dist_bin_width) + 1) ) west, east, north, south = get_spherical_bounding_box(lons, lats) west = numpy.floor(west / coord_bin_width) * coord_bin_width east = numpy.ceil(east / coord_bin_width) * coord_bin_width lon_extent = get_longitudinal_extent(west, east) lon_bins, _, _ = npoints_between(west, 0, 0, east, 0, 0, numpy.round(lon_extent / coord_bin_width + 1)) lat_bins = coord_bin_width * numpy.arange( int(numpy.floor(south / coord_bin_width)), int(numpy.ceil(north / coord_bin_width) + 1) ) eps_bins = numpy.linspace(-truncation_level, truncation_level, n_epsilons + 1) return mag_bins, dist_bins, lon_bins, lat_bins, eps_bins, trt_bins
def bins_edges(self, dist_bin_width, coord_bin_width): """ Define bin edges for disaggregation histograms, from the bin data collected from the ruptures. :param dists: array of distances from the ruptures :param lons: array of longitudes from the ruptures :param lats: array of latitudes from the ruptures :param dist_bin_width: distance_bin_width from job.ini :param coord_bin_width: coordinate_bin_width from job.ini """ dist_edges = dist_bin_width * numpy.arange( int(self.min_dist / dist_bin_width), int(numpy.ceil(self.max_dist / dist_bin_width) + 1)) west = numpy.floor(self.west / coord_bin_width) * coord_bin_width east = numpy.ceil(self.east / coord_bin_width) * coord_bin_width lon_extent = get_longitudinal_extent(west, east) lon_edges, _, _ = npoints_between( west, 0, 0, east, 0, 0, numpy.round(lon_extent / coord_bin_width) + 1) lat_edges = coord_bin_width * numpy.arange( int(numpy.floor(self.south / coord_bin_width)), int(numpy.ceil(self.north / coord_bin_width) + 1)) return dist_edges, lon_edges, lat_edges
def _define_bins(bins_data, mag_bin_width, dist_bin_width, coord_bin_width, truncation_level, n_epsilons): """ Define bin edges for disaggregation histograms. Given bins data as provided by :func:`_collect_bins_data`, this function finds edges of histograms, taking into account maximum and minimum values of magnitude, distance and coordinates as well as requested sizes/numbers of bins. """ mags, dists, lons, lats, tect_reg_types, trt_bins, _ = bins_data mag_bins = mag_bin_width * numpy.arange( int(numpy.floor(mags.min() / mag_bin_width)), int(numpy.ceil(mags.max() / mag_bin_width) + 1)) dist_bins = dist_bin_width * numpy.arange( int(numpy.floor(dists.min() / dist_bin_width)), int(numpy.ceil(dists.max() / dist_bin_width) + 1)) west, east, north, south = get_spherical_bounding_box(lons, lats) west = numpy.floor(west / coord_bin_width) * coord_bin_width east = numpy.ceil(east / coord_bin_width) * coord_bin_width lon_extent = get_longitudinal_extent(west, east) lon_bins, _, _ = npoints_between( west, 0, 0, east, 0, 0, numpy.round(lon_extent / coord_bin_width + 1)) lat_bins = coord_bin_width * numpy.arange( int(numpy.floor(south / coord_bin_width)), int(numpy.ceil(north / coord_bin_width) + 1)) eps_bins = numpy.linspace(-truncation_level, truncation_level, n_epsilons + 1) return mag_bins, dist_bins, lon_bins, lat_bins, eps_bins, trt_bins
def close_sids(self, src_or_rec, trt=None, maxdist=None): """ :param src_or_rec: a source or a rupture record :param trt: passed only if src_or_rec is a rupture record :returns: the site indices within the maximum_distance of the hypocenter, plus the maximum size of the bounding box """ assert self.sitecol is not None if not self.integration_distance: # do not filter return self.sitecol.sids if trt: # rupture proxy assert hasattr(self.integration_distance, 'x') dlon = get_longitudinal_extent(src_or_rec['minlon'], src_or_rec['maxlon']) / 2. dlat = (src_or_rec['maxlat'] - src_or_rec['minlat']) / 2. lon, lat, dep = src_or_rec['hypo'] dist = self.integration_distance( src_or_rec['mag']) + numpy.sqrt(dlon**2 + dlat**2) / KM_TO_DEGREES dist += 10 # added 10 km of buffer to guard against numeric errors # the test most sensitive to the buffer effect is in oq-risk-tests, # case_ucerf/job_eb.ini; without buffer, sites can be discarded # even if within the maximum_distance return self._close_sids(lon, lat, dep, dist) else: # source trt = src_or_rec.tectonic_region_type try: bbox = self.get_enlarged_box(src_or_rec, maxdist) except BBoxError: # do not filter return self.sitecol.sids return self.sitecol.within_bbox(bbox)
def close_sids(self, rec, trt): """ :param rec: a record with fields mag, minlon, minlat, maxlon, maxlat, hypo :param trt: tectonic region type string :returns: the site indices close to the given record, by considering as maximum radius the distance from the hypocenter (ignoring the depth) plus the half diagonal of the bounding box """ if self.sitecol is None: return [] elif not self.integration_distance: # do not filter return self.sitecol.sids if not hasattr(self, 'kdt'): self.kdt = cKDTree(self.sitecol.xyz) xyz = spherical_to_cartesian(*rec['hypo']) dlon = get_longitudinal_extent(rec['minlon'], rec['maxlon']) dlat = rec['maxlat'] - rec['minlat'] delta = max(dlon, dlat) / KM_TO_DEGREES maxradius = self.integration_distance(trt) + delta sids = U16(self.kdt.query_ball_point(xyz, maxradius, eps=.001)) sids.sort() return sids
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
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 xrange(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
def test_polygon_on_international_date_line(self): MESH_SPACING = 10 bl = geo.Point(177, 40) bml = geo.Point(179, 40) bmr = geo.Point(-179, 40) br = geo.Point(-177, 40) tr = geo.Point(-177, 43) tmr = geo.Point(-179, 43) tml = geo.Point(179, 43) tl = geo.Point(177, 43) poly = geo.Polygon([bl, bml, bmr, br, tr, tmr, tml, tl]) mesh = list(poly.discretize(mesh_spacing=MESH_SPACING)) west = east = mesh[0] for point in mesh: if geo_utils.get_longitudinal_extent(point.longitude, west.longitude) > 0: west = point if geo_utils.get_longitudinal_extent(point.longitude, east.longitude) < 0: east = point self.assertLess(west.longitude, 177.15) self.assertGreater(east.longitude, -177.15)
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
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
def lon_lat_bins(bb, coord_bin_width): """ Define lon, lat bin edges for disaggregation histograms. :param bb: bounding box west, south, east, north :param coord_bin_width: bin width """ west, south, east, north = bb west = numpy.floor(west / coord_bin_width) * coord_bin_width east = numpy.ceil(east / coord_bin_width) * coord_bin_width lon_extent = get_longitudinal_extent(west, east) lon_bins, _, _ = npoints_between( west, 0, 0, east, 0, 0, numpy.round(lon_extent / coord_bin_width + 1)) lat_bins = coord_bin_width * numpy.arange( int(numpy.floor(south / coord_bin_width)), int(numpy.ceil(north / coord_bin_width) + 1)) return lon_bins, lat_bins
def discretize(self, mesh_spacing): """ Get a mesh of uniformly spaced points inside the polygon area with distance of ``mesh_spacing`` km between. :returns: An instance of :class:`~openquake.hazardlib.geo.mesh.Mesh` that holds the points data. Mesh is created with no depth information (all the points are on the Earth surface). """ self._init_polygon2d() west, east, north, south = self._bbox lons = [] lats = [] # we cover the bounding box (in spherical coordinates) from highest # to lowest latitude and from left to right by longitude. we step # by mesh spacing distance (linear measure). we check each point # if it is inside the polygon and yield the point object, if so. # this way we produce an uniformly-spaced mesh regardless of the # latitude. latitude = north while latitude > south: longitude = west while utils.get_longitudinal_extent(longitude, east) > 0: # we use Cartesian space just for checking if a point # is inside of the polygon. x, y = self._projection(longitude, latitude) if self._polygon2d.contains(shapely.geometry.Point(x, y)): lons.append(longitude) lats.append(latitude) # move by mesh spacing along parallel... longitude, _, = geodetic.point_at(longitude, latitude, 90, mesh_spacing) # ... and by the same distance along meridian in outer one _, latitude = geodetic.point_at(west, latitude, 180, mesh_spacing) lons = numpy.array(lons) lats = numpy.array(lats) return Mesh(lons, lats, depths=None)
def lon_lat_bins(bb, coord_bin_width): """ Define bin edges for disaggregation histograms. Given bins data as provided by :func:`collect_bin_data`, this function finds edges of histograms, taking into account maximum and minimum values of magnitude, distance and coordinates as well as requested sizes/numbers of bins. """ west, south, east, north = bb west = numpy.floor(west / coord_bin_width) * coord_bin_width east = numpy.ceil(east / coord_bin_width) * coord_bin_width lon_extent = get_longitudinal_extent(west, east) lon_bins, _, _ = npoints_between( west, 0, 0, east, 0, 0, numpy.round(lon_extent / coord_bin_width + 1)) lat_bins = coord_bin_width * numpy.arange( int(numpy.floor(south / coord_bin_width)), int(numpy.ceil(north / coord_bin_width) + 1)) return lon_bins, lat_bins
def close_sids(self, src_or_rec, trt=None): """ :param src_or_rec: a source or a rupture record :param trt: passed only if src_or_rec is a rupture record :returns: the site indices within the maximum_distance of the hypocenter, plus the maximum size of the bounding box """ if self.sitecol is None: return [] elif not self.integration_distance: # do not filter return self.sitecol.sids if not hasattr(self, 'kdt'): self.kdt = cKDTree(self.sitecol.xyz) if trt: # rupture, called by GmfGetter.gen_computers dlon = get_longitudinal_extent( src_or_rec['minlon'], src_or_rec['maxlon']) / 2. dlat = (src_or_rec['maxlat'] - src_or_rec['minlat']) / 2. lon, lat, dep = src_or_rec['hypo'] dist = self.integration_distance(trt) + numpy.sqrt( dlon**2 + dlat**2) / KM_TO_DEGREES dist += 10 # added 10 km of buffer to guard against numeric errors # the test most sensitive to the buffer effect is in oq-risk-tests, # case_ucerf/job_eb.ini; without buffer, sites can be discarded # even if within the maximum_distance else: # source trt = src_or_rec.tectonic_region_type try: bbox = self.integration_distance.get_enlarged_box(src_or_rec) except BBoxError: # do not filter return self.sitecol.sids dlon, dlat = (bbox[2] - bbox[0]) / 2., (bbox[3] - bbox[1]) / 2. lon, lat, dep = ( (bbox[2] + bbox[0]) / 2., (bbox[3] + bbox[1]) / 2, 0) dist = numpy.sqrt(dlon**2 + dlat**2) / KM_TO_DEGREES xyz = spherical_to_cartesian(lon, lat, dep) sids = U32(self.kdt.query_ball_point(xyz, dist, eps=.001)) sids.sort() return sids
def test_positive(self): self.assertEqual(utils.get_longitudinal_extent(10, 20), 10) self.assertEqual(utils.get_longitudinal_extent(-120, 30), 150)
def test_negative(self): self.assertEqual(utils.get_longitudinal_extent(20, 10), -10) self.assertEqual(utils.get_longitudinal_extent(-10, -15), -5)
def test_international_date_line(self): self.assertEqual(utils.get_longitudinal_extent(-178.3, 177.7), -4) self.assertEqual(utils.get_longitudinal_extent(177.7, -178.3), 4) self.assertEqual(utils.get_longitudinal_extent(95, -180 + 94), 179) self.assertEqual(utils.get_longitudinal_extent(95, -180 + 96), -179)