Source code for shakelib.utils.utils

import os
import json
import pkg_resources

import numpy as np
from shapely.geometry import Polygon, Point

from openquake.hazardlib.geo.utils import get_orthographic_projection

from shakelib.rupture.edge_rupture import EdgeRupture
from shakelib.rupture.quad_rupture import QuadRupture
from shakelib.rupture.base import Rupture


[docs]def get_extent(rupture): """ Method to compute map extent from rupture. Args: rupture (Rupture): A ShakeMap Rupture instance. Returns: tuple: lonmin, lonmax, latmin, latmax rounded to the nearest arc-minute.. """ if not rupture or not isinstance(rupture, Rupture): raise TypeError('get_extent() takes exactly 1 argument (0 given)') origin = rupture.getOrigin() if isinstance(rupture, (QuadRupture, EdgeRupture)): lats = rupture.lats lons = rupture.lons # Remove nans lons = lons[~np.isnan(lons)] lats = lats[~np.isnan(lats)] clat = 0.5 * (np.nanmax(lats) + np.nanmin(lats)) clon = 0.5 * (np.nanmax(lons) + np.nanmin(lons)) else: clat = origin.lat clon = origin.lon mag = origin.mag # Is this a stable or active tectonic event? # (this could be made an attribute of the ShakeMap Origin class) hypo = origin.getHypo() stable = is_stable(hypo.longitude, hypo.latitude) if stable is False: if mag < 6.48: mindist_km = 100. else: mindist_km = 27.24 * mag**2 - 250.4 * mag + 579.1 else: if mag < 6.10: mindist_km = 100. else: mindist_km = 63.4 * mag**2 - 465.4 * mag + 581.3 # Apply an upper limit on extent. This should only matter for large # magnitudes (> ~8.25) in stable tectonic environments. if mindist_km > 1000.: mindist_km = 1000. # Projection proj = get_orthographic_projection(clon - 4, clon + 4, clat + 4, clat - 4) if isinstance(rupture, (QuadRupture, EdgeRupture)): ruptx, rupty = proj(lons, lats) else: ruptx, rupty = proj(clon, clat) xmin = np.nanmin(ruptx) - mindist_km ymin = np.nanmin(rupty) - mindist_km xmax = np.nanmax(ruptx) + mindist_km ymax = np.nanmax(rupty) + mindist_km # Put a limit on range of aspect ratio dx = xmax - xmin dy = ymax - ymin ar = dy / dx if ar > 1.25: # Inflate x dx_target = dy / 1.25 ddx = dx_target - dx xmax = xmax + ddx / 2 xmin = xmin - ddx / 2 if ar < 0.6: # inflate y dy_target = dx * 0.6 ddy = dy_target - dy ymax = ymax + ddy / 2 ymin = ymin - ddy / 2 lonmin, latmin = proj(np.array([xmin]), np.array([ymin]), reverse=True) lonmax, latmax = proj(np.array([xmax]), np.array([ymax]), reverse=True) # # Round coordinates to the nearest minute -- that should make the # output grid register with common grid resolutions (60c, 30c, # 15c, 7.5c) # return _round_coord(lonmin[0]), _round_coord(lonmax[0]), \ _round_coord(latmin[0]), _round_coord(latmax[0])
def _round_coord(coord): """ Round a number to the nearest arc-minute """ dm = 1.0 / 60 mm = coord / dm imm = int(mm + 0.5) return imm * dm
[docs]def is_stable(lon, lat): """ Determine if point is located in the US stable tectonic region. Uses the same boundary as the US NSHMP and so this function needs to be modified to work outside of the US. Args: lon (float): Lognitude. lat (float): Latitude. Returns: bool: Is the point classified as tectonically stable. """ p = Point((lon, lat)) pfile = pkg_resources.resource_filename('shakelib.utils', os.path.join('data', 'cratons.geojson')) with open(pfile) as f: cratons = json.load(f) coord_list = cratons['features'][0]['geometry']['coordinates'] for clist in coord_list: poly = Polygon(clist[0]) if p.within(poly): return True return False