def within_bbox(self, bbox): """ :param bbox: a quartet (min_lon, min_lat, max_lon, max_lat) :returns: site IDs within the bounding box """ min_lon, min_lat, max_lon, max_lat = bbox lons, lats = self.array['lon'], self.array['lat'] if cross_idl(lons.min(), lons.max()) or cross_idl(min_lon, max_lon): lons = lons % 360 min_lon, max_lon = min_lon % 360, max_lon % 360 mask = (min_lon < lons) * (lons < max_lon) * \ (min_lat < lats) * (lats < max_lat) return mask.nonzero()[0]
def within_bbox(self, bbox): """ :param bbox: a quartet (min_lon, min_lat, max_lon, max_lat) :returns: a filtered SiteCollection within the bounding box or None """ min_lon, min_lat, max_lon, max_lat = bbox arr = self.array if self.indices is None else self.array[self.indices] lons, lats = arr['lons'], arr['lats'] if cross_idl(lons.min(), lons.max()) or cross_idl(min_lon, max_lon): lons = lons % 360 min_lon, max_lon = min_lon % 360, max_lon % 360 mask = (min_lon < lons) * (lons < max_lon) * \ (min_lat < lats) * (lats < max_lat) return self.filter(mask)
def within_bbox(self, srcs): """ :param srcs: a list of source objects :returns: the site IDs within the enlarged bounding box of the sources """ if self.sitecol is None: # for test_case_1_ruptures return [0] lons = [] lats = [] for src in srcs: try: box = self.integration_distance.get_affected_box(src) except BBoxError as exc: logging.error(exc) continue lons.append(box[0]) lats.append(box[1]) lons.append(box[2]) lats.append(box[3]) if cross_idl(*(list(self.sitecol.lons) + lons)): lons = numpy.array(lons) % 360 else: lons = numpy.array(lons) bbox = (lons.min(), min(lats), lons.max(), max(lats)) if bbox[2] - bbox[0] > 180: raise BBoxError( 'The bounding box of the sources is larger than half ' 'the globe: %d degrees' % (bbox[2] - bbox[0])) return self.sitecol.within_bbox(bbox)
def plot_sites(calc_id=-1): """ Plot the sites and the bounding boxes of the sources, enlarged by the maximum distance """ # NB: matplotlib is imported inside since it is a costly import import matplotlib.pyplot as p from matplotlib.patches import Rectangle logging.basicConfig(level=logging.INFO) dstore = datastore.read(calc_id) sitecol = dstore['sitecol'] lons, lats = sitecol.lons, sitecol.lats sources = dstore['source_info'].value source_geom = dstore['source_geom'].value fig, ax = p.subplots() ax.grid(True) rects = [get_rectangle(src, source_geom[src['gidx1']:src['gidx2']]) for src in sources] lonset = set(lons) for ((lon, lat), width, height) in rects: lonset.add(lon) lonset.add(fix_lon(lon + width)) idl = cross_idl(min(lonset), max(lonset)) if idl: lons = lons % 360 for ((lon, lat), width, height) in rects: lonlat = (lon % 360 if idl else lon, lat) ax.add_patch(Rectangle(lonlat, width, height, fill=False)) # NB: the code below could be restored in the future # if hasattr(src.__class__, 'polygon'): # xs, ys = fix_polygon(src.polygon, idl) # p.plot(xs, ys, marker='.') p.scatter(lons, lats, marker='+') p.show()
def get_bbox(self): """ Returns a simple 2D bounding box from the extrema of lons and lats """ min_lon, max_lon = self.lons.min(), self.lons.max() if utils.cross_idl(min_lon, max_lon): lons = self.lons % 360 min_lon, max_lon = lons.min(), lons.max() return (min_lon, self.lats.min(), max_lon, self.lats.max())
def __init__(self, sitecol, maximum_distance): self.sitecol = sitecol self.maximum_distance = maximum_distance # determine the bounding box by taking into account the IDL self.cross_idl = cross_idl(sitecol.lons.min(), sitecol.lons.max()) lons = self.fix_lons(sitecol.lons) self.min_lon, self.max_lon = lons.min(), lons.max() self.min_lat, self.max_lat = ( self.sitecol.lats.min(), self.sitecol.lats.max())
def __init__(self, sitecol, maximum_distance): self.sitecol = sitecol self.maximum_distance = maximum_distance # determine the bounding box by taking into account the IDL self.cross_idl = cross_idl(sitecol.lons.min(), sitecol.lons.max()) lons = self.fix_lons(sitecol.lons) self.min_lon, self.max_lon = lons.min(), lons.max() self.min_lat, self.max_lat = (self.sitecol.lats.min(), self.sitecol.lats.max())
def main(calc_id: int = -1, site_model=False): """ Plot the sites and the assets """ # NB: matplotlib is imported inside since it is a costly import import matplotlib.pyplot as p from openquake.hmtk.plotting.patch import PolygonPatch dstore = util.read(calc_id) try: region = dstore['oqparam'].region except KeyError: region = None sitecol = dstore['sitecol'] try: assetcol = dstore['assetcol'][()] except AttributeError: assetcol = dstore['assetcol'].array fig = p.figure() ax = fig.add_subplot(111) if region: pp = PolygonPatch(shapely.wkt.loads(region), alpha=0.1) ax.add_patch(pp) ax.grid(True) if site_model and 'site_model' in dstore: sm = dstore['site_model'] sm_lons, sm_lats = sm['lon'], sm['lat'] if len(sm_lons) > 1 and cross_idl(*sm_lons): sm_lons %= 360 p.scatter(sm_lons, sm_lats, marker='.', color='orange', label='site model') # p.scatter(sitecol.complete.lons, sitecol.complete.lats, marker='.', # color='gray', label='grid') p.scatter(assetcol['lon'], assetcol['lat'], marker='.', color='green', label='assets') p.scatter(sitecol.lons, sitecol.lats, marker='+', color='black', label='sites') if 'discarded' in dstore: disc = numpy.unique(dstore['discarded']['lon', 'lat']) p.scatter(disc['lon'], disc['lat'], marker='x', color='red', label='discarded') ax.legend() p.show()
def plot_sites(calc_id=-1): """ Plot the sites """ # NB: matplotlib is imported inside since it is a costly import import matplotlib.pyplot as p dstore = util.read(calc_id) sitecol = dstore['sitecol'] lons, lats = sitecol.lons, sitecol.lats if len(lons) > 1 and cross_idl(*lons): lons %= 360 fig, ax = p.subplots() ax.grid(True) if 'site_model' in dstore: sm = dstore['site_model'] sm_lons, sm_lats = sm['lon'], sm['lat'] if len(sm_lons) > 1 and cross_idl(*sm_lons): sm_lons %= 360 p.scatter(sm_lons, sm_lats, marker='.', color='orange') p.scatter(lons, lats, marker='+') p.show()
def plot_sites(calc_id=-1): """ Plot the sites and the bounding boxes of the sources, enlarged by the maximum distance """ # NB: matplotlib is imported inside since it is a costly import import matplotlib.pyplot as p logging.basicConfig(level=logging.INFO) dstore = engine.read(calc_id) sitecol = dstore['sitecol'] lons, lats = sitecol.lons, sitecol.lats if len(lons) > 1 and cross_idl(*lons): lons %= 360 fig, ax = p.subplots() ax.grid(True) if 'site_model' in dstore: sm = dstore['site_model'] sm_lons, sm_lats = sm['lon'], sm['lat'] if len(sm_lons) > 1 and cross_idl(*sm_lons): sm_lons %= 360 p.scatter(sm_lons, sm_lats, marker='.', color='orange') p.scatter(lons, lats, marker='+') p.show()
def make_figure_sources(extractors, what): """ $ oq plot "sources?limit=100" $ oq plot "sources?source_id=1&source_id=2" $ oq plot "sources?code=A&code=N" """ # NB: matplotlib is imported inside since it is a costly import import matplotlib.pyplot as plt [ex] = extractors info = ex.get(what) wkts = gzip.decompress(info.wkt_gz).decode('utf8').split(';') srcs = gzip.decompress(info.src_gz).decode('utf8').split(';') fig, ax = plt.subplots() ax.grid(True) sitecol = ex.get('sitecol') pp = PolygonPlotter(ax) n = 0 tot = 0 psources = [] for rec, srcid, wkt in zip(info, srcs, wkts): if not wkt: logging.warning('No geometries for source id %s', srcid) continue if rec['eff_ruptures']: # not filtered out color = 'green' alpha = .3 n += 1 else: color = 'yellow' alpha = .1 if wkt.startswith('POINT'): psources.append(shapely.wkt.loads(wkt)) else: pp.add(shapely.wkt.loads(wkt), alpha=alpha, color=color) tot += 1 lons = [p.x for p in psources] lats = [p.y for p in psources] ss_lons = lons + list(sitecol['lon']) # sites + sources longitudes ss_lats = lats + list(sitecol['lat']) # sites + sources latitudes if len(ss_lons) > 1 and cross_idl(*ss_lons): ss_lons = [lon % 360 for lon in ss_lons] lons = [lon % 360 for lon in lons] sitecol['lon'] = sitecol['lon'] % 360 ax.plot(sitecol['lon'], sitecol['lat'], '.') ax.plot(lons, lats, 'o') pp.set_lim(ss_lons, ss_lats) ax.set_title('%d/%d sources' % (n, tot)) return plt
def get_bounding_box(self, integration_distance): """ Bounding box containing all points, enlarged by the maximum distance and the maximum rupture projection radius (upper limit). """ maxradius = self._get_max_rupture_projection_radius() min_lon = self.mesh.lons.min() max_lon = self.mesh.lons.max() if cross_idl(min_lon, max_lon): min_lon, max_lon = max_lon, min_lon + 360 min_lat = self.mesh.lats.min() max_lat = self.mesh.lats.max() a1 = (integration_distance + maxradius) * KM_TO_DEGREES a2 = max(angular_distance(integration_distance + maxradius, min_lat), angular_distance(integration_distance + maxradius, max_lat)) return min_lon - a2, min_lat - a1, max_lon + a2, max_lat + a1
def get_bounding_box(self, maxdist): """ Bounding box containing all points, enlarged by the maximum distance and the maximum rupture projection radius (upper limit). """ maxradius = self._get_max_rupture_projection_radius() min_lon = self.mesh.lons.min() max_lon = self.mesh.lons.max() if cross_idl(min_lon, max_lon): min_lon, max_lon = max_lon, min_lon + 360 min_lat = self.mesh.lats.min() max_lat = self.mesh.lats.max() a1 = (maxdist + maxradius) * KM_TO_DEGREES a2 = max(angular_distance(maxdist + maxradius, min_lat), angular_distance(maxdist + maxradius, max_lat)) return min_lon - a2, min_lat - a1, max_lon + a2, max_lat + a1
def within_bbox(self, bbox): """ :param bbox: a quartet (min_lon, min_lat, max_lon, max_lat) :returns: a filtered SiteCollection within the bounding box """ min_lon, min_lat, max_lon, max_lat = bbox if cross_idl(min_lon, max_lon): raise ValueError('Crossing the International Date Line is ' 'not supported yet') mask = numpy.array([ min_lon < rec['lons'] < max_lon and min_lat < rec['lats'] < max_lat for rec in self.array[self.indices] ]) if not mask.any(): raise Exception('There are no sites within the boundind box %s' % str(bbox)) return self.filter(mask)
def _check_csm(csm, oqparam, h5): # checks csm.gsim_lt.check_imts(oqparam.imtls) srcs = csm.get_sources() if not srcs: raise RuntimeError('All sources were discarded!?') if os.environ.get('OQ_CHECK_INPUT'): source.check_complex_faults(srcs) # build a smart SourceFilter try: sitecol = get_site_collection(oqparam, h5) # already stored except Exception: # missing sites.csv in test_case_1_ruptures sitecol = None csm.sitecol = sitecol if sitecol is None: return srcfilter = SourceFilter(sitecol, oqparam.maximum_distance) logging.info('Checking the sources bounding box') lons = [] lats = [] for src in srcs: try: box = srcfilter.get_enlarged_box(src) except BBoxError as exc: logging.error(exc) continue lons.append(box[0]) lats.append(box[1]) lons.append(box[2]) lats.append(box[3]) if cross_idl(*(list(sitecol.lons) + lons)): lons = numpy.array(lons) % 360 else: lons = numpy.array(lons) bbox = (lons.min(), min(lats), lons.max(), max(lats)) if bbox[2] - bbox[0] > 180: raise BBoxError( 'The bounding box of the sources is larger than half ' 'the globe: %d degrees' % (bbox[2] - bbox[0])) sids = sitecol.within_bbox(bbox) if len(sids) == 0: raise RuntimeError('All sources were discarded!?')
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 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)) if cross_idl(*lon_bins): lon_bins %= 360 return lon_bins, lat_bins
def lon_lat_bins(lon, lat, size_km, coord_bin_width): """ Define lon, lat bin edges for disaggregation histograms. :param lon: longitude of the site :param lat: latitude of the site :param size_km: total size of the bins in km :param coord_bin_width: bin width in degrees :returns: two arrays lon bins, lat bins """ nbins = numpy.ceil(size_km * KM_TO_DEGREES / coord_bin_width) delta_lon = min(angular_distance(size_km, lat), 180) delta_lat = min(size_km * KM_TO_DEGREES, 90) EPS = .001 # avoid discarding the last edgebdata.pnes.shape lon_bins = lon + numpy.arange(-delta_lon, delta_lon + EPS, delta_lon / nbins) lat_bins = lat + numpy.arange(-delta_lat, delta_lat + EPS, delta_lat / nbins) if cross_idl(*lon_bins): lon_bins %= 360 return lon_bins, lat_bins
def plot_sites(calc_id=-1): """ Plot the sites and the bounding boxes of the sources, enlarged by the maximum distance """ # NB: matplotlib is imported inside since it is a costly import import matplotlib.pyplot as p from matplotlib.patches import Rectangle logging.basicConfig(level=logging.INFO) dstore = datastore.read(calc_id) oq = dstore['oqparam'] sitecol = dstore['sitecol'] lons, lats = sitecol.lons, sitecol.lats srcfilter = SourceFilter(sitecol.complete, oq.maximum_distance) csm = readinput.get_composite_source_model(oq).pfilter( srcfilter, oq.concurrent_tasks) sources = csm.get_sources() if len(sources) > 100: logging.info('Sampling 100 sources of %d', len(sources)) sources = random.Random(42).sample(sources, 100) fig, ax = p.subplots() ax.grid(True) rects = [srcfilter.get_rectangle(src) for src in sources] lonset = set(lons) for ((lon, lat), width, height) in rects: lonset.add(lon) lonset.add(fix_lon(lon + width)) idl = cross_idl(min(lonset), max(lonset)) if idl: lons = lons % 360 for src, ((lon, lat), width, height) in zip(sources, rects): lonlat = (lon % 360 if idl else lon, lat) ax.add_patch(Rectangle(lonlat, width, height, fill=False)) if hasattr(src.__class__, 'polygon'): xs, ys = fix_polygon(src.polygon, idl) p.plot(xs, ys, marker='.') p.scatter(lons, lats, marker='+') p.show()
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 plot_assets(calc_id=-1, site_model=False): """ Plot the sites and the assets """ # NB: matplotlib is imported inside since it is a costly import import matplotlib.pyplot as p from openquake.hmtk.plotting.patch import PolygonPatch dstore = util.read(calc_id) try: region = dstore['oqparam'].region except KeyError: region = None sitecol = dstore['sitecol'] try: assetcol = dstore['assetcol'].value except AttributeError: assetcol = dstore['assetcol'].array fig = p.figure() ax = fig.add_subplot(111) if region: pp = PolygonPatch(shapely.wkt.loads(region), alpha=0.1) ax.add_patch(pp) ax.grid(True) if site_model and 'site_model' in dstore: sm = dstore['site_model'] sm_lons, sm_lats = sm['lon'], sm['lat'] if len(sm_lons) > 1 and cross_idl(*sm_lons): sm_lons %= 360 p.scatter(sm_lons, sm_lats, marker='.', color='orange') p.scatter(sitecol.complete.lons, sitecol.complete.lats, marker='.', color='gray') p.scatter(assetcol['lon'], assetcol['lat'], marker='.', color='green') p.scatter(sitecol.lons, sitecol.lats, marker='+', color='black') if 'discarded' in dstore: disc = numpy.unique(dstore['discarded'].value[['lon', 'lat']]) p.scatter(disc['lon'], disc['lat'], marker='x', color='red') p.show()
def cross(lonlat, width, height): return cross_idl(lonlat[0], lonlat[0] + width)