Example #1
0
File: smooth.py Project: gem/oq-mbt
	def gaussian(self, radius, sigma):
		# Values
		values = numpy.zeros((len(self.mesh)))
		# Compute the number of expected nodes
		numpnts = consts.pi*radius**2/(self.cellsize**2)
		# Smoothing the catalogue
		for lon, lat, mag in zip(self.catalogue.data['longitude'],
								 self.catalogue.data['latitude'],
								 self.catalogue.data['magnitude']):
			# set the bounding box
			minlon, minlat = point_at(lon, lat, 225, radius*2**0.5)
			maxlon, maxlat = point_at(lon, lat, 45, radius*2**0.5) 
			# find nodes within the bounding box
			idxs = list(self.rtree.intersection((minlon, 
					                             minlat, 
			                                     maxlon, 
			                                     maxlat)))
			# get distances
			dsts = min_geodetic_distance(lon, lat, 
			                             self.mesh.lons[idxs],
			                             self.mesh.lats[idxs])   
			jjj = numpy.nonzero(dsts < 50)[0]
			idxs = numpy.array(idxs)
			iii = idxs[jjj]
			# set values
			tmpvalues= numpy.exp(-dsts[jjj]/sigma**2)
			normfact = sum(tmpvalues)
			values[iii] += tmpvalues/normfact
		return values
Example #2
0
    def test(self):
        lon, lat = geodetic.point_at(10.0, 20.0, 30.0, 50.0)
        self.assertAlmostEqual(lon, 10.239856504796101, places=6)
        self.assertAlmostEqual(lat, 20.38925590463351, places=6)

        lon, lat = geodetic.point_at(-13.5, 22.4, -140.0, 120.0)
        self.assertAlmostEqual(lon, -14.245910669126582, places=6)
        self.assertAlmostEqual(lat, 21.57159463157223, places=6)
def sample_aftershock_coords(mainshock,
                             n_aftershocks,
                             min_width=5,
                             min_depth=4,
                             max_depth=20.):
    main_midpt_lat = mainshock.surface.get_middle_point().latitude
    main_midpt_lon = mainshock.surface.get_middle_point().longitude

    width = mainshock.surface.get_width()
    length = mainshock.surface.get_area() / width
    surface_width = width * np.sin(np.radians(mainshock.surface.get_dip()))
    if surface_width < min_width:
        surface_width = min_width

    along_strike_distance = length * inverse_transform_sample(
        aft_axis_distance, aft_distance_probs, n_aftershocks)

    strike_perp_distance = width * inverse_transform_sample(
        aft_axis_distance, aft_distance_probs, n_aftershocks)
    aftershock_dists = np.sqrt(along_strike_distance**2 +
                               strike_perp_distance**2)

    aftershock_angle_from_strike = np.degrees(
        np.arctan2(strike_perp_distance, along_strike_distance))

    aftershock_az = (aftershock_angle_from_strike +
                     mainshock.surface.get_strike())

    aftershock_lons, aftershock_lats = point_at(main_midpt_lon, main_midpt_lat,
                                                aftershock_az,
                                                aftershock_dists)

    aftershock_depths = np.random.uniform(min_depth, max_depth, n_aftershocks)

    return aftershock_lons, aftershock_lats, aftershock_depths
Example #4
0
    def point_at(self, horizontal_distance, vertical_increment, azimuth):
        """
        Compute the point with given horizontal, vertical distances
        and azimuth from this point.

        :param horizontal_distance:
            Horizontal distance, in km.
        :type horizontal_distance:
            float
        :param vertical_increment:
            Vertical increment, in km. When positive, the new point
            has a greater depth. When negative, the new point
            has a smaller depth.
        :type vertical_increment:
            float
        :type azimuth:
            Azimuth, in decimal degrees.
        :type azimuth:
            float
        :returns:
            The point at the given distances.
        :rtype:
            Instance of :class:`Point`
        """
        lon, lat = geodetic.point_at(self.longitude, self.latitude, azimuth,
                                     horizontal_distance)
        return Point(lon, lat, self.depth + vertical_increment)
Example #5
0
 def _set_vertexes(self):
     self.plo.append(self.olo)
     self.pla.append(self.ola)
     for lngh, strk in zip(self.length, self.strike):
         tlo, tla = point_at(self.plo[-1], self.pla[-1], strk, lngh)
         self.plo.append(tlo)
         self.pla.append(tla)
Example #6
0
    def point_at(self, horizontal_distance, vertical_increment, azimuth):
        """
        Compute the point with given horizontal, vertical distances
        and azimuth from this point.

        :param horizontal_distance:
            Horizontal distance, in km.
        :type horizontal_distance:
            float
        :param vertical_increment:
            Vertical increment, in km. When positive, the new point
            has a greater depth. When negative, the new point
            has a smaller depth.
        :type vertical_increment:
            float
        :type azimuth:
            Azimuth, in decimal degrees.
        :type azimuth:
            float
        :returns:
            The point at the given distances.
        :rtype:
            Instance of :class:`Point`
        """
        lon, lat = geodetic.point_at(self.longitude, self.latitude,
                                     azimuth, horizontal_distance)
        return Point(lon, lat, self.depth + vertical_increment)
Example #7
0
    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
Example #8
0
    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 _create_rupture(distance, magnitude,
                    tectonic_region_type=TRT.ACTIVE_SHALLOW_CRUST):
    # Return a rupture with a fixed geometry located at a given r_jb distance
    # from a site located at (0.0, 0.0).
    # parameter float distance:
    #    Joyner and Boore rupture-site distance
    # parameter float magnitude:
    #    Rupture magnitude

    # Find the point at a given distance
    lonp, latp = point_at(0.0, 0.0, 90., distance)
    mag = magnitude
    rake = 0.0
    tectonic_region_type = tectonic_region_type
    hypocenter = Point(lonp, latp, 2.5)
    surface = PlanarSurface.from_corner_points(
        Point(lonp, -1, 0.), Point(lonp, +1, 0.),
        Point(lonp, +1, 5.), Point(lonp, -1, 5.))
    surface = SimpleFaultSurface.from_fault_data(
        fault_trace=Line([Point(lonp, -1), Point(lonp, 1)]),
        upper_seismogenic_depth=0.0,
        lower_seismogenic_depth=5.0,
        dip=90.0,
        mesh_spacing=1.0)
    # check effective rupture-site distance
    from openquake.hazardlib.geo.mesh import Mesh
    mesh = Mesh(numpy.array([0.0]), numpy.array([0.0]))
    assert abs(surface.get_joyner_boore_distance(mesh)-distance) < 1e-2
    return BaseRupture(mag, rake, tectonic_region_type, hypocenter,
                       surface, NonParametricSeismicSource)
def _create_rupture(distance, magnitude,
                    tectonic_region_type=TRT.ACTIVE_SHALLOW_CRUST):
    # Return a rupture with a fixed geometry located at a given r_jb distance
    # from a site located at (0.0, 0.0).
    # parameter float distance:
    #    Joyner and Boore rupture-site distance
    # parameter float magnitude:
    #    Rupture magnitude

    # Find the point at a given distance
    lonp, latp = point_at(0.0, 0.0, 90., distance)
    mag = magnitude
    rake = 0.0
    tectonic_region_type = tectonic_region_type
    hypocenter = Point(lonp, latp, 2.5)
    surface = PlanarSurface.from_corner_points(
        Point(lonp, -1, 0.), Point(lonp, +1, 0.),
        Point(lonp, +1, 5.), Point(lonp, -1, 5.))
    surface = SimpleFaultSurface.from_fault_data(
        fault_trace=Line([Point(lonp, -1), Point(lonp, 1)]),
        upper_seismogenic_depth=0.0,
        lower_seismogenic_depth=5.0,
        dip=90.0,
        mesh_spacing=1.0)
    # check effective rupture-site distance
    from openquake.hazardlib.geo.mesh import Mesh
    mesh = Mesh(numpy.array([0.0]), numpy.array([0.0]))
    assert abs(surface.get_joyner_boore_distance(mesh)-distance) < 1e-2
    return BaseRupture(mag, rake, tectonic_region_type, hypocenter,
                       surface, NonParametricSeismicSource)
Example #11
0
    def discretize(self, mesh_spacing):
        """
        Get a mesh of uniformly spaced points inside the polygon area
        with distance of ``mesh_spacing`` km between.

        :returns:
            An instance of :class:`~openquake.hazardlib.geo.mesh.Mesh` that
            holds the points data. Mesh is created with no depth information
            (all the points are on the Earth surface).
        """
        self._init_polygon2d()

        west, east, north, south = self._bbox

        lons = []
        lats = []

        # we cover the bounding box (in spherical coordinates) from highest
        # to lowest latitude and from left to right by longitude. we step
        # by mesh spacing distance (linear measure). we check each point
        # if it is inside the polygon and yield the point object, if so.
        # this way we produce an uniformly-spaced mesh regardless of the
        # latitude.
        latitude = north
        while latitude > south:
            longitude = west
            while utils.get_longitudinal_extent(longitude, east) > 0:
                # we use Cartesian space just for checking if a point
                # is inside of the polygon.
                x, y = self._projection(longitude, latitude)
                if self._polygon2d.contains(shapely.geometry.Point(x, y)):
                    lons.append(longitude)
                    lats.append(latitude)

                # move by mesh spacing along parallel...
                longitude, _, = geodetic.point_at(longitude, latitude, 90,
                                                  mesh_spacing)
            # ... and by the same distance along meridian in outer one
            _, latitude = geodetic.point_at(west, latitude, 180, mesh_spacing)

        lons = numpy.array(lons)
        lats = numpy.array(lats)

        return Mesh(lons, lats, depths=None)
Example #12
0
    def discretize(self, mesh_spacing):
        """
        Get a mesh of uniformly spaced points inside the polygon area
        with distance of ``mesh_spacing`` km between.

        :returns:
            An instance of :class:`~openquake.hazardlib.geo.mesh.Mesh` that
            holds the points data. Mesh is created with no depth information
            (all the points are on the Earth surface).
        """
        self._init_polygon2d()

        west, east, north, south = self._bbox

        lons = []
        lats = []

        # we cover the bounding box (in spherical coordinates) from highest
        # to lowest latitude and from left to right by longitude. we step
        # by mesh spacing distance (linear measure). we check each point
        # if it is inside the polygon and yield the point object, if so.
        # this way we produce an uniformly-spaced mesh regardless of the
        # latitude.
        latitude = north
        while latitude > south:
            longitude = west
            while utils.get_longitudinal_extent(longitude, east) > 0:
                # we use Cartesian space just for checking if a point
                # is inside of the polygon.
                x, y = self._projection(longitude, latitude)
                if self._polygon2d.contains(shapely.geometry.Point(x, y)):
                    lons.append(longitude)
                    lats.append(latitude)

                # move by mesh spacing along parallel...
                longitude, _, = geodetic.point_at(longitude, latitude,
                                                  90, mesh_spacing)
            # ... and by the same distance along meridian in outer one
            _, latitude = geodetic.point_at(west, latitude, 180, mesh_spacing)

        lons = numpy.array(lons)
        lats = numpy.array(lats)

        return Mesh(lons, lats, depths=None)
Example #13
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)
Example #14
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)
Example #15
0
    def __call__(self, event):

        if isinstance(event, KeyEvent):
            if event.key is 'd':
                print('----------------------')
                self.xs = []
                self.ys = []
                self.xp = []
                self.yp = []
                self.line.set_data(self.xp, self.yp)
                self.point.set_data(self.xs, self.ys)
                self.line.figure.canvas.draw()
                self.point.figure.canvas.draw()
                self.data = []
            elif event.key is 'f':
                dat = numpy.array(self.data)
                fname = './cs_%s.csv' % (self.csec.ids)
                numpy.savetxt(fname, dat)
                print('Section data saved to: %s' % (fname))
            else:
                pass

        else:
            olo = self.csec.olo
            ola = self.csec.ola
            assert len(self.csec.strike) == 1
            if event.xdata is not None:
                strike = self.csec.strike[0]
                nlo, nla = point_at(olo, ola, strike, event.xdata)

                cnt = len(self.xs)+1
                print('%03d, %+7.4f, %+7.4f, %6.2f' % (cnt, nlo, nla,
                                                       event.ydata))

                if event.inaxes != self.line.axes:
                    return

                self.xp.append(event.xdata)
                self.yp.append(event.ydata)
                self.xs.append(event.xdata)
                self.ys.append(event.ydata)
                self.data.append([nlo, nla, event.ydata])
                self.point.set_data(self.xs, self.ys)
                self.line.set_data(self.xs, self.ys)
                self.line.figure.canvas.draw()
                self.point.figure.canvas.draw()
Example #16
0
    def from_hypocenter(cls, hypoc, msr, mag, aratio, strike, dip, rake):
        """
        Create and return a planar surface given the hypocenter location
        and other rupture properties.

        :param hypoc:
            An instance of :class: `openquake.hazardlib.geo.point.Point`
        :param msr:
            The magnitude scaling relationship
            e.g. an instance of :class: `openquake.hazardlib.scalerel.WC1994`
        :param mag:
            The magnitude
        :param aratio:
            The rupture aspect ratio
        :param strike:
            The rupture strike
        :param dip:
            The rupture dip
        :param rake:
            The rupture rake

        """
        lon = hypoc.longitude
        lat = hypoc.latitude
        depth = hypoc.depth

        area = msr.get_median_area(mag, rake)
        width = (area / aratio)**0.5
        length = width * aratio

        height = width * numpy.sin(numpy.radians(dip))
        hdist = width * numpy.cos(numpy.radians(dip))
        # Move hor. 1/2 hdist in direction -90
        mid_top = point_at(lon, lat, strike - 90, hdist / 2)
        # Move hor. 1/2 hdist in direction +90
        mid_bot = point_at(lon, lat, strike + 90, hdist / 2)

        # compute corner points at the surface
        top_right = point_at(mid_top[0], mid_top[1], strike, length / 2)
        top_left = point_at(mid_top[0], mid_top[1], strike + 180, length / 2)
        bot_right = point_at(mid_bot[0], mid_bot[1], strike, length / 2)
        bot_left = point_at(mid_bot[0], mid_bot[1], strike + 180, length / 2)

        # compute corner points in 3D
        pbl = Point(bot_left[0], bot_left[1], depth + height / 2)
        pbr = Point(bot_right[0], bot_right[1], depth + height / 2)
        hei = depth - height / 2
        ptl = Point(top_left[0], top_left[1], hei)
        ptr = Point(top_right[0], top_right[1], hei)

        self = cls(strike, dip, ptl, ptr, pbr, pbl)
        return self
Example #17
0
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 test01(self):
        tmp_fname = 'trash'
        cs_length = 400
        cs_depth = 100
        intd = 100
        handle, tmp_fname = tempfile.mkstemp()
        print(tmp_fname)
        get_cs(self.trench, 'tmp.txt', cs_length, cs_depth, intd, 0, tmp_fname)

        if PLOT:
            _ = plt.figure()
            columns = ['lon', 'lat', 'dep', 'len', 'azim', 'id', 'fname']
            df = pd.read_csv(tmp_fname, names=columns, delimiter=' ')
            for i, row in df.iterrows():
                ex, ey = point_at(row.lon, row.lat, row.azim, row.len)
                plt.plot([row.lon], [row.lat], 'o')
                plt.text(row.lon, row.lat, '{:d}'.format(row.id))
                plt.plot([row.lon, ex], [row.lat, ey], '-')
            plt.show()

        expected = os.path.join(BASE_PATH, 'data', 'traces', 'expected.txt')
        msg = 'The two files do not match'
        self.assertTrue(filecmp.cmp(tmp_fname, expected), msg)
def make_aftershock_surface(aft_d, scale_relationship=WC1994, mesh_spacing=2.):
    rupture_area = scale_relationship().get_median_area(
        aft_d['Mw'], aft_d['rake'])

    length = (rupture_area * aft_d['aspect_ratio'])**0.5
    width = length / aft_d['aspect_ratio']

    mid_upper_lon, mid_upper_lat = point_at(
        aft_d['lon'], aft_d['lat'], aft_d['strike'] - 90,
        width * np.sin(np.radians(aft_d['dip'])))
    mid_lower_lon, mid_lower_lat = point_at(
        aft_d['lon'], aft_d['lat'], aft_d['strike'] + 90,
        width * np.sin(np.radians(aft_d['dip'])))

    ul_lon, ul_lat = point_at(mid_upper_lon, mid_upper_lat,
                              aft_d['strike'] - 180, length / 2)
    ur_lon, ur_lat = point_at(mid_upper_lon, mid_upper_lat, aft_d['strike'],
                              length / 2)
    ll_lon, ll_lat = point_at(mid_upper_lon, mid_upper_lat,
                              aft_d['strike'] - 180, length / 2)
    lr_lon, lr_lat = point_at(mid_upper_lon, mid_upper_lat, aft_d['strike'],
                              length / 2)

    upper_surface_depth = (aft_d['depth'] -
                           width * np.cos(np.radians(aft_d['dip'])))

    if upper_surface_depth < 0:
        upper_surface_depth = 0.

    lower_surface_depth = (aft_d['depth'] +
                           width * np.cos(np.radians(aft_d['dip'])))

    ul_corner = Point(ul_lon, ul_lat, upper_surface_depth)
    ll_corner = Point(ll_lon, ll_lat, lower_surface_depth)
    ur_corner = Point(ur_lon, ur_lat, upper_surface_depth)
    lr_corner = Point(lr_lon, lr_lat, lower_surface_depth)

    return PlanarSurface.from_corner_points(mesh_spacing, ul_corner, ur_corner,
                                            lr_corner, ll_corner)
Example #20
0
    def createGeoJSON(self):
        """
        Create the GeoJSON for the segment grid cells and earthquake point.

        Returns:
            dictionary: GeoJSON formatted dictionary.
        """
        segment_cells = []

        slips = np.asarray([])
        for segment in self.segments:
            slips = np.append(slips, segment['slip'].flatten())
        max_slip = np.ceil(np.max(slips))
        COLORS.vmax = max_slip

        for num in range(self.getNumSegments()):
            # Get segment
            segment = self.getSegment(num)
            arr_size = len(segment['lat'].flatten())
            dx = [self.event['dx'] / 2] * arr_size
            dy = [self.event['dz'] / 2] * arr_size
            length = [self.event['dx']] * arr_size
            width = [self.event['dz']] * arr_size
            strike = [segment['strike']] * arr_size
            dip = [segment['dip']] * arr_size
            optional_properties = copy.deepcopy(segment)
            for key in [
                    'dip', 'strike', 'lon', 'depth', 'slip', 'lat', 'length',
                    'width'
            ]:
                del optional_properties[key]
            for key in optional_properties:
                optional_properties[key] = optional_properties[key].flatten()

            px = segment['lon'].flatten()
            py = segment['lat'].flatten()
            pz = segment['depth'].flatten()
            slips = segment['slip'].flatten()

            # Verify that all are numpy arrays
            px = np.array(px, dtype='d')
            py = np.array(py, dtype='d')
            # depth should be in meters not in km
            pz = np.array(pz, dtype='d') * 1000
            dx = np.array(dx, dtype='d')
            dy = np.array(dy, dtype='d')
            length = np.array(length, dtype='d')
            width = np.array(width, dtype='d')
            strike = np.array(strike, dtype='d')
            dip = np.array(dip, dtype='d')

            # Get P1 and P2 (top horizontal points)
            theta = np.rad2deg(np.arctan((dy * np.cos(np.deg2rad(dip))) / dx))
            P1_direction = strike + 180 + theta
            P1_distance = np.sqrt(dx**2 + (dy * np.cos(np.deg2rad(dip)))**2)
            P2_direction = strike
            P2_distance = length
            P1_lon = np.asarray([])
            P1_lat = np.asarray([])
            P2_lon = np.asarray([])
            P2_lat = np.asarray([])
            for idx, value in enumerate(px):
                P1_points = point_at(px[idx], py[idx], P1_direction[idx],
                                     P1_distance[idx])
                P1_lon = np.append(P1_lon, P1_points[0])
                P1_lat = np.append(P1_lat, P1_points[1])
                P2_points = point_at(P1_points[0], P1_points[1],
                                     P2_direction[idx], P2_distance[idx])
                P2_lon = np.append(P2_lon, P2_points[0])
                P2_lat = np.append(P2_lat, P2_points[1])

            # Get top depth
            top_horizontal_depth = pz - 1000 * np.abs(
                dy * np.sin(np.deg2rad(dip)))

            group_index = np.array(range(len(P1_lon)))

            # Convert dip to radians
            dip = np.radians(dip)

            # Get a projection object
            west = np.min((P1_lon.min(), P2_lon.min()))
            east = np.max((P1_lon.max(), P2_lon.max()))
            south = np.min((P1_lat.min(), P2_lat.min()))
            north = np.max((P1_lat.max(), P2_lat.max()))

            # Projected coordinates are in km
            proj = OrthographicProjection(west, east, north, south)
            xp2 = np.zeros_like(P1_lon)
            xp3 = np.zeros_like(P1_lon)
            yp2 = np.zeros_like(P1_lon)
            yp3 = np.zeros_like(P1_lon)
            zpdown = np.zeros_like(top_horizontal_depth)
            for i, p1lon in enumerate(P1_lon):
                # Project the top edge coordinates
                p0x, p0y = proj(p1lon, P1_lat[i])
                p1x, p1y = proj(P2_lon[i], P2_lat[i])

                # Get the rotation angle defined by these two points
                if strike is None:
                    dx = p1x - p0x
                    dy = p1y - p0y
                    theta = np.arctan2(dx, dy)  # theta is angle from north
                elif len(strike) == 1:
                    theta = np.radians(strike[0])
                else:
                    theta = np.radians(strike[i])

                R = np.array([[np.cos(theta), -np.sin(theta)],
                              [np.sin(theta), np.cos(theta)]])

                # Rotate the top edge points into a new coordinate system (vertical
                # line)
                p0 = np.array([p0x, p0y])
                p1 = np.array([p1x, p1y])
                p0p = np.dot(R, p0)
                p1p = np.dot(R, p1)

                # Get right side coordinates in project, rotated system
                dz = np.sin(dip[i]) * width[i] * 1000
                dx = np.cos(dip[i]) * width[i]
                p3xp = p0p[0] + dx
                p3yp = p0p[1]
                p2xp = p1p[0] + dx
                p2yp = p1p[1]

                # Get right side coordinates in un-rotated projected system
                p3p = np.array([p3xp, p3yp])
                p2p = np.array([p2xp, p2yp])
                Rback = np.array([[np.cos(-theta), -np.sin(-theta)],
                                  [np.sin(-theta),
                                   np.cos(-theta)]])
                p3 = np.dot(Rback, p3p)
                p2 = np.dot(Rback, p2p)
                p3x = np.array([p3[0]])
                p3y = np.array([p3[1]])
                p2x = np.array([p2[0]])
                p2y = np.array([p2[1]])

                # project lower edge points back to lat/lon coordinates
                lon3, lat3 = proj(p3x, p3y, reverse=True)
                lon2, lat2 = proj(p2x, p2y, reverse=True)

                xp2[i] = lon2
                xp3[i] = lon3
                yp2[i] = lat2
                yp3[i] = lat3
                zpdown[i] = top_horizontal_depth[i] + dz

            # ---------------------------------------------------------------------
            # Create GeoJSON object
            # ---------------------------------------------------------------------

            u_groups = np.unique(group_index)
            n_groups = len(u_groups)
            polygons = []

            for i in range(n_groups):
                ind = np.where(u_groups[i] == group_index)[0]
                lons = np.concatenate([
                    P1_lon[ind[0]].reshape((1, )), P2_lon[ind], xp2[ind][::-1],
                    xp3[ind][::-1][-1].reshape((1, )), P1_lon[ind[0]].reshape(
                        (1, ))
                ])
                lats = np.concatenate([
                    P1_lat[ind[0]].reshape((1, )), P2_lat[ind], yp2[ind][::-1],
                    yp3[ind][::-1][-1].reshape((1, )), P1_lat[ind[0]].reshape(
                        (1, ))
                ])
                deps = np.concatenate([
                    top_horizontal_depth[ind[0]].reshape(
                        (1, )), top_horizontal_depth[ind], zpdown[ind][::-1],
                    zpdown[ind][::-1][-1].reshape(
                        (1, )), top_horizontal_depth[ind[0]].reshape((1, ))
                ])

                poly = []
                for lon, lat, dep in zip(lons, lats, deps):
                    lon = np.around(lon, decimals=4)
                    lat = np.around(lat, decimals=4)
                    deps = np.around(deps, decimals=4)
                    coordinates = np.around(np.asarray([lon, lat, dep]),
                                            decimals=5)
                    poly.append(coordinates.tolist())

                properties = {}
                for property in optional_properties:
                    properties[property] = optional_properties[property][i]
                h = COLORS.getDataColor(slips[i], color_format='hex')
                properties["slip"] = slips[i]
                properties["fill"] = h
                properties["stroke-width"] = 1.5
                properties["fill-opacity"] = 1
                d = {
                    "type": "Feature",
                    "properties": properties,
                    "geometry": {
                        "type": "Polygon",
                        "coordinates": [poly]
                    }
                }
                polygons += [d]
            segment_cells += polygons
        features = {
            "type": "FeatureCollection",
            "metadata": {
                'epicenter': {
                    'location': self.event['location'],
                    'date':
                    self.event['date'].strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
                    'depth': self.event['depth'],
                    'moment': self.event['moment'],
                    'mag': self.event['mag'],
                    'lon': self.event['lon'],
                    'lat': self.event['lat']
                }
            },
            "features": segment_cells
        }
        self.corners = features
Example #21
0
    def fromOrientation(cls, px, py, pz, dx, dy, length, width, strike, dip,
                        origin):
        """
        Create a QuadRupture instance from a known point, shape, and
        orientation.

        A point is defined as a set of latitude, longitude, and depth, which
        is located in the corner between the tail of the vector pointing in
        the strike direction and the dip direction (nearest to the surface).
        The shape is defined by length, width, dx, and dy. The length is the
        measurement of the quadrilateral in the direction of strike, and
        width is the measurement of quadrilateral in the direction of dip.
        Dx is the measurement on the plane in the strike direction between
        the known point and the corner between the tail of the vector pointing
        in the strike direction and the dip direction (nearest to the surface).
        Dy is the measurement on the plane in the dip direction between
        the known point and the corner between the tail of the vector pointing
        in the strike direction and the dip direction (nearest to the surface).
        The orientation is defined by azimuth and angle from
        horizontal, strike and dip respectively. For example in plane view:
            ::
                            strike direction
                        p1*------------------->>p2
                        *        | dy           |
                 dip    |--------o              |
              direction |   dx    known point   | Width
                        V                       |
                        V                       |
                        p4----------------------p3
                                Length

        Args:
            px (array): Array or list of longitudes (floats) of the known
                point.
            py (array): Array or list of latitudes (floats) of the known point.
            pz (array): Array or list of depths (floats) of the known point.
            dx (array): Array or list of distances (floats), in the strike
                direction, between the known point and P1. dx must be less than
                length.
            dy (array): Array or list of distances (floats), in the dip
                direction, between the known point and P1. dy must be less than
                width.
            length (array): Array or list of widths (floats) of the plane in
                the strike direction.
            width (array): Array or list of widths (floats) of the plane in the
                dip direction.
            strike (array): Array or list of strike angles (floats).
            dip (array): Array or list of dip angles (floats).
            origin (Origin): Reference to a ShakeMap Origin object.
        Returns:
            QuadRupture instance.

        Raises:
            ShakeLibException: if the lengths of the points arrays are not
                all equal.
        """
        # Verify that arrays are of equal length
        if len(px) == len(py) == len(pz) == len(dx) == len(dy) == len(
                length) == len(width) == len(strike) == len(dip):
            pass
        else:
            raise ShakeLibException(
                'Number of px, py, pz, dx, dy, length, width, '
                'strike, dip points must be '
                'equal.')

        # Verify that all are numpy arrays
        px = np.array(px, dtype='d')
        py = np.array(py, dtype='d')
        pz = np.array(pz, dtype='d')
        dx = np.array(dx, dtype='d')
        dy = np.array(dy, dtype='d')
        length = np.array(length, dtype='d')
        width = np.array(width, dtype='d')
        strike = np.array(strike, dtype='d')
        dip = np.array(dip, dtype='d')

        # Get P1 and P2 (top horizontal points)
        theta = np.rad2deg(np.arctan2(dy * np.cos(np.deg2rad(dip)), dx))
        P1_direction = strike + 180 + theta
        P1_distance = np.sqrt(dx**2 + (dy * np.cos(np.deg2rad(dip)))**2)
        P2_direction = strike
        P2_distance = length
        P1_lon = []
        P1_lat = []
        P2_lon = []
        P2_lat = []
        for idx, value in enumerate(px):
            P1_points = point_at(px[idx], py[idx], P1_direction[idx],
                                 P1_distance[idx])
            P1_lon += [P1_points[0]]
            P1_lat += [P1_points[1]]
            P2_points = point_at(P1_points[0], P1_points[1], P2_direction[idx],
                                 P2_distance[idx])
            P2_lon += [P2_points[0]]
            P2_lat += [P2_points[1]]

        # Get top depth
        top_horizontal_depth = pz - np.abs(dy * np.sin(np.deg2rad(dip)))

        # Get QuadRupture object
        quad = QuadRupture.fromTrace(P1_lon,
                                     P1_lat,
                                     P2_lon,
                                     P2_lat,
                                     top_horizontal_depth,
                                     width,
                                     dip,
                                     origin,
                                     strike=strike)
        return quad
Example #22
0
 def test_zero_distance(self):
     lon, lat = geodetic.point_at(1.3, -5.6, -35.0, 0)
     self.assertAlmostEqual(lon, 1.3)
     self.assertAlmostEqual(lat, -5.6)