def test_LAX_to_JFK(self): dist = geodetic.geodetic_distance(*(LAX + JFK)) self.assertAlmostEqual(dist, 0.623585 * geodetic.EARTH_RADIUS, delta=0.1) dist2 = geodetic.geodetic_distance(*(JFK + LAX)) self.assertAlmostEqual(dist, dist2)
def _plot_volc(axes, csda): """ :parameter axes: :parameter csda: """ if csda.volc is None: return olo = csda.csec.olo ola = csda.csec.ola patches = [] if (len(csda.volc)-1) >= 1: vuls = geodetic_distance(olo, ola, csda.volc[:, 0], csda.volc[:, 1]) for v in vuls: square = Rectangle((v, -10.0), 7, 12) patches.append(square) else: vuls = geodetic_distance(olo, ola, csda.volc[0], csda.volc[1]) square = Rectangle((vuls, -10.0), 7, 12) patches.append(square) vv = PatchCollection(patches, zorder=6, color='red', edgecolors='red') vv.set_alpha(0.85) axes.add_collection(vv)
def test_one_to_many(self): dist = geodetic.geodetic_distance(0, 0, [-1, 1], [0, 0]) self.assertTrue(numpy.allclose(dist, [111.195, 111.195]), str(dist)) dist = geodetic.geodetic_distance(0, 0, [[-1, 0], [1, 0]], [[0, 0], [0, 0]]) self.assertTrue(numpy.allclose(dist, [[111.195, 0], [111.195, 0]]), str(dist))
def inc_stations(j,i,N,K,r,site_collection_SM, site_collection_station, dist_mat, X, inc_ind): """ If there are stations included within the radius for a point, this function will add those stations to the distance matrix and determine the array of points included in the radius, x INPUTS: i,j- current points row and column N,K - number of points in row and total number of stations r- radius site_collection_SM/station- site collections for ShakeMap and station data dist_mat- reduced distance matrix X- array of previously calculated correlation values inc_ind- indices of included points inc_indices- total number of points in the top most row of distance matrix OUTPUTS: dist_mat- reduced distance matrix, modified to include stations x- array of points in X included in radius and stations included inc_sta_indices- indices of stations included in the radius """ # Compute the distances for all stations to the grid point we're looking at dist_sta_sit = np.array(geodetic_distance(site_collection_SM.lons[j+i*N], site_collection_SM.lats[j+i*N], site_collection_station.lons[0:K], site_collection_station.lats[0:K])) # Find which of those stations are in the radius we are considering inc_sta_indices = np.where(dist_sta_sit < r)[0] if np.size(inc_sta_indices) != 0: sta_to_sta_dist = np.zeros([np.size(inc_sta_indices), np.size(inc_sta_indices)]) sta_to_grd_dist = np.zeros([np.size(inc_sta_indices), np.size(inc_ind)]) iinds = np.array(inc_ind).T[0] # Calculate distance between each included station and all included grid points, then calculate the distance # from each included station to every other included station for eta in range(0, np.size(inc_sta_indices)): sta_to_grd_dist[eta, :] = geodetic_distance( site_collection_station.lons[inc_sta_indices[eta]], site_collection_station.lats[inc_sta_indices[eta]], site_collection_SM.lons[iinds], site_collection_SM.lats[iinds]) sta_to_sta_dist[eta, eta+1:] = geodetic_distance( site_collection_station.lons[inc_sta_indices[eta]], site_collection_station.lats[inc_sta_indices[eta]], site_collection_station.lons[inc_sta_indices[eta+1:]], site_collection_station.lats[inc_sta_indices[eta+1:]]) sta_to_sta_dist = sta_to_sta_dist + sta_to_sta_dist.T station_distance_matrix = np.concatenate((sta_to_sta_dist, sta_to_grd_dist), axis=1) # Concatenate the station distance matrix with the modified distance matrix, dist_mat dist_mat = np.concatenate((station_distance_matrix[:, np.size(inc_sta_indices):], dist_mat), axis=0) dist_mat = np.concatenate((station_distance_matrix.T, dist_mat), axis=1) # x: vector of previously calculated covariance values x = np.concatenate((np.zeros([np.size(inc_sta_indices),1]),X[inc_ind,0]), axis = 0) x = np.mat(x[0:-1]) else: # x: vector of previously calculated covariance values x = X[inc_ind,0] x = np.mat(x[0:-1]) return {'dist_mat':dist_mat, 'x':x, 'inc_sta_indices':inc_sta_indices}
def inc_stations(j,i,N,K,r,site_collection_SM, site_collection_station, dist_mat, X, inc_ind, inc_indices): ##### # If there are stations included within the radius for a point, this function will add those stations to the # distance matrix and determine the array of points included in the radius, x # IN: i,j- current points row and column # N,K - number of points in row and total number of stations # r- radius # site_collection_SM/station- site collections for ShakeMap and station data # dist_mat- reduced distance matrix # X- array of previously calculated correlation values # inc_ind- indices of included points # inc_indices- total number of points in the top most row of distance matrix #OUT: dist_mat- reduced distance matrix, modified to include stations # x- array of points in X included in radius and stations included # inc_sta_indices- indices of stations included in the radius ##### num = i*N+j # Compute the distances for all stations to the grid point we're looking at dist_sta_sit = np.array(geodetic_distance(site_collection_SM.lons[j+i*N], site_collection_SM.lats[j+i*N], site_collection_station.lons[0:K], site_collection_station.lats[0:K])) # Find which of those stations are in the radius we are considering inc_sta_indices = np.where(dist_sta_sit < r) if np.size(inc_sta_indices) != 0: station_distance_matrix = np.zeros([np.size(inc_sta_indices), np.size(inc_sta_indices)+np.size(inc_ind)]) # Calculate distance between each included station and all included grid points, then calculate the distance # from each included station to every other included station for eta in range(0, np.size(inc_sta_indices)): for beta in range(0,np.size(inc_ind)): station_distance_matrix[eta,np.size(inc_sta_indices) + beta] = geodetic_distance( site_collection_station.lons[inc_sta_indices[0][eta]], site_collection_station.lats[inc_sta_indices[0][eta]], site_collection_SM.lons[inc_ind[beta]], site_collection_SM.lats[inc_ind[beta]]) for beta in range(0, np.size(inc_sta_indices)): station_distance_matrix[eta, beta] = geodetic_distance( site_collection_station.lons[inc_sta_indices[0][eta]], site_collection_station.lats[inc_sta_indices[0][eta]], site_collection_station.lons[inc_sta_indices[0][beta]], site_collection_station.lats[inc_sta_indices[0][beta]]) # Concatenate the station distance matrix with the modified distance matrix, dist_mat dist_mat = np.concatenate((station_distance_matrix[:, np.size(inc_sta_indices):], dist_mat), axis=0) dist_mat = np.concatenate((station_distance_matrix.T, dist_mat), axis=1) # x: vector of previously calculated covariance values x = np.concatenate((np.zeros([np.size(inc_sta_indices),1]),X[inc_ind,0]), axis = 0) x = np.mat(x[0:-1]) else: # x: vector of previously calculated covariance values x = X[inc_ind,0] x = np.mat(x[0:-1]) return {'dist_mat':dist_mat, 'x':x, 'inc_sta_indices':inc_sta_indices}
def test_get_area(self): computed = self.msrf.get_area() length = geodetic_distance(0.0, 0.0, 0.3, 0.0) expected = length * 20.0 perc_diff = abs(computed - expected) / computed * 100 msg = 'Multi fault surface: area is wrong' self.assertTrue(perc_diff < 2, msg=msg)
def get_distance_matrix(self): """ Compute and return distances between each pairs of points in the mesh. This method requires that all the points lie on Earth surface (have zero depth) and coordinate arrays are one-dimensional. .. warning:: Because of its quadratic space and time complexity this method is safe to use for meshes of up to several thousand points. For mesh of 10k points it needs ~800 Mb for just the resulting matrix and four times that much for intermediate storage. :returns: Two-dimensional numpy array, square matrix of distances. The matrix has zeros on main diagonal and positive distances in kilometers on all other cells. That is, value in cell (3, 5) is the distance between mesh's points 3 and 5 in km, and it is equal to value in cell (5, 3). Uses :func:`openquake.hazardlib.geo.geodetic.geodetic_distance`. """ assert self.lons.ndim == 1 assert self.depths is None or (self.depths == 0).all() distances = geodetic.geodetic_distance( self.lons.reshape(self.lons.shape + (1, )), self.lats.reshape(self.lats.shape + (1, )), self.lons, self.lats) return numpy.matrix(distances, copy=False)
def average_azimuth(self): """ Calculate and return weighted average azimuth of all line's segments in decimal degrees. Uses formula from http://en.wikipedia.org/wiki/Mean_of_circular_quantities >>> from openquake.hazardlib.geo.point import Point as P >>> str(Line([P(0, 0), P(1e-5, 1e-5)]).average_azimuth()) '45.0' >>> str(Line([P(0, 0), P(0, 1e-5), P(1e-5, 1e-5)]).average_azimuth()) '45.0' >>> line = Line([P(0, 0), P(-2e-5, 0), P(-2e-5, 1.154e-5)]) >>> '%.1f' % line.average_azimuth() '300.0' """ if len(self.points) == 2: return self.points[0].azimuth(self.points[1]) lons = numpy.array([point.longitude for point in self.points]) lats = numpy.array([point.latitude for point in self.points]) azimuths = geodetic.azimuth(lons[:-1], lats[:-1], lons[1:], lats[1:]) distances = geodetic.geodetic_distance(lons[:-1], lats[:-1], lons[1:], lats[1:]) azimuths = numpy.radians(azimuths) # convert polar coordinates to Cartesian ones and calculate # the average coordinate of each component avg_x = numpy.mean(distances * numpy.sin(azimuths)) avg_y = numpy.mean(distances * numpy.cos(azimuths)) # find the mean azimuth from that mean vector azimuth = numpy.degrees(numpy.arctan2(avg_x, avg_y)) if azimuth < 0: azimuth += 360 return azimuth
def get_xyz_from_ll(projected, reference): """ This method computes the x, y and z coordinates of a set of points provided a reference point :param projected: :class:`~openquake.hazardlib.geo.point.Point` object representing the coordinates of target point to be projected :param reference: :class:`~openquake.hazardlib.geo.point.Point` object representing the coordinates of the reference point. :returns: x y z """ azims = geod.azimuth(reference.longitude, reference.latitude, projected.longitude, projected.latitude) depths = np.subtract(reference.depth, projected.depth) dists = geod.geodetic_distance(reference.longitude, reference.latitude, projected.longitude, projected.latitude) return (dists * math.sin(math.radians(azims)), dists * math.cos(math.radians(azims)), depths)
def translate(self, p1, p2): """ Translate the surface for a specific distance along a specific azimuth direction. Parameters are two points (instances of :class:`openquake.hazardlib.geo.point.Point`) representing the direction and an azimuth for translation. The resulting surface corner points will be that far along that azimuth from respective corner points of this surface as ``p2`` is located with respect to ``p1``. :returns: A new :class:`PlanarSurface` object with the same mesh spacing, dip, strike, width, length and depth but with corners longitudes and latitudes translated. """ azimuth = geodetic.azimuth(p1.longitude, p1.latitude, p2.longitude, p2.latitude) distance = geodetic.geodetic_distance(p1.longitude, p1.latitude, p2.longitude, p2.latitude) # avoid calling PlanarSurface's constructor nsurf = object.__new__(PlanarSurface) # but do call BaseQuadrilateralSurface's one BaseQuadrilateralSurface.__init__(nsurf) nsurf.mesh_spacing = self.mesh_spacing nsurf.dip = self.dip nsurf.strike = self.strike nsurf.corner_lons, nsurf.corner_lats = geodetic.point_at( self.corner_lons, self.corner_lats, azimuth, distance ) nsurf.corner_depths = self.corner_depths.copy() nsurf._init_plane() nsurf.width = self.width nsurf.length = self.length return nsurf
def distance_to_mesh(self, mesh, with_depths=True): """ Compute distance (in km) between this point and each point of ``mesh``. :param mesh: :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate distance to. :param with_depths: If ``True`` (by default), distance is calculated between actual point and the mesh, geodetic distance of projections is combined with vertical distance (difference of depths). If this is set to ``False``, only geodetic distance between projections is calculated. :returns: Numpy array of floats of the same shape as ``mesh`` with distance values in km in respective indices. """ if with_depths: if mesh.depths is None: mesh_depths = numpy.zeros_like(mesh.lons) else: mesh_depths = mesh.depths return geodetic.distance(self.longitude, self.latitude, self.depth, mesh.lons, mesh.lats, mesh_depths) else: return geodetic.geodetic_distance(self.longitude, self.latitude, mesh.lons, mesh.lats)
def _plot_eqks(axes, csda): """ :parameter axes: :parameter csda: """ if csda.ecat is None: return newcat = csda.ecat olo = csda.csec.olo ola = csda.csec.ola dsts = geodetic_distance(olo, ola, newcat.data['longitude'], newcat.data['latitude']) # MN: 'sze' assigned but never used sze = (newcat.data['magnitude'])**0.5 patches = [] for dst, dep, mag in zip(dsts, newcat.data['depth'], newcat.data['magnitude']): circle = Circle((dst, dep), (mag*0.5)**1.5, ec='white') patches.append(circle) colors = newcat.data['magnitude'] p = PatchCollection(patches, zorder=6, edgecolors='white') p.set_alpha(0.5) p.set_array(numpy.array(colors)) axes.add_collection(p)
def translate(self, p1, p2): """ Translate the surface for a specific distance along a specific azimuth direction. Parameters are two points (instances of :class:`openquake.hazardlib.geo.point.Point`) representing the direction and an azimuth for translation. The resulting surface corner points will be that far along that azimuth from respective corner points of this surface as ``p2`` is located with respect to ``p1``. :returns: A new :class:`PlanarSurface` object with the same mesh spacing, dip, strike, width, length and depth but with corners longitudes and latitudes translated. """ azimuth = geodetic.azimuth(p1.longitude, p1.latitude, p2.longitude, p2.latitude) distance = geodetic.geodetic_distance(p1.longitude, p1.latitude, p2.longitude, p2.latitude) # avoid calling PlanarSurface's constructor nsurf = object.__new__(PlanarSurface) nsurf.dip = self.dip nsurf.strike = self.strike nsurf.corner_lons, nsurf.corner_lats = geodetic.point_at( self.corner_lons, self.corner_lats, azimuth, distance) nsurf.corner_depths = self.corner_depths.copy() nsurf._init_plane() nsurf.width = self.width nsurf.length = self.length return nsurf
def get_distance_matrix(self): """ Compute and return distances between each pairs of points in the mesh. This method requires that the coordinate arrays are one-dimensional. NB: the depth of the points is ignored .. warning:: Because of its quadratic space and time complexity this method is safe to use for meshes of up to several thousand points. For mesh of 10k points it needs ~800 Mb for just the resulting matrix and four times that much for intermediate storage. :returns: Two-dimensional numpy array, square matrix of distances. The matrix has zeros on main diagonal and positive distances in kilometers on all other cells. That is, value in cell (3, 5) is the distance between mesh's points 3 and 5 in km, and it is equal to value in cell (5, 3). Uses :func:`openquake.hazardlib.geo.geodetic.geodetic_distance`. """ assert self.lons.ndim == 1 distances = geodetic.geodetic_distance( self.lons.reshape(self.lons.shape + (1, )), self.lats.reshape(self.lats.shape + (1, )), self.lons, self.lats) return numpy.matrix(distances, copy=False)
def build_time_distance_arrays(self): """ Determines the arrays of distance between events and from events to target sites """ neq = self.learning_catalogue.get_number_events() print "Building Time arrays" time_dset = self.fle.create_dataset("time", (neq, neq), dtype="f") #nearest_tset = self.fle.create_dataset("nearest_time", (neq, neq), # dtype="i") counter1 = ProgressCounter(neq, timer=True) for i in range(neq - 1): counter1.update(i) # Get time difference (in DAYS) time_kernel = (365.25 * (self.learning_catalogue.data["dtime"] - self.learning_catalogue.data["dtime"][i])) time_dset[i, :] = time_kernel #nearest_tset[i, :] = np.argsort(time_kernel) print "Building Distance Arrays" distance_dset = self.fle.create_dataset("distance", (neq, neq), dtype="f") nearest_dset = self.fle.create_dataset("d_nearest", (neq, neq), dtype="i") counter1.reset() for i in range(neq - 1): counter1.update(i) epi_distance = geodetic.geodetic_distance( self.learning_catalogue.data["longitude"][i], self.learning_catalogue.data["latitude"][i], self.learning_catalogue.data["longitude"], self.learning_catalogue.data["latitude"]) distance_dset[i, :] = epi_distance nearest_dset[i, :] = np.argsort(epi_distance)
def get_xyz_from_ll(projected, reference): """ This method computes the x, y and z coordinates of a set of points provided a reference point :param projected: :class:`~openquake.hazardlib.geo.point.Point` object representing the coordinates of target point to be projected :param reference: :class:`~openquake.hazardlib.geo.point.Point` object representing the coordinates of the reference point. :returns: x y z """ azims = geod.azimuth(reference.longitude, reference.latitude, projected.longitude, projected.latitude) depths = np.subtract(reference.depth, projected.depth) dists = geod.geodetic_distance(reference.longitude, reference.latitude, projected.longitude, projected.latitude) return (dists * math.sin(math.radians(azims)), dists * math.cos(math.radians(azims)), depths)
def distance_to_mesh(self, mesh, with_depths=True): """ Compute distance (in km) between this point and each point of ``mesh``. :param mesh: :class:`~openquake.hazardlib.geo.mesh.Mesh` of points to calculate distance to. :param with_depths: If ``True`` (by default), distance is calculated between actual point and the mesh, geodetic distance of projections is combined with vertical distance (difference of depths). If this is set to ``False``, only geodetic distance between projections is calculated. :returns: Numpy array of floats of the same shape as ``mesh`` with distance values in km in respective indices. """ if with_depths: if mesh.depths is None: mesh_depths = numpy.zeros_like(mesh.lons) else: mesh_depths = mesh.depths return geodetic.distance(self.longitude, self.latitude, self.depth, mesh.lons, mesh.lats, mesh_depths) else: return geodetic.geodetic_distance(self.longitude, self.latitude, mesh.lons, mesh.lats)
def average_azimuth(self): """ Calculate and return weighted average azimuth of all line's segments in decimal degrees. Uses formula from http://en.wikipedia.org/wiki/Mean_of_circular_quantities >>> from openquake.hazardlib.geo.point import Point as P >>> '%.1f' % Line([P(0, 0), P(1e-5, 1e-5)]).average_azimuth() '45.0' >>> '%.1f' % Line([P(0, 0), P(0, 1e-5), P(1e-5, 1e-5)]).average_azimuth() '45.0' >>> line = Line([P(0, 0), P(-2e-5, 0), P(-2e-5, 1.154e-5)]) >>> '%.1f' % line.average_azimuth() '300.0' """ if len(self.points) == 2: return self.points[0].azimuth(self.points[1]) lons = numpy.array([point.longitude for point in self.points]) lats = numpy.array([point.latitude for point in self.points]) azimuths = geodetic.azimuth(lons[:-1], lats[:-1], lons[1:], lats[1:]) distances = geodetic.geodetic_distance(lons[:-1], lats[:-1], lons[1:], lats[1:]) azimuths = numpy.radians(azimuths) # convert polar coordinates to Cartesian ones and calculate # the average coordinate of each component avg_x = numpy.mean(distances * numpy.sin(azimuths)) avg_y = numpy.mean(distances * numpy.cos(azimuths)) # find the mean azimuth from that mean vector azimuth = numpy.degrees(numpy.arctan2(avg_x, avg_y)) if azimuth < 0: azimuth += 360 return azimuth
def getMatchingEvents(self, solve=True): """Return a list of dictionaries matching input parameters. Args: solve (bool): If set to True, then this method should return a list with a maximum of one event. Returns: list: List of event dictionaries, with fields: - time Event time (UTC) - lat Event latitude - lon Event longitude - depth Event depth - mag Event magnitude """ start_time = self.time - timedelta(seconds=3600) end_time = self.time + timedelta(seconds=3600) tpl = (start_time.strftime(TIMEFMT), end_time.strftime(TIMEFMT)) url = CATBASE % tpl req = requests.get(url) logging.debug("GeoNet search url: %s", str(url)) logging.debug("GeoNet search response code: %s", req.status_code) data = req.text f = io.StringIO(data) df = pd.read_csv(f, parse_dates=["origintime"]) f.close() # some of the column names have spaces in them cols = df.columns newcols = {} for col in cols: newcol = col.strip() newcols[col] = newcol df = df.rename(columns=newcols) lats = df["latitude"].to_numpy() lons = df["longitude"].to_numpy() etime = pd.Timestamp(self.time) dtimes = np.abs(df["origintime"] - etime) distances = geodetic_distance(self.lon, self.lat, lons, lats) didx = distances <= self.radius tidx = (dtimes <= np.timedelta64(int(self.dt), "s")).to_numpy() newdf = df[didx & tidx] events = [] for idx, row in newdf.iterrows(): eventdict = { "time": UTCDateTime(row["origintime"]), "lat": row["latitude"], "lon": row["longitude"], "depth": row["depth"], "mag": row["magnitude"], } events.append(eventdict) if solve and len(events) > 1: event = self.solveEvents(events) events = [event] return events
def set_up_grid_dist(M,N, site_collection_SM): ###### # Calculates the vertical and horozontal spacing between points for each row # IN: M,N- number of points in grid vertically and horozontally # site_collection_SM- site collection for ShakeMap data # OUT: l,d- vectors of distances between points vertically and horozontally ###### l = np.zeros([M-1]) d = np.zeros([M]) # Calculate vertical and horozonal spacing between points for each row l[:] = geodetic_distance(site_collection_SM.lons[range(N,N*M,N)], site_collection_SM.lats[range(N,N*M,N)], site_collection_SM.lons[range(0,N*M-N,N)], site_collection_SM.lats[range(0,N*M-N,N)]) d[:] = geodetic_distance(site_collection_SM.lons[range(0, M*N, N)], site_collection_SM.lats[range(0, M*N, N)], site_collection_SM.lons[range(1, M*N, N)], site_collection_SM.lats[range(1, M*N, N)]) return {'l':l, 'd':d}
def getMatchingEvents(self, solve=True): """Return a list of dictionaries matching input parameters. Args: solve (bool): If set to True, then this method should return a list with a maximum of one event. Returns: list: List of event dictionaries, with fields: - time Event time (UTC) - lat Event latitude - lon Event longitude - depth Event depth - mag Event magnitude """ start_time = self.time - timedelta(seconds=3600) end_time = self.time + timedelta(seconds=3600) tpl = (start_time.strftime(TIMEFMT), end_time.strftime(TIMEFMT)) url = CATBASE % tpl req = requests.get(url) data = req.text f = io.StringIO(data) df = pd.read_csv(f, parse_dates=['origintime']) # some of the column names have spaces in them cols = df.columns newcols = {} for col in cols: newcol = col.strip() newcols[col] = newcol df = df.rename(columns=newcols) lats = df['latitude'].values lons = df['longitude'].values etime = pd.Timestamp(self.time) dtimes = np.abs(df['origintime'] - etime) distances = geodetic_distance(self.lon, self.lat, lons, lats) didx = distances <= self.radius tidx = (dtimes <= np.timedelta64(int(self.dt), 's')).values newdf = df[didx & tidx] events = [] for idx, row in newdf.iterrows(): eventdict = { 'time': UTCDateTime(row['origintime']), 'lat': row['latitude'], 'lon': row['longitude'], 'depth': row['depth'], 'mag': row['magnitude'] } events.append(eventdict) if solve and len(events) > 1: event = self.solveEvents(events) events = [event] return events
def set_up_grid_dist(M,N, site_collection_SM): """ Calculates the vertical and horozontal spacing between points for each row INPUTS: M,N- number of points in grid vertically and horozontally site_collection_SM- site collection for ShakeMap data OUTPUTS: l,d- vectors of distances between points vertically and horozontally """ l = np.zeros([M-1]) d = np.zeros([M]) # Calculate vertical and horozonal spacing between points for each row l[:] = geodetic_distance(site_collection_SM.lons[range(N,N*M,N)], site_collection_SM.lats[range(N,N*M,N)], site_collection_SM.lons[range(0,N*M-N,N)], site_collection_SM.lats[range(0,N*M-N,N)]) d[:] = geodetic_distance(site_collection_SM.lons[range(0, M*N, N)], site_collection_SM.lats[range(0, M*N, N)], site_collection_SM.lons[range(1, M*N, N)], site_collection_SM.lats[range(1, M*N, N)]) return {'l':l, 'd':d}
def test_areas(self): """ Compute the areas of surfaces """ length = geodetic_distance(0.0, 0.0, 0.3, 0.0) expected = np.array([length * 20.0, 10 * 14.14]) computed = self.msrf._get_areas() msg = 'Multi fault surface: areas are wrong' np.testing.assert_almost_equal(expected, computed, err_msg=msg, decimal=-1)
def test_rx_kite(self): spc = 2.0 pro1 = Line([Point(0.2, 0.0, 0.0), Point(0.2, 0.05, 15.0)]) pro2 = Line([Point(0.0, 0.0, 0.0), Point(0.0, 0.05, 15.0)]) sfc1 = KiteSurface.from_profiles([pro1, pro2], spc, spc) msurf = MultiSurface([sfc1]) pcoo = numpy.array([[0.2, 0.1], [0.0, -0.1]]) mesh = Mesh(pcoo[:, 0], pcoo[:, 1]) # Compute expected distances lo = pro1.points[0].longitude la = pro1.points[0].longitude tmp0 = geodetic_distance(lo, la, pcoo[0, 0], pcoo[0, 1]) lo = pro2.points[0].longitude la = pro2.points[0].longitude tmp1 = geodetic_distance(lo, la, pcoo[1, 0], pcoo[1, 1]) # Checking rx = msurf.get_rx_distance(mesh) expected = numpy.array([tmp0, -tmp1]) numpy.testing.assert_almost_equal(expected, rx, decimal=5)
def getMatchingEvents(self, solve=True): """Return a list of dictionaries matching input parameters. Args: solve (bool): If set to True, then this method should return a list with a maximum of one event. Returns: list: List of event dictionaries, with fields: - time Event time (UTC) - lat Event latitude - lon Event longitude - depth Event depth - mag Event magnitude """ start_time = self.time - timedelta(seconds=3600) end_time = self.time + timedelta(seconds=3600) tpl = (start_time.strftime(TIMEFMT), end_time.strftime(TIMEFMT)) url = CATBASE % tpl req = requests.get(url) data = req.text f = io.StringIO(data) df = pd.read_csv(f, parse_dates=['origintime']) # some of the column names have spaces in them cols = df.columns newcols = {} for col in cols: newcol = col.strip() newcols[col] = newcol df = df.rename(columns=newcols) lats = df['latitude'].values lons = df['longitude'].values etime = pd.Timestamp(self.time) dtimes = np.abs(df['origintime'] - etime) distances = geodetic_distance(self.lon, self.lat, lons, lats) didx = distances <= self.radius tidx = (dtimes <= np.timedelta64(int(self.dt), 's')).values newdf = df[didx & tidx] events = [] for idx, row in newdf.iterrows(): eventdict = {'time': UTCDateTime(row['origintime']), 'lat': row['latitude'], 'lon': row['longitude'], 'depth': row['depth'], 'mag': row['magnitude']} events.append(eventdict) if solve and len(events) > 1: event = self.solveEvents(events) events = [event] return events
def get_quake_desc(event,lat,lon,isMainEvent): ndeaths = event['TotalDeaths'] #summarize the exposure values exposures = np.array([event['MMI1'],event['MMI2'],event['MMI3'],event['MMI4'],event['MMI5'], event['MMI6'],event['MMI7'],event['MMI8'],event['MMI9+']]) exposures = np.array([round_to_nearest(exp,1000) for exp in exposures]) #get the highest two exposures greater than zero iexp = np.where(exposures > 0)[0][::-1] romans = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX or greater'] if len(iexp) >= 2: exposures = [exposures[iexp[1]],exposures[iexp[0]]] ilevels = [romans[iexp[1]],romans[iexp[0]]] expfmt = ', with estimated population exposures of %s at intensity' expfmt = expfmt + ' %s and %s at intensity %s' exptxt = expfmt % (commify(int(exposures[0])),ilevels[0],commify(int(exposures[1])),ilevels[1]) else: exptxt = '' #create string describing this most impactful event dfmt = 'A magnitude %.1f earthquake %i km %s of this event struck %s on %s (UTC)%s' mag = event['Magnitude'] etime = event['Time'].strftime('%B %d, %Y') etime = re.sub(' 0',' ',etime) country = Country() if not event['Name']: if event['CountryCode'] == 'UM' and event['Latitude'] > 40: #hack for persistent error in expocat cdict = country.getCountryCode('US') else: cdict = country.getCountryCode(event['CountryCode']) if cdict: cname = cdict['Name'] else: cname = 'in the open ocean' else: cname = event['Name'].replace('"','') cdist = round(geodetic_distance(event['Lat'],event['Lon'],lat,lon)) cdir = get_compass_dir(lat,lon,event['Lat'],event['Lon'],format='long').lower() if ndeaths and str(ndeaths) != "nan": dfmt = dfmt + ', resulting in a reported %s %s.' if ndeaths > 1: dstr = 'fatalities' else: dstr = 'fatality' ndeathstr = commify(int(ndeaths)) eqdesc = dfmt % (mag,cdist,cdir,cname,etime,exptxt,ndeathstr,dstr) else: dfmt = dfmt + ', with no reported fatalities.' eqdesc = dfmt % (mag,cdist,cdir,cname,etime,exptxt) return eqdesc
def selectByRadius(self, clat, clon, radius): """Select events by restricting to those within a search radius around a set of coordinates. """ lons = self._dataframe['Lon'] lats = self._dataframe['Lat'] distances = geodetic_distance(clon, clat, lons, lats) iclose = pd.Series(distances < radius) newdf = self._dataframe[iclose] d1 = distances[distances < radius] newdf = newdf.assign(Distance=d1) return ExpoCat(newdf)
def get_closest(self, lon, lat): """ Get the closest object to the given longitude and latitude and its distance. :param lon: longitude in degrees :param lat: latitude in degrees :param max_distance: distance in km (or None) """ x, y = self.proj(lon, lat) idx = list(self.index.nearest((x, y, x, y), 1))[0] min_dist = geodetic_distance( lon, lat, self.lons[idx], self.lats[idx]) return self.objects[idx], min_dist
def conditional_simulation(known_sites, residuals, unknown_sites, imt, nsim, correlation_model=DEFAULT_CORRELATION): """ Generates the residuals for a set of sites, conditioned upon the known residuals at a set of observation locations :param known_sites: Locations of known sites as instance of :class: openquake.hazardlib.sites.SiteCollection :param dict residuals: Dictionary of residuals for specifc GMPE and IMT :param unknown_sites: Locations of unknown sites as instance of :class: openquake.hazardlib.sites.SiteCollection :param imt: Intensity measure type :psram int nsim: Number of simulations :param correlation_model: Chosen correlation model """ # Get site to site distances for known imt = from_string(imt) # Make sure that sites are at the surface (to check!) known_sites.depths = np.zeros_like(known_sites.depths) unknown_sites.depths = np.zeros_like(unknown_sites.depths) cov_kk = correlation_model._get_correlation_matrix(known_sites, imt).I cov_uu = correlation_model._get_correlation_matrix(unknown_sites, imt) d_k_uk = np.zeros([known_sites.total_sites, unknown_sites.total_sites], dtype=float) for iloc in range(0, known_sites.total_sites): d_k_uk[iloc, :] = geodetic_distance(known_sites.lons[iloc], known_sites.lats[iloc], unknown_sites.lons, unknown_sites.lats) cov_ku = correlation_model._get_correlation_model(d_k_uk, imt) mu = cov_ku.T * cov_kk * np.matrix(residuals).T stddev = cov_uu - (cov_ku.T * cov_kk * cov_ku) unknown_residuals = np.matrix( np.random.normal(0., 1., [len(unknown_sites), nsim])) lower_matrix = np.linalg.cholesky(stddev) output_residuals = np.zeros_like(unknown_residuals) for iloc in range(0, nsim): output_residuals[:, iloc] = mu + \ lower_matrix * unknown_residuals[:, iloc] return output_residuals
def test_arrays(self): lons1 = numpy.array([[-50.03824533, -153.97808192], [-106.36068694, 47.06944014]]) lats1 = numpy.array([[52.20211151, 17.018482], [-26.06421527, -20.30383723]]) lons2 = numpy.array([[49.97448794, 52.3126795], [-165.13925579, 162.16421979]]) lats2 = numpy.array([[-27.66510775, -73.66591257], [-60.24498761, -9.92908014]]) edist = numpy.array([[13061.87935023, 13506.24000062], [5807.34519649, 12163.45759805]]) dist = geodetic.geodetic_distance(lons1, lats1, lons2, lats2) self.assertEqual(dist.shape, edist.shape) self.assertTrue(numpy.allclose(dist, edist))
def get_middle_point(lon1, lat1, lon2, lat2): """ Given two points return the point exactly in the middle lying on the same great circle arc. Parameters are point coordinates in degrees. :returns: Tuple of longitude and latitude of the point in the middle. """ if lon1 == lon2 and lat1 == lat2: return lon1, lat1 dist = geodetic.geodetic_distance(lon1, lat1, lon2, lat2) azimuth = geodetic.azimuth(lon1, lat1, lon2, lat2) return geodetic.point_at(lon1, lat1, azimuth, dist / 2.0)
def get_middle_point(lon1, lat1, lon2, lat2): """ Given two points return the point exactly in the middle lying on the same great circle arc. Parameters are point coordinates in degrees. :returns: Tuple of longitude and latitude of the point in the middle. """ if lon1 == lon2 and lat1 == lat2: return lon1, lat1 dist = geodetic.geodetic_distance(lon1, lat1, lon2, lat2) azimuth = geodetic.azimuth(lon1, lat1, lon2, lat2) return geodetic.point_at(lon1, lat1, azimuth, dist / 2.0)
def _plot_topo(axes, csda): """ :parameter axes: :parameter csda: """ if csda.topo is None: return plt.sca(axes) olo = csda.csec.olo ola = csda.csec.ola topo = csda.topo tbsts = geodetic_distance(olo, ola, topo[:, 0], topo[:, 1]) jjj = numpy.argsort(tbsts) plt.plot(tbsts[jjj], ((-1*topo[jjj, 2])/1000.), '-g', zorder=100, linewidth=2)
def conditional_simulation( known_sites, residuals, unknown_sites, imt, nsim, correlation_model=DEFAULT_CORRELATION): """ Generates the residuals for a set of sites, conditioned upon the known residuals at a set of observation locations :param known_sites: Locations of known sites as instance of :class: `openquake.hazardlib.sites.SiteCollection` :param dict residuals: Dictionary of residuals for specifc GMPE and IMT :param unknown_sites: Locations of unknown sites as instance of :class: `openquake.hazardlib.sites.SiteCollection` :param imt: Intensity measure type :psram int nsim: Number of simulations :param correlation_model: Chosen correlation model, i.e. jbcorrelation """ # Get site to site distances for known imt = from_string(imt) # Make sure that sites are at the surface (to check!) known_sites.depths = np.zeros_like(known_sites.depths) unknown_sites.depths = np.zeros_like(unknown_sites.depths) cov_kk = np.linalg.inv(correlation_model(known_sites, imt)) cov_uu = correlation_model(unknown_sites, imt) d_k_uk = np.zeros([len(known_sites), len(unknown_sites)], dtype=float) klons, klats = known_sites.lons, known_sites.lats ulons, ulats = unknown_sites.lons, unknown_sites.lats for iloc in range(len(known_sites)): d_k_uk[iloc, :] = geodetic_distance(klons[iloc], klats[iloc], ulons, ulats) cov_ku = correlation_model(d_k_uk, imt) mu = cov_ku.T @ cov_kk @ residuals.T stddev = cov_uu - (cov_ku.T @ cov_kk @ cov_ku) unknown_residuals = np.random.normal( 0., 1., [len(unknown_sites), nsim]) lower_matrix = np.linalg.cholesky(stddev) output_residuals = np.zeros_like(unknown_residuals) for iloc in range(0, nsim): output_residuals[:, iloc] = mu + \ lower_matrix @ unknown_residuals[:, iloc] return output_residuals
def _plot_litho(axes, csda): """ :parameter axes: :parameter csda: """ if csda.litho is None: print("No LITHO1.0...") return plt.sca(axes) olo = csda.csec.olo ola = csda.csec.ola litho = csda.litho if litho.size == 3: litho = numpy.concatenate((litho, litho), axis=0).reshape((2, 3)) lists = geodetic_distance(olo, ola, litho[:, 0], litho[:, 1]) lll = numpy.argsort(lists) plt.plot(lists[lll], litho[lll, 2], '-.', zorder=100, linewidth=2)
def _plot_moho(axes, csda): """ :parameter axes: :parameter csda: """ if csda.moho is None: print("No CRUST1.0...") return plt.sca(axes) olo = csda.csec.olo ola = csda.csec.ola moho = csda.moho if moho.size == 3: moho = numpy.concatenate((moho, moho), axis=0).reshape((2, 3)) mdsts = geodetic_distance(olo, ola, moho[:, 0], moho[:, 1]) iii = numpy.argsort(mdsts) plt.plot(mdsts[iii], moho[iii, 2], '--p', zorder=100, linewidth=2)
def _plot_slab1pt0(axes, csda): """ :parameter axes: :parameter csda: """ if csda.slab1pt0 is None: return plt.sca(axes) olo = csda.csec.olo ola = csda.csec.ola slab1pt0 = csda.slab1pt0 slb_dst = geodetic_distance(olo, ola, slab1pt0[:, 0], slab1pt0[:, 1]) slb_dep = slab1pt0[:, 2] iii = numpy.argsort(slb_dst) if len(iii) > 2: plt.plot(slb_dst[iii], -1*slb_dep[iii], '-b', linewidth=3, zorder=30) plt.text(slb_dst[iii[-1]], -1*slb_dep[iii[-1]], 'Slab1.0', fontsize=8)
def _plot_focal_mech(axes, csda): """ :parameter axes: :parameter csda: """ if csda.gcmt is None: return olo = csda.csec.olo ola = csda.csec.ola cat_gcmt = csda.gcmt cmt_dst = geodetic_distance(olo, ola, cat_gcmt.data['longitude'], cat_gcmt.data['latitude']) cmt_dep = cat_gcmt.data['depth'] cmts = numpy.array(cat_gcmt.gcmts) idx = 0 for ddd, dep, eve, mag, yea in zip(list(cmt_dst), list(cmt_dep), list(cmts), cat_gcmt.data['magnitude'], cat_gcmt.data['year']): if yea > 1000 and mag > 1.0: # Kaverina classification plungeb = cat_gcmt.data['plunge_b'][idx] plungep = cat_gcmt.data['plunge_p'][idx] plunget = cat_gcmt.data['plunge_t'][idx] mclass = mecclass(plunget, plungeb, plungep) com = eve.moment_tensor._to_6component() # REMOVE try: bcc = beach(com, xy=(ddd, dep), width=eve.magnitude * 2, linewidth=1, zorder=20, size=mag, facecolor=KAVERINA[mclass]) bcc.set_alpha(0.5) axes.add_collection(bcc) except: pass idx += 1
def _plot_np_intersection(axes, csda): """ """ if csda.gcmt is None: return olo = csda.csec.olo ola = csda.csec.ola cat_gcmt = csda.gcmt cmt_dst = geodetic_distance(olo, ola, cat_gcmt.data['longitude'], cat_gcmt.data['latitude']) cmt_dep = cat_gcmt.data['depth'] cmts = numpy.array(cat_gcmt.gcmts) idx = 0 for ddd, dep, eve, mag, yea in zip(list(cmt_dst), list(cmt_dep), list(cmts), cat_gcmt.data['magnitude'], cat_gcmt.data['year']): if yea > 1000 and mag > 1.0: # Kaverina classification plungeb = cat_gcmt.data['plunge_b'][idx] plungep = cat_gcmt.data['plunge_p'][idx] plunget = cat_gcmt.data['plunge_t'][idx] mclass = mecclass(plunget, plungeb, plungep) plot_planes_at(ddd, dep, [eve.nodal_planes.nodal_plane_1['strike'], eve.nodal_planes.nodal_plane_2['strike']], [eve.nodal_planes.nodal_plane_1['dip'], eve.nodal_planes.nodal_plane_2['dip']], [mag, mag], strike_cs=csda.csec.strike[0], dip_cs=90., aratio=1.0, color=KAVERINA[mclass], linewidth=2.0, axis=axes) idx += 1
def limitByRadius(self,lat,lon,radius): """Search for cities within a radius (km) around a central point. :param lat: Central latitude coordinate (dd). :param lon: Central longitude coordinate (dd). :param radius: Radius (km) around which cities will be searched. :returns: New Cities instance containing smaller cities data set. """ #TODO - figure out what to do with a meridian crossing? newdf = self._dataframe.copy() dist = geodetic_distance(lon,lat,self._dataframe['lon'],self._dataframe['lat']) newdf['dist'] = dist newdf = newdf[newdf['dist'] <= radius] del newdf['dist'] return type(self)(newdf)
def get_closest(self, lon, lat): """ Get the closest object to the given longitude and latitude and its distance. :param lon: longitude in degrees :param lat: latitude in degrees :param max_distance: distance in km (or None) """ if rtree: x, y = self.proj(lon, lat) idx = list(self.index.nearest((x, y, x, y), 1))[0] min_dist = geodetic_distance(lon, lat, self.lons[idx], self.lats[idx]) else: zeros = numpy.zeros_like(self.lons) idx, min_dist = min_idx_dst(self.lons, self.lats, zeros, lon, lat) return self.objects[idx], min_dist
def get_resampled_coordinates(lons, lats): """ Resample polygon line segments and return the coordinates of the new vertices. This limits distortions when projecting a polygon onto a spherical surface. Parameters define longitudes and latitudes of a point collection in the form of lists or numpy arrays. :return: A tuple of two numpy arrays: longitudes and latitudes of resampled vertices. """ num_coords = len(lons) assert num_coords == len(lats) lons1 = numpy.array(lons) lats1 = numpy.array(lats) lons2 = numpy.concatenate((lons1[1:], lons1[0:1])) lats2 = numpy.concatenate((lats1[1:], lats1[0:1])) distances = geodetic.geodetic_distance(lons1, lats1, lons2, lats2) resampled_lons = [lons[0]] resampled_lats = [lats[0]] for i in xrange(num_coords): next_point = (i + 1) % num_coords lon1, lat1 = lons[i], lats[i] lon2, lat2 = lons[next_point], lats[next_point] distance = distances[i] num_points = int(distance / UPSAMPLING_STEP_KM) + 1 if num_points >= 2: # We need to increase the resolution of this arc by adding new # points. new_lons, new_lats, _ = geodetic.npoints_between( lon1, lat1, 0, lon2, lat2, 0, num_points ) resampled_lons.extend(new_lons[1:]) resampled_lats.extend(new_lats[1:]) else: resampled_lons.append(lon2) resampled_lats.append(lat2) # we cut off the last point because it repeats the first one. return numpy.array(resampled_lons[:-1]), numpy.array(resampled_lats[:-1])
def conditional_simulation(known_sites, residuals, unknown_sites, imt, nsim, correlation_model=DEFAULT_CORRELATION): """ Generates the residuals for a set of sites, conditioned upon the known residuals at a set of observation locations :param known_sites: Locations of known sites as instance of :class: openquake.hazardlib.sites.SiteCollection :param dict residuals: Dictionary of residuals for specifc GMPE and IMT :param unknown_sites: Locations of unknown sites as instance of :class: openquake.hazardlib.sites.SiteCollection :param imt: Intensity measure type :psram int nsim: Number of simulations :param correlation_model: Chosen correlation model """ # Get site to site distances for known imt = from_string(imt) cov_kk = correlation_model._get_correlation_matrix(known_sites, imt).I cov_uu = correlation_model._get_correlation_matrix(unknown_sites, imt) d_k_uk = np.zeros([known_sites.total_sites, unknown_sites.total_sites], dtype=float) for iloc in range(0, known_sites.total_sites): d_k_uk[iloc, :] = geodetic_distance(known_sites.lons[iloc], known_sites.lats[iloc], unknown_sites.lons, unknown_sites.lats) cov_ku = correlation_model._get_correlation_model(d_k_uk, imt) mu = cov_ku.T * cov_kk * np.matrix(residuals).T stddev = cov_uu - (cov_ku.T * cov_kk * cov_ku) unknown_residuals = np.matrix(np.random.normal(0., 1., [len(unknown_sites), nsim])) lower_matrix = np.linalg.cholesky(stddev) output_residuals = np.zeros_like(unknown_residuals) for iloc in range(0, nsim): output_residuals[:, iloc] = mu + \ lower_matrix * unknown_residuals[:, iloc] return output_residuals
def solveEvents(self, events): """Reduce a list of events down to one that best matches the input. Args: events (list): List of dictionaries with fields: - time Event time (UTC) - lat Event latitude - lon Event longitude - depth Event depth - mag Event magnitude Returns: dict: Event dictionary (see above) """ edict = {'time': UTCDateTime(self.time), 'lat': self.lat, 'lon': self.lon, 'depth': self.depth, 'mag': self.magnitude} zmin = 9e12 minevent = None for i in range(0, len(events)): event = events[i] ddist = geodetic_distance(edict['lon'], edict['lat'], event['lon'], event['lat']) ddist_norm = ddist / self.radius dt_norm = np.abs(edict['time'] - event['time']) / self.dt ddepth_norm = np.abs(edict['depth'] - event['depth']) / self.ddepth dmag_norm = np.abs(edict['mag'] - event['mag']) / self.dmag ddsq = np.power(ddist_norm, 2) dtsq = np.power(dt_norm, 2) dzsq = np.power(ddepth_norm, 2) dmsq = np.power(dmag_norm, 2) z = np.sqrt(ddsq + dtsq + dzsq + dmsq) if z < zmin: zmin = z minevent = event return minevent
def get_closest(self, lon, lat, max_distance=None): """ Get the closest object to the given longitude and latitude and its distance. If the `max_distance` is given and all objects are farther than the maximum distance, returns (None, None). :param lon: longitude in degrees :param lat: latitude in degrees :param max_distance: distance in km (or None) """ if rtree: x, y = self.proj(lon, lat) idx = list(self.index.nearest((x, y, x, y), 1))[0] min_dist = geodetic_distance( lon, lat, self.lons[idx], self.lats[idx]) else: zeros = numpy.zeros_like(self.lons) idx, min_dist = min_idx_dst(self.lons, self.lats, zeros, lon, lat) if max_distance is not None and min_dist > max_distance: return None, None return self.objects[idx], min_dist
def getMatchingEvents(self, solve=True): """Return a list of dictionaries matching input parameters. Args: solve (bool): If set to True, then this method should return a list with a maximum of one event. Returns: list: List of event dictionaries, with fields: - time Event time (UTC) - lat Event latitude - lon Event longitude - depth Event depth - mag Event magnitude """ df = get_turkey_dataframe(self.time, 1) lats = df['latitude'].values lons = df['longitude'].values etime = pd.Timestamp(self.time) dtimes = np.abs(df['origintime'] - etime) distances = geodetic_distance(self.lon, self.lat, lons, lats) didx = distances <= self.radius tidx = (dtimes <= np.timedelta64(int(self.dt), 's')).values newdf = df[didx & tidx] events = [] for idx, row in newdf.iterrows(): eventdict = {'time': UTCDateTime(row['origintime']), 'lat': row['latitude'], 'lon': row['longitude'], 'depth': row['depth'], 'url': row['url'], 'mag': row['magnitude']} events.append(eventdict) if solve and len(events) > 1: event = self.solveEvents(events) events = [event] return events
def calc_full_dist(row, vert, hor, N, site_collection_SM): """ Calculates full distance matrix. Called once per row. INPUTS: vert- number of included rows hor- number of columns within radius N- number of points in row site_collection_SM- site collection for ShakeMap data OUTPUTS: grid_indices- indices of points included in distance matrix distance_matrix- full distance matrix """ # gathers indices for full distance matrix for each row grid_indices = [None]*(vert*(2*hor+1)) n_grid_indices = 0 for k in range(row-vert+1, row+1): if k == row: for j in range(0,hor+1): grid_indices[n_grid_indices] = j + N*k n_grid_indices += 1 else: for j in range(0,2*hor+1): grid_indices[n_grid_indices] = j + N*k n_grid_indices += 1 del grid_indices[n_grid_indices:] distance_matrix = np.zeros([np.size(grid_indices), np.size(grid_indices)]) # Create full distance matrix for row for k in range(0, np.size(grid_indices)): distance_matrix[k, k:] = geodetic_distance( site_collection_SM.lons[grid_indices[k ]], site_collection_SM.lats[grid_indices[k]], site_collection_SM.lons[grid_indices[k:]], site_collection_SM.lats[grid_indices[k:]]).flatten() distance_matrix = distance_matrix + distance_matrix.T return {'grid_indices':grid_indices, 'distance_matrix':distance_matrix}
def calc_full_dist(vert, hor, N, site_collection_SM): ##### # Calculates full distance matrix. Called once per row. # IN: vert- number of included rows # hor- number of columns within radius # N- number of points in row # site_collection_SM- site collection for ShakeMap data #OUT: grid_indices- indices of points included in distance matrix # distance_matrix- full distance matrix ##### # gathers indices for full distance matrix for each row grid_indices = [None]*(vert*(2*hor+1)) n_grid_indices = 0 for k in range(0, vert): if k == vert-1: for j in range(0,hor+1): grid_indices[n_grid_indices] = [j + N*k] n_grid_indices += 1 else: for j in range(0,2*hor+1): grid_indices[n_grid_indices] = [j + N*k] n_grid_indices += 1 del grid_indices[n_grid_indices:] distance_matrix = np.zeros([np.size(grid_indices), np.size(grid_indices)]) grid_indices = np.vstack(grid_indices) # Create full distance matrix for row for k in range(0, np.size(grid_indices)): distance_matrix[k, k:] = geodetic_distance( site_collection_SM.lons[grid_indices[k ]], site_collection_SM.lats[grid_indices[k]], site_collection_SM.lons[grid_indices[k:]], site_collection_SM.lats[grid_indices[k:]]).flatten() distance_matrix = distance_matrix + distance_matrix.T return {'grid_indices':grid_indices, 'distance_matrix':distance_matrix}
def get_dppvalue(self, site): """ Get the directivity prediction value, DPP at a given site as described in Spudich et al. (2013). :param site: :class:`~openquake.hazardlib.geo.point.Point` object representing the location of the target site :returns: A float number, directivity prediction value (DPP). """ origin = self.surface.get_resampled_top_edge()[0] dpp_multi = [] index_patch = self.surface.hypocentre_patch_index( self.hypocenter, self.surface.get_resampled_top_edge(), self.surface.mesh.depths[0][0], self.surface.mesh.depths[-1][0], self.surface.get_dip()) idx_nxtp = True hypocenter = self.hypocenter while idx_nxtp: # E Plane Calculation p0, p1, p2, p3 = self.surface.get_fault_patch_vertices( self.surface.get_resampled_top_edge(), self.surface.mesh.depths[0][0], self.surface.mesh.depths[-1][0], self.surface.get_dip(), index_patch=index_patch) [normal, dist_to_plane] = get_plane_equation( p0, p1, p2, origin) pp = projection_pp(site, normal, dist_to_plane, origin) pd, e, idx_nxtp = directp( p0, p1, p2, p3, hypocenter, origin, pp) pd_geo = origin.point_at( (pd[0] ** 2 + pd[1] ** 2) ** 0.5, -pd[2], numpy.degrees(math.atan2(pd[0], pd[1]))) # determine the lower bound of E path value f1 = geodetic_distance(p0.longitude, p0.latitude, p1.longitude, p1.latitude) f2 = geodetic_distance(p2.longitude, p2.latitude, p3.longitude, p3.latitude) if f1 > f2: f = f1 else: f = f2 fs, rd, r_hyp = average_s_rad(site, hypocenter, origin, pp, normal, dist_to_plane, e, p0, p1, self.rupture_slip_direction) cprime = isochone_ratio(e, rd, r_hyp) dpp_exp = cprime * numpy.maximum(e, 0.1 * f) *\ numpy.maximum(fs, 0.2) dpp_multi.append(dpp_exp) # check if go through the next patch of the fault index_patch = index_patch + 1 if (len(self.surface.get_resampled_top_edge()) <= 2) and (index_patch >= len(self.surface.get_resampled_top_edge())): idx_nxtp = False elif index_patch >= len(self.surface.get_resampled_top_edge()): idx_nxtp = False elif idx_nxtp: hypocenter = pd_geo idx_nxtp = True # calculate DPP value of the site. dpp = numpy.log(numpy.sum(dpp_multi)) return dpp
def test_along_meridian(self): coords = list(map(numpy.array, [(77.5, -150.), (-10., 15.), (77.5, -150.), (-20., 25.)])) dist = geodetic.geodetic_distance(*coords) assert_aeq(dist, [1111.949, 1111.949], decimal=3)
def getMatchingEvents(self, solve=True): """Return a list of dictionaries matching input parameters. Args: solve (bool): If set to True, then this method should return a list with a maximum of one event. Returns: list: List of event dictionaries, with fields: - time Event time (UTC) - lat Event latitude - lon Event longitude - depth Event depth - mag Event magnitude """ jpyear = str(self.jptime.year) jpquarter = str(QUARTERS[self.jptime.month]) url = SEARCH_URL.replace('YEAR', jpyear) url = url.replace('QUARTER', jpquarter) req = requests.get(url) data = req.text soup = BeautifulSoup(data, features="lxml") select = soup.find('select') options = select.find_all('option') times = [] lats = [] lons = [] depths = [] mags = [] values = [] for option in options: eventstr = option.contents[0] timestr = re.search(TIMEPAT, eventstr).group() latstr = re.search(LATPAT, eventstr).group() lonstr = re.search(LONPAT, eventstr).group() depstr = re.search(DEPPAT, eventstr).group() magstr = re.search(MAGPAT, eventstr).group() lat = float(latstr.replace('N', '')) lon = float(lonstr.replace('E', '')) depth = float(depstr.replace('km', '')) mag = float(magstr.replace('M', '')) etime = datetime.strptime(timestr, TIMEFMT) times.append(np.datetime64(etime)) lats.append(lat) lons.append(lon) depths.append(depth) mags.append(mag) values.append(option.get('value')) times = np.array(times) lats = np.array(lats) lons = np.array(lons) depths = np.array(depths) mags = np.array(mags) values = np.array(values) distances = geodetic_distance(self.lon, self.lat, lons, lats) didx = distances <= self.radius jptime = np.datetime64(self.jptime) # dtimes is in microseconds dtimes = np.abs(jptime - times) tidx = dtimes <= np.timedelta64(int(self.dt), 's') etimes = times[didx & tidx] elats = lats[didx & tidx] elons = lons[didx & tidx] edepths = depths[didx & tidx] emags = mags[didx & tidx] evalues = values[didx & tidx] events = [] for etime, elat, elon, edep, emag, evalue in zip(etimes, elats, elons, edepths, emags, evalues): jtime = UTCDateTime(str(etime)) utime = jtime - JST_OFFSET edict = {'time': utime, 'lat': elat, 'lon': elon, 'depth': edep, 'mag': emag, 'cgi_value': evalue} events.append(edict) if solve and len(events) > 1: event = self.solveEvents(events) events = [event] return events
def test_LAX_to_JFK(self): dist = geodetic.geodetic_distance(*(LAX + JFK)) self.assertAlmostEqual(dist, 0.623585 * geodetic.EARTH_RADIUS, delta=0.1) dist2 = geodetic.geodetic_distance(*(JFK + LAX)) self.assertAlmostEqual(dist, dist2)
def test_one_to_many(self): dist = geodetic.geodetic_distance(0, 0, [-1, 1], [0, 0]) assert_aeq(dist, [111.195, 111.195], decimal=4) dist = geodetic.geodetic_distance(0, 0, [[-1, 0], [1, 0]], [[0, 0], [0, 0]]) assert_aeq(dist, [[111.195, 0], [111.195, 0]], decimal=4)
def test_on_equator(self): dist = geodetic.geodetic_distance(0, 0, 1, 0) self.assertAlmostEqual(dist, 111.1949266) [dist2] = geodetic.geodetic_distance([-5], [0], [-6], [0]) self.assertAlmostEqual(dist, dist2)
def test_along_meridian(self): coords = list(map(numpy.array, [(77.5, -150.), (-10., 15.), (77.5, -150.), (-20., 25.)])) dist = geodetic.geodetic_distance(*coords) self.assertTrue(numpy.allclose(dist, [1111.949, 1111.949]), str(dist))
def test_one_point_on_pole(self): dist = geodetic.geodetic_distance(0, 90, 0, 88) self.assertAlmostEqual(dist, 222.3898533)
def test_small_distance(self): dist = geodetic.geodetic_distance(0, 0, 0, 1e-10) self.assertAlmostEqual(dist, 0) dist = geodetic.geodetic_distance(-1e-12, 0, 0, 0) self.assertAlmostEqual(dist, 0)
def test_opposite_points(self): dist = geodetic.geodetic_distance(110, -10, -70, 10) self.assertAlmostEqual(dist, geodetic.EARTH_RADIUS * numpy.pi, places=3)