def getDip(self): """ Return average dip of all quadrilaterals in the rupture. Returns: float: Average dip in degrees. """ dipsum = 0.0 for quad in self._quadrilaterals: N = utils.get_quad_normal(quad) V = utils.get_vertical_vector(quad) dipsum = dipsum + np.degrees(np.arccos(Vector.dot(N, V))) dip = dipsum / len(self._quadrilaterals) return dip
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
def getDepthAtPoint(self, lat, lon): SMALL_DISTANCE = 2e-03 # 2 meters depth = np.nan tmp, _ = self.computeRjb(np.array([lon]), np.array([lat]), np.array([0])) if tmp > SMALL_DISTANCE: return depth i = 0 imin = -1 dmin = 9999999999999999 for quad in self.getQuadrilaterals(): pX = Vector.fromPoint(Point(lon, lat, 0)) points = np.reshape(np.array([pX.x, pX.y, pX.z]), (1, 3)) rjb = utils._quad_distance(quad, points, horizontal=True) if rjb[0][0] < dmin: dmin = rjb[0][0] imin = i i += 1 quad = self._quadrilaterals[imin] P0, P1, P2, P3 = quad # project the quad and the point in question to orthographic defined by # quad xmin = np.min([P0.x, P1.x, P2.x, P3.x]) xmax = np.max([P0.x, P1.x, P2.x, P3.x]) ymin = np.min([P0.y, P1.y, P2.y, P3.y]) ymax = np.max([P0.y, P1.y, P2.y, P3.y]) proj = OrthographicProjection(xmin, xmax, ymax, ymin) # project each vertex of quad (at 0 depth) s0x, s0y = proj(P0.x, P0.y) s1x, s1y = proj(P1.x, P1.y) s2x, s2y = proj(P2.x, P2.y) s3x, s3y = proj(P3.x, P3.y) sxx, sxy = proj(lon, lat) # turn these to vectors s0 = Vector(s0x, s0y, 0) s1 = Vector(s1x, s1y, 0) s3 = Vector(s3x, s3y, 0) sx = Vector(sxx, sxy, 0) # Compute vector from s0 to s1 s0s1 = s1 - s0 # Compute the vector from s0 to s3 s0s3 = s3 - s0 # Compute the vector from s0 to sx s0sx = sx - s0 # cross products s0normal = s0s3.cross(s0s1) dd = s0s1.cross(s0normal) # normalize dd (down dip direction) ddn = dd.norm() # dot product sxdd = ddn.dot(s0sx) # get width of quad (convert from km to m) w = utils.get_quad_width(quad) * 1000 # Get weights for top and bottom edge depths N = utils.get_quad_normal(quad) V = utils.get_vertical_vector(quad) dip = np.degrees(np.arccos(Vector.dot(N, V))) ws = (w * np.cos(np.radians(dip))) wtt = (ws - sxdd) / ws wtb = sxdd / ws # Compute the depth of of the plane at Px: depth = wtt * P0.z + wtb * P3.z * 1000 return depth
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