def _fix_right_hand(self): # This method fixes the mesh used to represent the grid surface so # that it complies with the right hand rule. found = False irow = 0 icol = 0 while not found: if np.all(np.isfinite(self.mesh.lons[irow:irow+2, icol:icol+2])): found = True else: icol += 1 if (icol+1) >= self.mesh.lons.shape[1]: irow += 1 icol = 1 if (irow+1) >= self.mesh.lons.shape[0]: break if found: azi_strike = azimuth(self.mesh.lons[irow, icol], self.mesh.lats[irow, icol], self.mesh.lons[irow+1, icol], self.mesh.lats[irow+1, icol]) azi_dip = azimuth(self.mesh.lons[irow, icol], self.mesh.lats[irow, icol], self.mesh.lons[irow, icol+1], self.mesh.lats[irow, icol+1]) if abs((azi_strike + 90) % 360 - azi_dip) < 10: tlo = np.fliplr(self.mesh.lons) tla = np.fliplr(self.mesh.lats) tde = np.fliplr(self.mesh.depths) mesh = RectangularMesh(tlo, tla, tde) self.mesh = mesh else: msg = 'Could not find a valid quadrilateral for strike calculation' raise ValueError(msg)
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 _find_turning_points(mesh, tol=1.0): """ Identifies the turning points in a rectangular mesh based on the deviation in the azimuth between successive points on the upper edge. A turning point is flagged if the change in azimuth change is greater than the specified tolerance (in degrees) :param mesh: Mesh for downsampling as instance of :class: openquake.hazardlib.geo.mesh.RectangularMesh :param float tol: Maximum difference in azimuth (decimal degrees) between successive points to identify a turning point :returns: Column indices of turning points (as numpy array) """ assert isinstance(mesh, RectangularMesh) azimuths = geodetic.azimuth(mesh.lons[0, :-1], mesh.lats[0, :-1], mesh.lons[0, 1:], mesh.lats[0, 1:]) naz = len(azimuths) azim = azimuths[0] # Retain initial point idx = [0] for i in range(1, naz): if numpy.fabs(azimuths[i] - azim) > tol: idx.append(i) azim = azimuths[i] # Add on last point - if not already in the set if not idx[-1] == (mesh.lons.shape[1] - 1): idx.append(mesh.lons.shape[1] - 1) return numpy.array(idx)
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 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 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 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 _find_turning_points(mesh, tol=1.0): """ Identifies the turning points in a rectangular mesh based on the deviation in the azimuth between successive points on the upper edge. A turning point is flagged if the change in azimuth change is greater than the specified tolerance (in degrees) :param mesh: Mesh for downsampling as instance of :class: openquake.hazardlib.geo.mesh.RectangularMesh :param float tol: Maximum difference in azimuth (decimal degrees) between successive points to identify a turning point :returns: Column indices of turning points (as numpy array) """ assert isinstance(mesh, RectangularMesh) azimuths = geodetic.azimuth(mesh.lons[0, :-1], mesh.lats[0, :-1], mesh.lons[0, 1:], mesh.lats[0, 1:]) naz = len(azimuths) azim = azimuths[0] # Retain initial point idx = [0] for i in range(1, naz): if numpy.fabs(azimuths[i] - azim) > tol: idx.append(i) azim = azimuths[i] # Add on last point - if not already in the set if idx[-1] != mesh.lons.shape[1] - 1: idx.append(mesh.lons.shape[1] - 1) return numpy.array(idx)
def test_map_rupture(interactive=False): xp0 = np.array([-90.898000]) xp1 = np.array([-91.308000]) yp0 = np.array([12.584000]) yp1 = np.array([12.832000]) zp = [0.0] strike = azimuth(yp0[0], xp0[0], yp1[0], xp1[0]) origin = Origin({ 'lat': 0.0, 'lon': 0.0, 'depth': 0.0, 'mag': 5.5, 'eventsourcecode': 'abcd' }) interface_width = MAX_DEPTH / np.sin(np.radians(DIP)) widths = np.ones(xp0.shape) * interface_width dips = np.ones(xp0.shape) * DIP strike = [strike] rupture = QuadRupture.fromTrace(xp0, yp0, xp1, yp1, zp, widths, dips, origin, strike=strike) map_rupture(rupture) if interactive: fname = os.path.join(os.path.expanduser('~'), 'rupture_map.png') plt.savefig(fname) print('Rupture map plot saved to %s. Delete this file if you wish.' % fname)
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 test_arrays(self): lons1 = numpy.array([[156.49676849, 150.03697145], [-77.96053914, -109.36694411]]) lats1 = numpy.array([[-79.78522764, -89.15044328], [-32.28244296, -25.11092309]]) lons2 = numpy.array([[-84.6732372, 140.08382287], [82.69227935, -18.9919318]]) lats2 = numpy.array([[82.16896786, 26.16081412], [41.21501474, -2.88241099]]) eazimuths = numpy.array([[47.07336955, 350.11740733], [54.46959147, 92.76923701]]) az = geodetic.azimuth(lons1, lats1, lons2, lats2) self.assertTrue(numpy.allclose(az, eazimuths), str(az))
def get_azimuth_of_closest_point(self, mesh): """ Compute the azimuth between point in `mesh` and the corresponding closest point on the rupture surface. :param mesh: An instance of :class:`openquake.hazardlib.geo.mesh` :return: An :class:`numpy.ndarray` instance with the azimuth values. """ mesh_closest = self.get_closest_points(mesh) return geodetic.azimuth(mesh.lons, mesh.lats, mesh_closest.lons, mesh_closest.lats)
def get_strike(self) -> float: """ Return the fault strike as the average strike along the top of the fault surface. :returns: The average strike, in decimal degrees. """ if self.strike is None: idx = np.isfinite(self.mesh.lons) azi = azimuth(self.mesh.lons[:-1, :], self.mesh.lats[:-1, :], self.mesh.lons[1:, :], self.mesh.lats[1:, :]) self.strike = np.mean(((azi[idx[:-1, :]] + 0.001) % 360)) return self.strike
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 azimuth(self, point): """ Compute the azimuth (in decimal degrees) between this point and the given point. :param point: Destination point. :type point: Instance of :class:`Point` :returns: The azimuth, value in a range ``[0, 360)``. :rtype: float """ return geodetic.azimuth(self.longitude, self.latitude, point.longitude, point.latitude)
def azimuth(self, point): """ Compute the azimuth (in decimal degrees) between this point and the given point. :param point: Destination point. :type point: Instance of :class:`Point` :returns: The azimuth, value in a range ``[0, 360)``. :rtype: float """ return geodetic.azimuth(self.longitude, self.latitude, point.longitude, point.latitude)
def test_plot_rupture(interactive=False): xp0 = np.array([-90.898000]) xp1 = np.array([-91.308000]) yp0 = np.array([12.584000]) yp1 = np.array([12.832000]) zp = [0.0] strike = azimuth(yp0[0], xp0[0], yp1[0], xp1[0]) origin = Origin({ 'lat': 0.0, 'lon': 0.0, 'depth': 0.0, 'mag': 5.5, 'id': '', 'netid': 'abcd', 'network': '', 'locstring': '', 'time': HistoricTime.utcfromtimestamp(time.time()) }) interface_width = MAX_DEPTH / np.sin(np.radians(DIP)) widths = np.ones(xp0.shape) * interface_width dips = np.ones(xp0.shape) * DIP strike = [strike] rupture = QuadRupture.fromTrace(xp0, yp0, xp1, yp1, zp, widths, dips, origin, strike=strike) plot_rupture_wire3d(rupture) if interactive: fname = os.path.join(os.path.expanduser('~'), 'rupture_wire_plot.png') plt.savefig(fname) print('Wire 3D plot saved to %s. Delete this file if you wish.' % fname) # Need to get tests to check exception for if an axis is handed off fig = plt.figure() ax = fig.add_subplot(111, projection='3d') plot_rupture_wire3d(rupture, ax) # And raise the exception if it is not a 3d axis with pytest.raises(TypeError): ax = fig.add_subplot(111) plot_rupture_wire3d(rupture, ax)
def resample(self, distance): """ This resamples the trench axis given a certain distance and computes the strike at each node. :parameter distance: The sampling distance [in km """ naxis = rsmpl(self.axis[:, 0], self.axis[:, 1], distance) if len(self.axis) < 3: raise ValueError('Small array') # # compute azimuths az = numpy.zeros_like(self.axis[:, 0]) az[1:-1] = azimuth(self.axis[:-2, 0], self.axis[:-2, 1], self.axis[2:, 0], self.axis[2:, 1]) az[0] = az[1] az[-1] = az[-2] return Trench(naxis, az)
def get_compass_dir(lat1, lon1, lat2, lon2, format='short'): """Get the nearest string compass direction between two points. :param lat1: Latitude of first point. :param lon1: Longitude of first point. :param lat2: Latitude of second point. :param lon2: Longitude of second point. :param format: String used to determine the type of output. ('short','long'). :returns: String compass direction, in the form of 'North','Northeast',... if format is 'long', or 'N','NE',... if format is 'short'. """ if format != 'short': points = ['North', 'Northeast', 'East', 'Southeast', 'South', 'Southwest', 'West', 'Northwest'] else: points = ['N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW'] az = geodetic.azimuth(lon1, lat1, lon2, lat2) angles = np.arange(0, 360, 45) adiff = abs(az - angles) i = adiff.argmin() return points[i]
def get_polygon_from_simple_fault(flt): """ """ xtrace = [] ytrace = [] if isinstance(flt, SimpleFaultSource): trc = flt.fault_trace elif isinstance(flt, OQtSource): trc = flt.trace for pnt in trc: xtrace.append(pnt.longitude) ytrace.append(pnt.latitude) # # Get strike direction azim = azimuth(xtrace[0], ytrace[0], xtrace[-1], ytrace[-1]) # # Compute the dip direction dip = flt.dip dip_dir = (azim + 90) % 360 seism_thickness = flt.lower_seismogenic_depth - flt.upper_seismogenic_depth # # Horizontal distance h_dist = seism_thickness / scipy.tan(scipy.radians(dip)) # # Compute the bottom trace xb = xtrace yb = ytrace for x, y in zip(xtrace[::-1], ytrace[::-1]): nx, ny = point_at(x, y, dip_dir, h_dist) xb.append(nx) yb.append(ny) # Create the polygon geometry pnt_list = [] for x, y in zip(xb, yb): pnt_list.append((x, y)) return pnt_list
def get_azimuth(self, mesh): """ This method computes the azimuth of a set of points in a :class:`openquake.hazardlib.geo.mesh` instance. The reference used for the calculation of azimuth is the middle point and the strike of the rupture. The value of azimuth computed corresponds to the angle measured in a clockwise direction from the strike of the rupture. :parameter mesh: An instance of :class:`openquake.hazardlib.geo.mesh` :return: An instance of `numpy.ndarray` """ # Get info about the rupture strike = self.get_strike() hypocenter = self.get_middle_point() # This is the azimuth from the north of each point Vs. the middle of # the rupture azim = geodetic.azimuth(hypocenter.longitude, hypocenter.latitude, mesh.lons, mesh.lats) # Compute the azimuth from the fault strike rel_azi = (azim - strike) % 360 return rel_azi
def get_azimuth(self, mesh): """ This method computes the azimuth of a set of points in a :class:`openquake.hazardlib.geo.mesh` instance. The reference used for the calculation of azimuth is the middle point and the strike of the rupture. The value of azimuth computed corresponds to the angle measured in a clockwise direction from the strike of the rupture. :parameter mesh: An instance of :class:`openquake.hazardlib.geo.mesh` :return: An instance of `numpy.ndarray` """ # Get info about the rupture strike = self.get_strike() hypocenter = self.get_middle_point() # This is the azimuth from the north of each point Vs. the middle of # the rupture azim = geodetic.azimuth(hypocenter.longitude, hypocenter.latitude, mesh.lons, mesh.lats) # Compute the azimuth from the fault strike rel_azi = (azim - strike) % 360 return rel_azi
def test_plot_rupture(interactive=False): xp0 = np.array([-90.898000]) xp1 = np.array([-91.308000]) yp0 = np.array([12.584000]) yp1 = np.array([12.832000]) zp = [0.0] strike = azimuth(yp0[0], xp0[0], yp1[0], xp1[0]) origin = Origin({ 'lat': 0.0, 'lon': 0.0, 'depth': 0.0, 'mag': 5.5, 'id': '', 'netid': 'abcd', 'network': '', 'locstring': '', 'time': HistoricTime.utcfromtimestamp(time.time()) }) interface_width = MAX_DEPTH / np.sin(np.radians(DIP)) widths = np.ones(xp0.shape) * interface_width dips = np.ones(xp0.shape) * DIP strike = [strike] rupture = QuadRupture.fromTrace(xp0, yp0, xp1, yp1, zp, widths, dips, origin, strike=strike) plot_rupture_wire3d(rupture) if interactive: fname = os.path.join(os.path.expanduser('~'), 'rupture_wire_plot.png') plt.savefig(fname) print('Wire 3D plot saved to %s. Delete this file if you wish.' % fname)
def test_map_rupture(interactive=False): xp0 = np.array([-90.898000]) xp1 = np.array([-91.308000]) yp0 = np.array([12.584000]) yp1 = np.array([12.832000]) zp = [0.0] strike = azimuth(yp0[0], xp0[0], yp1[0], xp1[0]) origin = Origin({'lat': 0.0, 'lon': 0.0, 'depth': 0.0, 'mag': 5.5, 'eventsourcecode': 'abcd'}) interface_width = MAX_DEPTH / np.sin(np.radians(DIP)) widths = np.ones(xp0.shape) * interface_width dips = np.ones(xp0.shape) * DIP strike = [strike] rupture = QuadRupture.fromTrace( xp0, yp0, xp1, yp1, zp, widths, dips, origin, strike=strike) map_rupture(rupture) if interactive: fname = os.path.join(os.path.expanduser('~'), 'rupture_map.png') plt.savefig(fname) print('Rupture map plot saved to %s. Delete this file if you wish.' % fname)
def _get_cell_area(rlo, rla, coo, nnidx): """ :parameter rlo: :parameter rla: :parameter coo: :parameter nnidx: :return: """ alo = [coo[idx][0] for idx in nnidx] ala = [coo[idx][1] for idx in nnidx] # # Computing azimuths and distances azis = azimuth(rlo, rla, alo, ala) dsts = geodetic_distance(rlo, rla, alo, ala) # # Processing the selected nodes delta = 5.0 colocated = 0 nearest_nodes = {} for azi, dst, idx in zip(azis, dsts, nnidx): if dst < 0.5: if (abs(rlo - coo[idx][0]) < 0.005 and abs(rla - coo[idx][1]) < 0.005): colocated += 1 continue # East if abs(azi - 90) < delta: if 90 in nearest_nodes: if dst < nearest_nodes[90][0]: nearest_nodes[90] = (dst, idx) else: nearest_nodes[90] = (dst, idx) # South elif abs(azi - 180) < delta: if 180 in nearest_nodes: if dst < nearest_nodes[180][0]: nearest_nodes[180] = (dst, idx) else: nearest_nodes[180] = (dst, idx) # West elif abs(azi - 270) < delta: if 270 in nearest_nodes: if dst < nearest_nodes[270][0]: nearest_nodes[270] = (dst, idx) else: nearest_nodes[270] = (dst, idx) # North elif abs(azi - 360) < delta or azi < delta: if 0 in nearest_nodes: if dst < nearest_nodes[0][0]: nearest_nodes[0] = (dst, idx) else: nearest_nodes[0] = (dst, idx) else: pass # # fix missing information out = np.nan try: fdsts = _get_final_dsts(nearest_nodes) out = (fdsts[0] + fdsts[2]) / 2 * (fdsts[1] + fdsts[3]) / 2 except: pass logging.debug('Node:', rlo, rla) logging.debug('Nearest nodes:', nearest_nodes) logging.debug('Queried nodes:') for idx in nnidx: logging.debug(' ', coo[idx][0], coo[idx][1], coo[idx][2]) return out, colocated
def test_rupture_depth(interactive=False): DIP = 17.0 WIDTH = 20.0 GRIDRES = 0.1 names = ['single', 'double', 'triple', 'concave', 'concave_simple', 'ANrvSA'] means = [3.1554422780092461, 2.9224454569459781, 3.0381968625073563, 2.0522694624400271, 2.4805390352818755, 2.8740121776209673] stds = [2.1895293825074575, 2.0506459673526174, 2.0244588429154402, 2.0112565876976416, 2.1599789955270019, 1.6156220309120068] xp0list = [np.array([118.3]), np.array([10.1, 10.1]), np.array([10.1, 10.1, 10.3]), np.array([10.9, 10.5, 10.9]), np.array([10.9, 10.6]), np.array([-76.483, -76.626, -76.757, -76.99, -77.024, -76.925, -76.65, -76.321, -75.997, -75.958])] xp1list = [np.array([118.3]), np.array([10.1, 10.3]), np.array([10.1, 10.3, 10.1]), np.array([10.5, 10.9, 11.3]), np.array([10.6, 10.9]), np.array([-76.626, -76.757, -76.99, -77.024, -76.925, -76.65, -76.321, -75.997, -75.958, -76.006])] yp0list = [np.array([34.2]), np.array([34.2, 34.5]), np.array([34.2, 34.5, 34.8]), np.array([34.2, 34.5, 34.8]), np.array([35.1, 35.2]), np.array([-52.068, -51.377, -50.729, -49.845, -49.192, -48.507, -47.875, -47.478, -47.08, -46.422])] yp1list = [np.array([34.5]), np.array([34.5, 34.8]), np.array([34.5, 34.8, 35.1]), np.array([34.5, 34.8, 34.6]), np.array([35.2, 35.4]), np.array([-51.377, -50.729, -49.845, -49.192, -48.507, -47.875, -47.478, -47.08, -46.422, -45.659])] for i in range(0, len(xp0list)): xp0 = xp0list[i] xp1 = xp1list[i] yp0 = yp0list[i] yp1 = yp1list[i] name = names[i] mean_value = means[i] std_value = stds[i] zp = np.zeros(xp0.shape) strike = azimuth(xp0[0], yp0[0], xp1[-1], yp1[-1]) widths = np.ones(xp0.shape) * WIDTH dips = np.ones(xp0.shape) * DIP strike = [strike] origin = Origin({'id': 'test', 'lon': 0, 'lat': 0, 'depth': 5.0, 'mag': 7.0, 'netid': 'us', 'network': '', 'locstring': '', 'time': HistoricTime.utcfromtimestamp(time.time())}) rupture = QuadRupture.fromTrace( xp0, yp0, xp1, yp1, zp, widths, dips, origin, strike=strike) # make a grid of points over both quads, ask for depths ymin = np.nanmin(rupture.lats) ymax = np.nanmax(rupture.lats) xmin = np.nanmin(rupture.lons) xmax = np.nanmax(rupture.lons) xmin = np.floor(xmin * (1 / GRIDRES)) / (1 / GRIDRES) xmax = np.ceil(xmax * (1 / GRIDRES)) / (1 / GRIDRES) ymin = np.floor(ymin * (1 / GRIDRES)) / (1 / GRIDRES) ymax = np.ceil(ymax * (1 / GRIDRES)) / (1 / GRIDRES) geodict = GeoDict.createDictFromBox( xmin, xmax, ymin, ymax, GRIDRES, GRIDRES) nx = geodict.nx ny = geodict.ny depths = np.zeros((ny, nx)) for row in range(0, ny): for col in range(0, nx): lat, lon = geodict.getLatLon(row, col) depth = rupture.getDepthAtPoint(lat, lon) depths[row, col] = depth np.testing.assert_almost_equal(np.nanmean(depths), mean_value) np.testing.assert_almost_equal(np.nanstd(depths), std_value) if interactive: fig, axes = plt.subplots(nrows=2, ncols=1) ax1, ax2 = axes xdata = np.append(xp0, xp1[-1]) ydata = np.append(yp0, yp1[-1]) plt.sca(ax1) plt.plot(xdata, ydata, 'b') plt.sca(ax2) im = plt.imshow(depths, cmap='viridis_r') # noqa ch = plt.colorbar() # noqa fname = os.path.join(os.path.expanduser('~'), 'quad_%s_test.png' % name) print('Saving image for %s quad test... %s' % (name, fname)) plt.savefig(fname) plt.close()
def _resample_profile(line, sampling_dist): """ :parameter line: An instance of :class:`openquake.hazardlib.geo.line.Line` :parameter sampling_dist: A scalar definining the distance used to sample the profile :returns: An instance of :class:`openquake.hazardlib.geo.line.Line` """ lo = [pnt.longitude for pnt in line.points] la = [pnt.latitude for pnt in line.points] de = [pnt.depth for pnt in line.points] # # initialise the cumulated distance cdist = 0. # # get the azimuth of the profile azim = azimuth(lo[0], la[0], lo[-1], la[-1]) # # initialise the list with the resampled nodes idx = 0 resampled_cs = [Point(lo[idx], la[idx], de[idx])] # # set the starting point slo = lo[idx] sla = la[idx] sde = de[idx] # # resampling while 1: # # check loop exit condition if idx > len(lo) - 2: break # # compute the distance between the starting point and the next point # on the profile segment_len = distance(slo, sla, sde, lo[idx + 1], la[idx + 1], de[idx + 1]) # # search for the point if cdist + segment_len > sampling_dist: # # this is the lenght of the last segment-fraction needed to # obtain the sampling distance delta = sampling_dist - cdist # # compute the slope of the last segment and its horizontal length. # We need to manage the case of a vertical segment TODO segment_hlen = distance(slo, sla, 0., lo[idx + 1], la[idx + 1], 0.) segment_slope = np.arctan((de[idx + 1] - sde) / segment_hlen) # # horizontal and vertical lenght of delta delta_v = delta * np.sin(segment_slope) delta_h = delta * np.cos(segment_slope) # # add a new point to the cross section pnts = npoints_towards(slo, sla, sde, azim, delta_h, delta_v, 2) # # update the starting point slo = pnts[0][-1] sla = pnts[1][-1] sde = pnts[2][-1] resampled_cs.append(Point(slo, sla, sde)) # # reset the cumulative distance cdist = 0. else: cdist += segment_len idx += 1 slo = lo[idx] sla = la[idx] sde = de[idx] line = Line(resampled_cs) return line
def store(filename, model, info=None): """ This creates a pickle file containing the list of earthquake sources representing an earthquake source model. :parameter filename: The name of the file where the to store the model :parameter model: A list of OpenQuake hazardlib source instances """ # Preparing output filenames dname = os.path.dirname(filename) slist = re.split('\\.', os.path.basename(filename)) # SIDx p = index.Property() p.dimension = 3 sidx = index.Rtree(os.path.join(dname, slist[0]), properties=p) # cpnt = 0 l_other = [] l_points = [] for src in model: if isinstance(src, (AreaSource, SimpleFaultSource, ComplexFaultSource, CharacteristicFaultSource, NonParametricSeismicSource)): l_other.append(src) else: if len(src.hypocenter_distribution.data) == 1: srcs = [src] else: srcs = _split_point_source(src) for src in srcs: l_points.append(src) # calculate distances dst = distance(l_points[0].location.longitude, l_points[0].location.latitude, 0., src.location.longitude, src.location.latitude, 0.) azi = azimuth(l_points[0].location.longitude, l_points[0].location.latitude, src.location.longitude, src.location.latitude) x = numpy.cos(numpy.radians(azi)) * dst y = numpy.sin(numpy.radians(azi)) * dst # update the spatial index z = src.hypocenter_distribution.data[0][1] sidx.insert(cpnt, (x, y, z, x, y, z)) cpnt += 1 # All the other sources fou = open(filename, 'wb') pickle.dump(l_other, fou) fou.close() # Load info if info is None: info = _get_model_info(model) # Points fou = open(os.path.join(dname, slist[0]) + '_points.pkl', 'wb') pickle.dump(l_points, fou) fou.close() # Info fou = open(os.path.join(dname, slist[0]) + '_info.pkl', 'wb') pickle.dump(info, fou) fou.close()
def test_quadrants(self): az = geodetic.azimuth(0, 0, [0.01, 0.01, -0.01, -0.01], [0.01, -0.01, -0.01, 0.01]) assert_aeq(az, [45, 135, 225, 315], decimal=5)
def test_quadrants(self): az = geodetic.azimuth(0, 0, [0.01, 0.01, -0.01, -0.01], [0.01, -0.01, -0.01, 0.01]) assert_aeq(az, [45, 135, 225, 315], decimal=5)
def test_meridians(self): az = geodetic.azimuth(0, 0, 0, 1) self.assertEqual(az, 0) az = geodetic.azimuth(0, 2, 0, 1) self.assertEqual(az, 180)
def test_LAX_to_JFK(self): az = geodetic.azimuth(*(LAX + JFK)) self.assertAlmostEqual(az, 360 - 65.8922, places=4)
def _resample_edge_with_direction(edge, sampling_dist, reference_idx, direct=+1): """ :param edge: :param sampling_dist: :param reference_idx: :param direct: """ # # checking that the increment is either 1 or -1 assert abs(direct) == 1 # # create three lists: one with longitude, one with latitude and one with # depth lo = [pnt.longitude for pnt in edge.points] la = [pnt.latitude for pnt in edge.points] de = [pnt.depth for pnt in edge.points] # # initialise the variable used to store the cumulated distance cdist = 0. # # initialise the list with the resampled nodes idx = reference_idx resampled_cs = [Point(lo[idx], la[idx], de[idx])] # # set the starting point slo = lo[idx] sla = la[idx] sde = de[idx] # # get the azimuth of the first segment on the edge in the given direction azim = azimuth(lo[idx], la[idx], lo[idx + direct], la[idx + direct]) # # resampling old_dst = 1.e10 while 1: # # this is a sanity check assert idx <= len(lo) - 1 # # check loop exit condition if direct > 0 and idx > len(lo) - 1: break if direct < 0 and idx < 1: break # # compute the distance between the starting point and the next point # on the profile segment_len = distance(slo, sla, sde, lo[idx + direct], la[idx + direct], de[idx + direct]) # # search for the point if cdist + segment_len > sampling_dist: # # check if segment_len > old_dst: print(segment_len, '>', old_dst) raise ValueError('The segment length is increasing') else: old_dst = segment_len # # this is the lenght of the last segment-fraction needed to # obtain the sampling distance delta = sampling_dist - cdist # # compute the slope of the last segment and its horizontal length. # we need to manage the case of a vertical segment TODO segment_hlen = distance(slo, sla, 0., lo[idx + direct], la[idx + direct], 0.) segment_slope = np.arctan((de[idx + direct] - sde) / segment_hlen) # # horizontal and vertical lenght of delta delta_v = delta * np.sin(segment_slope) delta_h = delta * np.cos(segment_slope) # # add a new point to the cross section pnts = npoints_towards(slo, sla, sde, azim, delta_h, delta_v, 2) # # update the starting point slo = pnts[0][-1] sla = pnts[1][-1] sde = pnts[2][-1] # # checking distance between the reference point and latest point # included in the resampled section pnt = resampled_cs[-1] checkd = distance(slo, sla, sde, pnt.longitude, pnt.latitude, pnt.depth) # >>> TOLERANCE if (cdist < 1e-2 and abs(checkd - sampling_dist) > 0.05 * sampling_dist): print(checkd, sampling_dist) msg = 'Segment distance different than sampling dst' raise ValueError(msg) # # updating the resample cross-section resampled_cs.append(Point(slo, sla, sde)) # # tot = distance(lo[idx], la[idx], de[idx], lo[idx + direct], la[idx + direct], de[idx + direct]) downd = distance(slo, sla, sde, lo[idx], la[idx], de[idx]) upd = distance(slo, sla, sde, lo[idx + direct], la[idx + direct], de[idx + direct]) # # >>> TOLERANCE if abs(tot - (downd + upd)) > tot * 0.05: print(' upd, downd, tot', upd, downd, tot) print(abs(tot - (downd + upd))) raise ValueError('Distances are not matching') # # reset the cumulative distance cdist = 0. else: # print('aa', cdist, segment_len, sampling_dist) # print(' ', idx, len(lo)-1, direct) # # old_dst = 1.e10 cdist += segment_len idx += direct slo = lo[idx] sla = la[idx] sde = de[idx] # # get the azimuth of the profile if idx < len(lo) - 1: azim = azimuth(lo[idx], la[idx], lo[idx + direct], la[idx + direct]) else: break # # return resampled_cs
def test_quadrants(self): az = geodetic.azimuth(0, 0, [0.01, 0.01, -0.01, -0.01], [0.01, -0.01, -0.01, 0.01]) self.assertTrue(numpy.allclose(az, [45, 135, 225, 315]), str(az))
def test_equator(self): az = geodetic.azimuth(0, 0, 1, 0) self.assertEqual(az, 90) az = geodetic.azimuth(1, 0, 0, 0) self.assertEqual(az, 270)
def test_rupture_depth(interactive=False): DIP = 17.0 WIDTH = 20.0 GRIDRES = 0.1 names = ['single', 'double', 'triple', 'concave', 'concave_simple', 'ANrvSA'] means = [3.1554422780092461, 2.9224454569459781, 3.0381968625073563, 2.0522694624400271, 2.4805390352818755, 2.8740121776209673] stds = [2.1895293825074575, 2.0506459673526174, 2.0244588429154402, 2.0112565876976416, 2.1599789955270019, 1.6156220309120068] xp0list = [np.array([118.3]), np.array([10.1, 10.1]), np.array([10.1, 10.1, 10.3]), np.array([10.9, 10.5, 10.9]), np.array([10.9, 10.6]), np.array([-76.483, -76.626, -76.757, -76.99, -77.024, -76.925, -76.65, -76.321, -75.997, -75.958])] xp1list = [np.array([118.3]), np.array([10.1, 10.3]), np.array([10.1, 10.3, 10.1]), np.array([10.5, 10.9, 11.3]), np.array([10.6, 10.9]), np.array([-76.626, -76.757, -76.99, -77.024, -76.925, -76.65, -76.321, -75.997, -75.958, -76.006])] yp0list = [np.array([34.2]), np.array([34.2, 34.5]), np.array([34.2, 34.5, 34.8]), np.array([34.2, 34.5, 34.8]), np.array([35.1, 35.2]), np.array([-52.068, -51.377, -50.729, -49.845, -49.192, -48.507, -47.875, -47.478, -47.08, -46.422])] yp1list = [np.array([34.5]), np.array([34.5, 34.8]), np.array([34.5, 34.8, 35.1]), np.array([34.5, 34.8, 34.6]), np.array([35.2, 35.4]), np.array([-51.377, -50.729, -49.845, -49.192, -48.507, -47.875, -47.478, -47.08, -46.422, -45.659])] for i in range(0, len(xp0list)): xp0 = xp0list[i] xp1 = xp1list[i] yp0 = yp0list[i] yp1 = yp1list[i] name = names[i] mean_value = means[i] std_value = stds[i] zp = np.zeros(xp0.shape) strike = azimuth(xp0[0], yp0[0], xp1[-1], yp1[-1]) widths = np.ones(xp0.shape) * WIDTH dips = np.ones(xp0.shape) * DIP strike = [strike] origin = Origin({'eventsourcecode': 'test', 'lat': 0, 'lon': 0, 'depth': 5.0, 'mag': 7.0}) rupture = QuadRupture.fromTrace( xp0, yp0, xp1, yp1, zp, widths, dips, origin, strike=strike) # make a grid of points over both quads, ask for depths ymin = np.nanmin(rupture.lats) ymax = np.nanmax(rupture.lats) xmin = np.nanmin(rupture.lons) xmax = np.nanmax(rupture.lons) xmin = np.floor(xmin * (1 / GRIDRES)) / (1 / GRIDRES) xmax = np.ceil(xmax * (1 / GRIDRES)) / (1 / GRIDRES) ymin = np.floor(ymin * (1 / GRIDRES)) / (1 / GRIDRES) ymax = np.ceil(ymax * (1 / GRIDRES)) / (1 / GRIDRES) geodict = GeoDict.createDictFromBox( xmin, xmax, ymin, ymax, GRIDRES, GRIDRES) nx = geodict.nx ny = geodict.ny depths = np.zeros((ny, nx)) for row in range(0, ny): for col in range(0, nx): lat, lon = geodict.getLatLon(row, col) depth = rupture.getDepthAtPoint(lat, lon) depths[row, col] = depth np.testing.assert_almost_equal(np.nanmean(depths), mean_value) np.testing.assert_almost_equal(np.nanstd(depths), std_value) if interactive: fig, axes = plt.subplots(nrows=2, ncols=1) ax1, ax2 = axes xdata = np.append(xp0, xp1[-1]) ydata = np.append(yp0, yp1[-1]) plt.sca(ax1) plt.plot(xdata, ydata, 'b') plt.sca(ax2) im = plt.imshow(depths, cmap='viridis_r') # noqa ch = plt.colorbar() # noqa fname = os.path.join(os.path.expanduser('~'), 'quad_%s_test.png' % name) print('Saving image for %s quad test... %s' % (name, fname)) plt.savefig(fname) plt.close()
def rsmpl_unsure(ix, iy, sampling_dist): direct = 1 idx = 0 # # create three lists: one with longitude, one with latitude and one with # depth lo = list(ix) la = list(iy) de = list(numpy.zeros_like(ix)) # # initialise the variable used to store the cumulated distance cdist = 0. # # set the starting point slo = lo[idx] sla = la[idx] sde = de[idx] # # get the azimuth of the first segment on the edge in the given direction azim = azimuth(lo[idx], la[idx], lo[idx + direct], la[idx + direct]) # # initialise the list with the resampled nodes resampled_cs = [[lo[idx], la[idx], azim]] # # resampling while 1: # # this is a sanity check assert idx <= len(lo) - 1 # # check loop exit condition if direct > 0 and idx > len(lo) - 1: break # # compute the distance between the starting point and the next point # on the profile segment_len = distance(slo, sla, sde, lo[idx + direct], la[idx + direct], de[idx + direct]) # # search for the point if cdist + segment_len > sampling_dist: # # this is the lenght of the last segment-fraction needed to # obtain the sampling distance delta = sampling_dist - cdist # # add a new point to the cross section pnts = npoints_towards(slo, sla, sde, azim, delta, 0., 2) # # update the starting point slo = pnts[0][-1] sla = pnts[1][-1] sde = pnts[2][-1] resampled_cs.append([slo, sla, azim]) # # reset the cumulative distance cdist = 0. else: cdist += segment_len idx += direct slo = lo[idx] sla = la[idx] sde = de[idx] # # get the azimuth of the profile if idx < len(lo) - 1: azim = azimuth(lo[idx], la[idx], lo[idx + direct], la[idx + direct]) else: break # code.interact(local=locals()) return numpy.array(resampled_cs)
def _resample_profile(line, sampling_dist): # TODO split this function into smaller components. """ :parameter line: An instance of :class:`openquake.hazardlib.geo.line.Line` :parameter sampling_dist: A scalar definining the distance [km] used to sample the profile :returns: An instance of :class:`openquake.hazardlib.geo.line.Line` """ lo = [pnt.longitude for pnt in line.points] la = [pnt.latitude for pnt in line.points] de = [pnt.depth for pnt in line.points] # Set projection g = Geod(ellps='WGS84') # Add a tolerance length to the last point of the profile # check that final portion of the profile is not vertical if abs(lo[-2] - lo[-1]) > 1e-5 and abs(la[-2] - la[-1]) > 1e-5: az12, _, odist = g.inv(lo[-2], la[-2], lo[-1], la[-1]) odist /= 1e3 slope = np.arctan((de[-1] - de[-2]) / odist) hdist = TOL * sampling_dist * np.cos(slope) vdist = TOL * sampling_dist * np.sin(slope) endlon, endlat, _ = g.fwd(lo[-1], la[-1], az12, hdist * 1e3) lo[-1] = endlon la[-1] = endlat de[-1] = de[-1] + vdist az12, _, odist = g.inv(lo[-2], la[-2], lo[-1], la[-1]) # Checking odist /= 1e3 slopec = np.arctan((de[-1] - de[-2]) / odist) assert abs(slope - slopec) < 1e-3 else: de[-1] = de[-1] + TOL * sampling_dist # Initialise the cumulated distance cdist = 0. # Get the azimuth of the profile azim = azimuth(lo[0], la[0], lo[-1], la[-1]) # Initialise the list with the resampled nodes idx = 0 resampled_cs = [Point(lo[idx], la[idx], de[idx])] # Set the starting point slo = lo[idx] sla = la[idx] sde = de[idx] # Resampling while 1: # Check loop exit condition if idx > len(lo) - 2: break # Compute the distance between the starting point and the next point # on the profile segment_len = distance(slo, sla, sde, lo[idx + 1], la[idx + 1], de[idx + 1]) # Search for the point if cdist + segment_len > sampling_dist: # This is the lenght of the last segment-fraction needed to # obtain the sampling distance delta = sampling_dist - cdist # Compute the slope of the last segment and its horizontal length. # We need to manage the case of a vertical segment TODO segment_hlen = distance(slo, sla, 0., lo[idx + 1], la[idx + 1], 0.) if segment_hlen > 1e-5: segment_slope = np.arctan((de[idx + 1] - sde) / segment_hlen) else: segment_slope = 90. # Horizontal and vertical lenght of delta delta_v = delta * np.sin(segment_slope) delta_h = delta * np.cos(segment_slope) # Add a new point to the cross section pnts = npoints_towards(slo, sla, sde, azim, delta_h, delta_v, 2) # Update the starting point slo = pnts[0][-1] sla = pnts[1][-1] sde = pnts[2][-1] resampled_cs.append(Point(slo, sla, sde)) # Reset the cumulative distance cdist = 0. else: cdist += segment_len idx += 1 slo = lo[idx] sla = la[idx] sde = de[idx] # Check the distances along the profile coo = [[pnt.longitude, pnt.latitude, pnt.depth] for pnt in resampled_cs] coo = np.array(coo) for i in range(0, coo.shape[0] - 1): dst = distance(coo[i, 0], coo[i, 1], coo[i, 2], coo[i + 1, 0], coo[i + 1, 1], coo[i + 1, 2]) if abs(dst - sampling_dist) > 0.1 * sampling_dist: raise ValueError('Wrong distance between points along the profile') return Line(resampled_cs)