Ejemplo n.º 1
0
    def computeRjb(self, lon, lat, depth, var=False):
        """
        Method for computing Joyner-Boore distance.

        Args:
            lon (array): Numpy array of longitudes.
            lat (array): Numpy array of latitudes.
            depth (array): Numpy array of depths (km; positive down).
            var (bool): Also return variance of prediction. Unused, and
                will raise an exception if not False.

        Returns:
           array: Joyner-Boore distance (km).

        """

        if var is True:
            raise ValueError('var must be False for EdgeRupture')

        mesh_dx = self._mesh_dx

        # ---------------------------------------------------------------------
        # Sort out sites
        # ---------------------------------------------------------------------
        oldshape = lon.shape

        if len(oldshape) == 2:
            newshape = (oldshape[0] * oldshape[1], 1)
        else:
            newshape = (oldshape[0], 1)

        x, y, z = latlon2ecef(lat, lon, depth)
        x.shape = newshape
        y.shape = newshape
        z.shape = newshape
        sites_ecef = np.hstack((x, y, z))

        # ---------------------------------------------------------------------
        # Get mesh
        # ---------------------------------------------------------------------
        mx = []
        my = []
        mz = []
        u_groups = np.unique(self._group_index)
        n_groups = len(u_groups)
        for j in range(n_groups):
            g_ind = np.where(u_groups[j] == self._group_index)[0]
            nq = len(self._toplats[g_ind]) - 1
            for i in range(nq):
                q = [
                    Point(self._toplons[g_ind[i]], self._toplats[g_ind[i]], 0),
                    Point(self._toplons[g_ind[i + 1]],
                          self._toplats[g_ind[i + 1]], 0),
                    Point(self._botlons[g_ind[i + 1]],
                          self._botlats[g_ind[i + 1]], 0),
                    Point(self._botlons[g_ind[i]], self._botlats[g_ind[i]], 0)
                ]
                mesh = utils.get_quad_mesh(q, dx=mesh_dx)
                mx.extend(list(np.reshape(mesh['x'], (-1, ))))
                my.extend(list(np.reshape(mesh['y'], (-1, ))))
                mz.extend(list(np.reshape(mesh['z'], (-1, ))))
        mesh_mat = np.array([np.array(mx), np.array(my), np.array(mz)])

        # ---------------------------------------------------------------------
        # Compute distance
        # ---------------------------------------------------------------------
        dist = np.zeros_like(x)
        for i in range(len(x)):
            sitecol = sites_ecef[i, :].reshape([3, 1])
            dif = sitecol - mesh_mat
            distarray = np.sqrt(np.sum(dif * dif, axis=0))
            dist[i] = np.min(distarray) / 1000.0  # convert to km

        dist = np.reshape(dist, oldshape)

        return dist
Ejemplo n.º 2
0
    def __computeXiPrime(self):
        """
        Computes the xi' value.
        """
        hypo_ecef = Vector.fromPoint(
            geo.point.Point(self._hyp.longitude, self._hyp.latitude,
                            self._hyp.depth))

        slat = self._lat
        slon = self._lon

        # Convert site to ECEF:
        site_ecef_x = np.ones_like(slat)
        site_ecef_y = np.ones_like(slat)
        site_ecef_z = np.ones_like(slat)

        # Make a 3x(#number of sites) matrix of site locations
        # (rows are x, y, z) in ECEF
        site_ecef_x, site_ecef_y, site_ecef_z = latlon2ecef(
            slat, slon, np.zeros(slon.shape))
        site_mat = np.array([
            np.reshape(site_ecef_x, (-1, )),
            np.reshape(site_ecef_y, (-1, )),
            np.reshape(site_ecef_z, (-1, ))
        ])

        xi_prime_unscaled = np.zeros_like(slat)

        # Normalize by total number of subruptures. For mtype == 1, the number
        # of subruptures will vary with site and be different for xi_s and
        # xi_p, so keep two variables and sum them for each quad.
        nsubs = np.zeros(np.product(slat.shape))
        nsubp = np.zeros(np.product(slat.shape))

        xi_prime_s = np.zeros(np.product(slat.shape))
        xi_prime_p = np.zeros(np.product(slat.shape))

        for k in range(len(self._rup.getQuadrilaterals())):
            # Select a quad
            q = self._rup.getQuadrilaterals()[k]

            # Quad mesh (ECEF coords)
            mesh = utils.get_quad_mesh(q, self._dx)

            # Rupture plane normal vector (ECEF coords)
            rpnv = utils.get_quad_normal(q)
            rpnvcol = np.array([[rpnv.x], [rpnv.y], [rpnv.z]])

            cp_mat = np.array([
                np.reshape(mesh['cpx'], (-1, )),
                np.reshape(mesh['cpy'], (-1, )),
                np.reshape(mesh['cpz'], (-1, ))
            ])

            # Compute matrix of p vectors
            hypcol = np.array([[hypo_ecef.x], [hypo_ecef.y], [hypo_ecef.z]])
            pmat = cp_mat - hypcol

            # Project pmat onto quad
            ndotp = np.sum(pmat * rpnvcol, axis=0)
            pmat = pmat - ndotp * rpnvcol

            mag = np.sqrt(np.sum(pmat * pmat, axis=0))
            pmatnorm = pmat / mag  # like r1

            # According to Rowshandel:
            #   "The choice of the +/- sign in the above equations
            #    depends on the (along-the-strike and across-the-dip)
            #    location of the rupturing sub-fault relative to the
            #    location of the hypocenter."
            # and:
            #   "for the along the strike component of the slip unit
            #    vector, the choice of the sign should result in the
            #    slip unit vector (s) being exactly the same as  the
            #    rupture unit vector (p) for a pure strike-slip case"

            # Strike slip and dip slip components of unit slip vector
            # (ECEF coords)
            ds_mat, ss_mat = _get_quad_slip_ds_ss(q, self._rake, cp_mat,
                                                  pmatnorm)

            slpmat = (ds_mat + ss_mat)
            mag = np.sqrt(np.sum(slpmat * slpmat, axis=0))
            slpmatnorm = slpmat / mag

            # Loop over sites
            for i in range(site_mat.shape[1]):
                sitecol = np.array([[site_mat[0, i]], [site_mat[1, i]],
                                    [site_mat[2, i]]])

                qmat = sitecol - cp_mat  # 3x(ni*nj), like r2
                mag = np.sqrt(np.sum(qmat * qmat, axis=0))
                qmatnorm = qmat / mag

                # Propagation dot product
                pdotqraw = np.sum(pmatnorm * qmatnorm, axis=0)

                # Slip vector dot product
                sdotqraw = np.sum(slpmatnorm * qmatnorm, axis=0)

                if self._mtype == 1:
                    # Only sum over (+) directivity effect subruptures

                    # xi_p_prime
                    pdotq = pdotqraw.clip(min=0)
                    nsubp[i] = nsubp[i] + np.sum(pdotq > 0)

                    # xi_s_prime
                    sdotq = sdotqraw.clip(min=0)
                    nsubs[i] = nsubs[i] + np.sum(sdotq > 0)

                elif self._mtype == 2:
                    # Sum over contributing subruptures

                    # xi_p_prime
                    pdotq = pdotqraw
                    nsubp[i] = nsubp[i] + cp_mat.shape[1]

                    # xi_s_prime
                    sdotq = sdotqraw
                    nsubs[i] = nsubs[i] + cp_mat.shape[1]

                # Normalize by n sub ruptures later
                xi_prime_s[i] = xi_prime_s[i] + np.sum(sdotq)
                xi_prime_p[i] = xi_prime_p[i] + np.sum(pdotq)

        # Apply a water level to nsubp and nsubs to avoid division by
        # zero. This should only occur when the numerator is also zero
        # and so the resulting value should be zero.
        nsubs = np.maximum(nsubs, 1)
        nsubp = np.maximum(nsubp, 1)

        # We are outside the 'k' loop over nquads.
        # o Normalize xi_prime_s and xi_prime_p
        # o Reshape them
        # o Add them together with the 'a' weights
        xi_prime_tmp = (self._a_weight) * (xi_prime_s / nsubs) + \
                       (1 - self._a_weight) * (xi_prime_p / nsubp)
        xi_prime_unscaled = xi_prime_unscaled + \
            np.reshape(xi_prime_tmp, slat.shape)

        # Scale so that xi_prime has range (0, 1)
        if self._mtype == 1:
            xi_prime = xi_prime_unscaled
        elif self._mtype == 2:
            xi_prime = 0.5 * (xi_prime_unscaled + 1)

        self._xi_prime = xi_prime
Ejemplo n.º 3
0
    def computeRrup(self, lon, lat, depth):
        """
        Method for computing rupture distance.

        Args:
            lon (array): Numpy array of longitudes.
            lat (array): Numpy array of latitudes.
            depth (array): Numpy array of depths (km; positive down).

        Returns:
           tuple: A tuple of an array of rupture distance (km), and None.

        """

        mesh_dx = self._mesh_dx

        # ---------------------------------------------------------------------
        # Sort out sites
        # ---------------------------------------------------------------------
        oldshape = lon.shape

        if len(oldshape) == 2:
            newshape = (oldshape[0] * oldshape[1], 1)
        else:
            newshape = (oldshape[0], 1)

        x, y, z = latlon2ecef(lat, lon, depth)
        x.shape = newshape
        y.shape = newshape
        z.shape = newshape
        sites_ecef = np.hstack((x, y, z))

        # ---------------------------------------------------------------------
        # Get mesh
        # ---------------------------------------------------------------------
        mx = []
        my = []
        mz = []
        u_groups = np.unique(self._group_index)
        n_groups = len(u_groups)
        for j in range(n_groups):
            g_ind = np.where(u_groups[j] == self._group_index)[0]
            nq = len(self._toplats[g_ind]) - 1
            for i in range(nq):
                q = [
                    Point(self._toplons[g_ind[i]], self._toplats[g_ind[i]],
                          self._topdeps[g_ind[i]]),
                    Point(self._toplons[g_ind[i + 1]],
                          self._toplats[g_ind[i + 1]],
                          self._topdeps[g_ind[i + 1]]),
                    Point(self._botlons[g_ind[i + 1]],
                          self._botlats[g_ind[i + 1]],
                          self._botdeps[g_ind[i + 1]]),
                    Point(self._botlons[g_ind[i]], self._botlats[g_ind[i]],
                          self._botdeps[g_ind[i]])
                ]
                mesh = utils.get_quad_mesh(q, dx=mesh_dx)
                mx.extend(list(np.reshape(mesh['x'], (-1, ))))
                my.extend(list(np.reshape(mesh['y'], (-1, ))))
                mz.extend(list(np.reshape(mesh['z'], (-1, ))))
        mesh_mat = np.array([np.array(mx), np.array(my), np.array(mz)])

        # ---------------------------------------------------------------------
        # Compute distance
        # ---------------------------------------------------------------------
        dist = np.zeros_like(x)
        for i in range(len(x)):
            sitecol = sites_ecef[i, :].reshape([3, 1])
            dif = sitecol - mesh_mat
            distarray = np.sqrt(np.sum(dif * dif, axis=0))
            dist[i] = np.min(distarray) / 1000.0  # convert to km

        dist = np.reshape(dist, oldshape)

        return dist, None
Ejemplo n.º 4
0
    def computeRjb(self, lon, lat, depth):
        """
        Method for computing Joyner-Boore distance.

        Args:
            lon (array): Numpy array of longitudes.
            lat (array): Numpy array of latitudes.
            depth (array): Numpy array of depths (km; positive down).

        Returns:
           array: Joyner-Boore distance (km).

        """

        mesh_dx = self._mesh_dx

        # ---------------------------------------------------------------------
        # Sort out sites
        # ---------------------------------------------------------------------
        oldshape = lon.shape

        if len(oldshape) == 2:
            newshape = (oldshape[0] * oldshape[1], 1)
        else:
            newshape = (oldshape[0], 1)

        x, y, z = latlon2ecef(lat, lon, depth)
        x.shape = newshape
        y.shape = newshape
        z.shape = newshape
        sites_ecef = np.hstack((x, y, z))

        # ---------------------------------------------------------------------
        # Get mesh
        # ---------------------------------------------------------------------
        mx = []
        my = []
        mz = []
        u_groups = np.unique(self._group_index)
        n_groups = len(u_groups)
        for j in range(n_groups):
            g_ind = np.where(u_groups[j] == self._group_index)[0]
            nq = len(self._toplats[g_ind]) - 1
            for i in range(nq):
                q = [Point(self._toplons[g_ind[i]],
                           self._toplats[g_ind[i]],
                           0),
                     Point(self._toplons[g_ind[i + 1]],
                           self._toplats[g_ind[i + 1]],
                           0),
                     Point(self._botlons[g_ind[i + 1]],
                           self._botlats[g_ind[i + 1]],
                           0),
                     Point(self._botlons[g_ind[i]],
                           self._botlats[g_ind[i]],
                           0)
                     ]
                mesh = utils.get_quad_mesh(q, dx=mesh_dx)
                mx.extend(list(np.reshape(mesh['x'], (-1,))))
                my.extend(list(np.reshape(mesh['y'], (-1,))))
                mz.extend(list(np.reshape(mesh['z'], (-1,))))
        mesh_mat = np.array([np.array(mx), np.array(my), np.array(mz)])

        # ---------------------------------------------------------------------
        # Compute distance
        # ---------------------------------------------------------------------
        dist = np.zeros_like(x)
        for i in range(len(x)):
            sitecol = sites_ecef[i, :].reshape([3, 1])
            dif = sitecol - mesh_mat
            distarray = np.sqrt(np.sum(dif * dif, axis=0))
            dist[i] = np.min(distarray) / 1000.0  # convert to km

        dist = np.reshape(dist, oldshape)

        return dist
Ejemplo n.º 5
0
    def __computeXiPrime(self):
        """
        Computes the xi' value.
        """
        hypo_ecef = Vector.fromPoint(geo.point.Point(
            self._hyp.longitude, self._hyp.latitude, self._hyp.depth))

        slat = self._lat
        slon = self._lon

        # Convert site to ECEF:
        site_ecef_x = np.ones_like(slat)
        site_ecef_y = np.ones_like(slat)
        site_ecef_z = np.ones_like(slat)

        # Make a 3x(#number of sites) matrix of site locations
        # (rows are x, y, z) in ECEF
        site_ecef_x, site_ecef_y, site_ecef_z = latlon2ecef(
            slat, slon, np.zeros(slon.shape))
        site_mat = np.array([np.reshape(site_ecef_x, (-1,)),
                             np.reshape(site_ecef_y, (-1,)),
                             np.reshape(site_ecef_z, (-1,))])

        xi_prime_unscaled = np.zeros_like(slat)

        # Normalize by total number of subruptures. For mtype == 1, the number
        # of subruptures will vary with site and be different for xi_s and
        # xi_p, so keep two variables and sum them for each quad.
        nsubs = np.zeros(np.product(slat.shape))
        nsubp = np.zeros(np.product(slat.shape))

        xi_prime_s = np.zeros(np.product(slat.shape))
        xi_prime_p = np.zeros(np.product(slat.shape))

        for k in range(len(self._rup.getQuadrilaterals())):
            # Select a quad
            q = self._rup.getQuadrilaterals()[k]

            # Quad mesh (ECEF coords)
            mesh = utils.get_quad_mesh(q, self._dx)

            # Rupture plane normal vector (ECEF coords)
            rpnv = utils.get_quad_normal(q)
            rpnvcol = np.array([[rpnv.x],
                                [rpnv.y],
                                [rpnv.z]])

            cp_mat = np.array([np.reshape(mesh['cpx'], (-1,)),
                               np.reshape(mesh['cpy'], (-1,)),
                               np.reshape(mesh['cpz'], (-1,))])

            # Compute matrix of p vectors
            hypcol = np.array([[hypo_ecef.x],
                               [hypo_ecef.y],
                               [hypo_ecef.z]])
            pmat = cp_mat - hypcol

            # Project pmat onto quad
            ndotp = np.sum(pmat * rpnvcol, axis=0)
            pmat = pmat - ndotp * rpnvcol

            mag = np.sqrt(np.sum(pmat * pmat, axis=0))
            pmatnorm = pmat / mag  # like r1

            # According to Rowshandel:
            #   "The choice of the +/- sign in the above equations
            #    depends on the (along-the-strike and across-the-dip)
            #    location of the rupturing sub-fault relative to the
            #    location of the hypocenter."
            # and:
            #   "for the along the strike component of the slip unit
            #    vector, the choice of the sign should result in the
            #    slip unit vector (s) being exactly the same as  the
            #    rupture unit vector (p) for a pure strike-slip case"

            # Strike slip and dip slip components of unit slip vector
            # (ECEF coords)
            ds_mat, ss_mat = _get_quad_slip_ds_ss(
                q, self._rake, cp_mat, pmatnorm)

            slpmat = (ds_mat + ss_mat)
            mag = np.sqrt(np.sum(slpmat * slpmat, axis=0))
            slpmatnorm = slpmat / mag

            # Loop over sites
            for i in range(site_mat.shape[1]):
                sitecol = np.array([[site_mat[0, i]],
                                    [site_mat[1, i]],
                                    [site_mat[2, i]]])

                qmat = sitecol - cp_mat  # 3x(ni*nj), like r2
                mag = np.sqrt(np.sum(qmat * qmat, axis=0))
                qmatnorm = qmat / mag

                # Propagation dot product
                pdotqraw = np.sum(pmatnorm * qmatnorm, axis=0)

                # Slip vector dot product
                sdotqraw = np.sum(slpmatnorm * qmatnorm, axis=0)

                if self._mtype == 1:
                    # Only sum over (+) directivity effect subruptures

                    # xi_p_prime
                    pdotq = pdotqraw.clip(min=0)
                    nsubp[i] = nsubp[i] + np.sum(pdotq > 0)

                    # xi_s_prime
                    sdotq = sdotqraw.clip(min=0)
                    nsubs[i] = nsubs[i] + np.sum(sdotq > 0)

                elif self._mtype == 2:
                    # Sum over contributing subruptures

                    # xi_p_prime
                    pdotq = pdotqraw
                    nsubp[i] = nsubp[i] + cp_mat.shape[1]

                    # xi_s_prime
                    sdotq = sdotqraw
                    nsubs[i] = nsubs[i] + cp_mat.shape[1]

                # Normalize by n sub ruptures later
                xi_prime_s[i] = xi_prime_s[i] + np.sum(sdotq)
                xi_prime_p[i] = xi_prime_p[i] + np.sum(pdotq)

        # Apply a water level to nsubp and nsubs to avoid division by
        # zero. This should only occur when the numerator is also zero
        # and so the resulting value should be zero.
        nsubs = np.maximum(nsubs, 1)
        nsubp = np.maximum(nsubp, 1)

        # We are outside the 'k' loop over nquads.
        # o Normalize xi_prime_s and xi_prime_p
        # o Reshape them
        # o Add them together with the 'a' weights
        xi_prime_tmp = (self._a_weight) * (xi_prime_s / nsubs) + \
                       (1 - self._a_weight) * (xi_prime_p / nsubp)
        xi_prime_unscaled = xi_prime_unscaled + \
            np.reshape(xi_prime_tmp, slat.shape)

        # Scale so that xi_prime has range (0, 1)
        if self._mtype == 1:
            xi_prime = xi_prime_unscaled
        elif self._mtype == 2:
            xi_prime = 0.5 * (xi_prime_unscaled + 1)

        self._xi_prime = xi_prime