def get_quad_slip(q, rake): """ Compute the unit slip vector in ECEF space for a quad and rake angle. Args: q (list): A quadrilateral; list of four points. rake (float): Direction of motion of the hanging wall relative to the foot wall, as measured by the angle (deg) from the strike vector. Returns: Vector: Unit slip vector in ECEF space. """ P0, P1, P2 = q[0:3] strike = P0.azimuth(P1) dip = get_quad_dip(q) s1_local = get_local_unit_slip_vector(strike, dip, rake) s0_local = Vector(0, 0, 0) qlats = [a.latitude for a in q] qlons = [a.longitude for a in q] proj = OrthographicProjection( np.min(qlons), np.max(qlons), np.min(qlats), np.max(qlats)) s1_ll = proj(np.array([s1_local.x]), np.array([s1_local.y]), reverse=True) s0_ll = proj(np.array([s0_local.x]), np.array([s0_local.y]), reverse=True) s1_ecef = Vector.fromTuple(latlon2ecef(s1_ll[1], s1_ll[0], s1_local.z)) s0_ecef = Vector.fromTuple(latlon2ecef(s0_ll[1], s0_ll[0], s0_local.z)) slp_ecef = (s1_ecef - s0_ecef).norm() return slp_ecef
def test_ss3_m4p5(): magnitude = 4.5 dip = np.array([90]) rake = 180.0 width = np.array([15]) rupx = np.array([0, 0]) rupy = np.array([0, 80]) zp = np.array([0]) epix = np.array([0]) epiy = np.array([0.2 * rupy[1]]) # Convert to lat/lon proj = OrthographicProjection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) epilon, epilat = proj(epix, epiy, reverse=True) # Origin origin = Origin({'lat': epilat[0], 'lon': epilon[0], 'depth': 10, 'mag': magnitude, 'id': 'ss3', 'netid': '', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) rup = QuadRupture.fromTrace( np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='ss3') x = np.linspace(0, 20, 6) y = np.linspace(0, 90, 11) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) deps = np.zeros_like(slon) test1 = Bayless2013(origin, rup, slat, slon, deps, T=1.0) # Test fd fd = test1.getFd() fd_test = np.array( [[0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 0.]]) np.testing.assert_allclose( fd, fd_test, rtol=1e-4)
def check_intersections(cs, css): """ Fixes the cross section trace 'cs' given a set of pre-existing cross section traces in 'css'. :param cs: A cross section trace i.e. an instance of :class:`openquake.sub.cross_section.CrossSection` :param css: A list of pre-existing cross sections """ # Get min and max mm = cs.get_mm() lngs = [] for icc, cc in enumerate(css): cmm = cc.get_mm() intersect = check_bboxes_overlap(mm, cmm) if intersect: prj = OrthographicProjection(min(mm[0], cmm[0]), max(mm[1], cmm[1]), min(mm[2], cmm[2]), min(mm[3], cmm[3])) ox, oy = prj(cs.plo, cs.pla) cx, cy = prj(cc.plo, cc.pla) for i in range(len(ox)-1): pa = numpy.array([ox[i], oy[i]]) pb = numpy.array([ox[i+1], oy[i+1]]) for j in range(len(cx)-1): pc = numpy.array([cx[j], cy[j]]) pd = numpy.array([cx[j+1], cy[j+1]]) chk = check_segments_intersection(pa, pb, pc, pd) if chk: # Calculate intersection point den = (pa[0]-pb[0]) a1 = (pa[1]-pb[1])/den if abs(den) > 1e-10 else 1e100 den = (pc[0]-pd[0]) a2 = (pc[1]-pd[1])/den if abs(den) > 1e-10 else 1e100 b1 = pa[1] - a1*pa[0] b2 = pc[1] - a2*pc[0] den = (a1 - a2) xp = (b2 - b1) / den if abs(den) > 1e-10 else 1e100 yp = a1 * xp + b1 lng = ((ox[i]-xp)**2 + (oy[i]-yp)**2)**0.5 lngs.append(lng) if len(lngs): return numpy.min(numpy.array(lngs)) else: return None
def _computeGC2(rupture, lon, lat, depth): """ Method for computing GC2 from a ShakeMap Rupture instance. Args: rupture (Rupture): ShakeMap rupture object. lon (array): Numpy array of site longitudes. lat (array): Numpy array of site latitudes. depth (array): Numpy array of site depths. Returns: dict: Dictionary of GC2 distances. Keys include "T", "U", "rx" "ry", "ry0". """ quadlist = rupture.getQuadrilaterals() quadgc2 = copy.deepcopy(quadlist) oldshape = lon.shape if len(oldshape) == 2: newshape = (oldshape[0] * oldshape[1], 1) else: newshape = (oldshape[0], 1) # ------------------------------------------------------------------------- # Define a projection that spans sites and rupture # ------------------------------------------------------------------------- all_lat = np.append(lat, rupture.lats) all_lon = np.append(lon, rupture.lons) west = np.nanmin(all_lon) east = np.nanmax(all_lon) south = np.nanmin(all_lat) north = np.nanmax(all_lat) proj = OrthographicProjection(west, east, north, south) totweight = np.zeros(newshape, dtype=lon.dtype) GC2T = np.zeros(newshape, dtype=lon.dtype) GC2U = np.zeros(newshape, dtype=lon.dtype) # ------------------------------------------------------------------------- # First sort out strike discordance and nominal strike prior to # starting the loop if there is more than one group/trace. # ------------------------------------------------------------------------- group_ind = rupture._getGroupIndex() # Need group_ind as numpy array for sensible indexing... group_ind_np = np.array(group_ind) uind = np.unique(group_ind_np) n_groups = len(uind) if n_groups > 1: # --------------------------------------------------------------------- # The first thing we need to worry about is finding the coordinate # shift. U's origin is "selected from the two endpoints most # distant from each other." # --------------------------------------------------------------------- # Need to get index of first and last quad # for each segment iq0 = np.zeros(n_groups, dtype='int16') iq1 = np.zeros(n_groups, dtype='int16') for k in uind: ii = [i for i, j in enumerate(group_ind) if j == uind[k]] iq0[k] = int(np.min(ii)) iq1[k] = int(np.max(ii)) # --------------------------------------------------------------------- # This is an iterator for each possible combination of traces # including trace orientations (i.e., flipped). # --------------------------------------------------------------------- it_seg = it.product(it.combinations(uind, 2), it.product([0, 1], [0, 1])) # Placeholder for the trace pair/orientation that gives the # largest distance. dist_save = 0 for k in it_seg: s0ind = k[0][0] s1ind = k[0][1] p0ind = k[1][0] p1ind = k[1][1] if p0ind == 0: P0 = quadlist[iq0[s0ind]][0] else: P0 = quadlist[iq1[s0ind]][1] if p1ind == 0: P1 = quadlist[iq1[s1ind]][0] else: P1 = quadlist[iq0[s1ind]][1] dist = geodetic.distance(P0.longitude, P0.latitude, 0.0, P1.longitude, P1.latitude, 0.0) if dist > dist_save: dist_save = dist A0 = P0 A1 = P1 # --------------------------------------------------------------------- # A0 and A1 are the furthest two segment endpoints, but we still # need to sort out which one is the "origin". # --------------------------------------------------------------------- # This goofy while-loop is to adjust the side of the rupture where the # origin is located dummy = -1 while dummy < 0: A0.depth = 0 A1.depth = 0 p_origin = Vector.fromPoint(A0) a0 = Vector.fromPoint(A0) a1 = Vector.fromPoint(A1) ahat = (a1 - a0).norm() # Loop over traces e_j = np.zeros(n_groups) b_prime = [None] * n_groups for j in range(n_groups): P0 = quadlist[iq0[j]][0] P1 = quadlist[iq1[j]][1] P0.depth = 0 P1.depth = 0 p0 = Vector.fromPoint(P0) p1 = Vector.fromPoint(P1) b_prime[j] = p1 - p0 e_j[j] = ahat.dot(b_prime[j]) E = np.sum(e_j) # List of discordancy dc = [np.sign(a) * np.sign(E) for a in e_j] b = Vector(0, 0, 0) for j in range(n_groups): b.x = b.x + b_prime[j].x * dc[j] b.y = b.y + b_prime[j].y * dc[j] b.z = b.z + b_prime[j].z * dc[j] bhat = b.norm() dummy = bhat.dot(ahat) if dummy < 0: tmpA0 = copy.deepcopy(A0) A0 = copy.deepcopy(A1) A1 = tmpA0 # --------------------------------------------------------------------- # To fix discordancy, need to flip quads and rearrange # the order of quadgc2 # --------------------------------------------------------------------- # 1) flip quads for i in range(len(quadgc2)): if dc[group_ind[i]] < 0: quadgc2[i] = reverse_quad(quadgc2[i]) # 2) rearrange quadlist order qind = np.arange(len(quadgc2)) for i in range(n_groups): qsel = qind[group_ind_np == uind[i]] if dc[i] < 0: qrev = qsel[::-1] qind[group_ind_np == uind[i]] = qrev quadgc2old = copy.deepcopy(quadgc2) for i in range(len(qind)): quadgc2[i] = quadgc2old[qind[i]] # End of if-statement for adjusting group discordancy s_i = 0.0 l_i = np.zeros(len(quadgc2)) for i in range(len(quadgc2)): G0, G1, G2, G3 = quadgc2[i] # Compute u_i and t_i for this quad t_i = __calc_t_i(G0, G1, lat, lon, proj) u_i = __calc_u_i(G0, G1, lat, lon, proj) # Quad length (top edge) l_i[i] = get_quad_length(quadgc2[i]) # --------------------------------------------------------------------- # Weight of segment, three cases # --------------------------------------------------------------------- # Case 3: t_i == 0 and 0 <= u_i <= l_i w_i = np.zeros_like(t_i) # To avoid division by zero in totweight later on: ix = (t_i == 0) & (0 <= u_i) & (u_i <= l_i[i]) totweight[ix] = 1.0 # Case 1: ix = t_i != 0 w_i[ix] = (1.0 / t_i[ix]) * (np.arctan( (l_i[i] - u_i[ix]) / t_i[ix]) - np.arctan(-u_i[ix] / t_i[ix])) # Case 2: ix = (t_i == 0) & ((u_i < 0) | (u_i > l_i[i])) w_i[ix] = 1 / (u_i[ix] - l_i[i]) - 1 / u_i[ix] totweight = totweight + w_i GC2T = GC2T + w_i * t_i if n_groups == 1: GC2U = GC2U + w_i * (u_i + s_i) else: if i == 0: qind = np.array(range(len(quadgc2))) l_kj = 0 s_ij_1 = 0 else: l_kj = l_i[(group_ind_np == group_ind_np[i]) & (qind < i)] s_ij_1 = np.sum(l_kj) # First endpoint in the current 'group' (or 'trace' in GC2 terms) p1 = Vector.fromPoint(quadgc2[iq0[group_ind[i]]][0]) s_ij_2 = (p1 - p_origin).dot(np.sign(E) * ahat) / 1000.0 # Above is GC2N, for GC2T use: # s_ij_2 = (p1 - p_origin).dot(bhat) / 1000.0 s_ij = s_ij_1 + s_ij_2 GC2U = GC2U + w_i * (u_i + s_ij) s_i = s_i + l_i[i] GC2T = GC2T / totweight GC2U = GC2U / totweight # Dictionary for holding the distances distdict = dict() distdict['T'] = copy.deepcopy(GC2T).reshape(oldshape) distdict['U'] = copy.deepcopy(GC2U).reshape(oldshape) # Take care of Rx Rx = copy.deepcopy(GC2T) # preserve sign (no absolute value) Rx = Rx.reshape(oldshape) distdict['rx'] = Rx # Ry Ry = GC2U - s_i / 2.0 Ry = Ry.reshape(oldshape) distdict['ry'] = Ry # Ry0 Ry0 = np.zeros_like(GC2U) ix = GC2U < 0 Ry0[ix] = np.abs(GC2U[ix]) if n_groups > 1: s_i = s_ij + l_i[-1] ix = GC2U > s_i Ry0[ix] = GC2U[ix] - s_i Ry0 = Ry0.reshape(oldshape) distdict['ry0'] = Ry0 return distdict
def test_so6(): magnitude = 7.2 dip = np.array([70]) rake = 135 width = np.array([15]) L = 80 rupx = np.array([0, 0]) rupy = np.array([0, L]) zp = np.array([0]) # Convert to lat/lon proj = OrthographicProjection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) # Dummy origin origin = Origin({'lat': 0, 'lon': 0, 'depth': 0, 'mag': 0, 'id': 'so6', 'netid': 'us', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) # Rupture rup = QuadRupture.fromTrace( np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='rv4') # Sites x = np.linspace(-80, 80, 21) y = np.linspace(-50, 130, 21) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) sdepth = np.zeros_like(slon) # Fix origin tmp = rup.getQuadrilaterals()[0] pp0 = Vector.fromPoint(point.Point( tmp[0].longitude, tmp[0].latitude, tmp[0].depth)) pp1 = Vector.fromPoint(point.Point( tmp[1].longitude, tmp[1].latitude, tmp[1].depth)) pp2 = Vector.fromPoint(point.Point( tmp[2].longitude, tmp[2].latitude, tmp[2].depth)) pp3 = Vector.fromPoint(point.Point( tmp[3].longitude, tmp[3].latitude, tmp[3].depth)) dxp = 10 / L dyp = (width - 5) / width mp0 = pp0 + (pp1 - pp0) * dxp mp1 = pp3 + (pp2 - pp3) * dxp rp = mp0 + (mp1 - mp0) * dyp epilat, epilon, epidepth = ecef2latlon(rp.x, rp.y, rp.z) epix, epiy = proj(epilon, epilat, reverse=False) origin = Origin({'lat': epilat, 'lon': epilon, 'depth': epidepth, 'mag': magnitude, 'id': 'so6', 'netid': 'us', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) ruplat = [a.latitude for a in rup.getQuadrilaterals()[0]] ruplon = [a.longitude for a in rup.getQuadrilaterals()[0]] ruplat = np.append(ruplat, ruplat[0]) ruplon = np.append(ruplon, ruplon[0]) rupx, rupy = proj(ruplon, ruplat, reverse=False) test1 = Bayless2013(origin, rup, slat, slon, sdepth, T=5) fd = test1.getFd() fd_test = np.array( [[0.00000000e+00, 0.00000000e+00, 0.00000000e+00, -8.92879772e-03, -1.74526918e-02, -2.22981746e-02, -2.34350450e-02, -2.13620062e-02, -1.72712346e-02, -1.29509613e-02, -1.02545064e-02, -1.03010185e-02, -1.28847597e-02, -1.66274727e-02, -1.96984070e-02, -2.05377743e-02, -1.81831337e-02, -1.21881814e-02, -2.64862879e-03, 0.00000000e+00, 0.00000000e+00], [0.00000000e+00, 0.00000000e+00, -8.73221519e-03, -2.21421374e-02, -3.18438939e-02, -3.71488270e-02, -3.76239913e-02, -3.35015951e-02, -2.61748968e-02, -1.83864728e-02, -1.34793002e-02, -1.36687799e-02, -1.85727143e-02, -2.55527671e-02, -3.14227568e-02, -3.38933995e-02, -3.19289607e-02, -2.53396980e-02, -1.45943649e-02, -3.71405488e-04, 0.00000000e+00], [0.00000000e+00, -2.54621422e-03, -2.11428566e-02, -3.68609103e-02, -4.87464747e-02, -5.56539037e-02, -5.64419387e-02, -5.05331157e-02, -3.52919381e-02, -2.18782050e-02, -1.40858125e-02, -1.47354546e-02, -2.35727189e-02, -3.74838465e-02, -4.75915414e-02, -5.13000399e-02, -4.87882409e-02, -4.05716321e-02, -2.77368254e-02, -1.13542729e-02, 0.00000000e+00], [0.00000000e+00, -1.21642958e-02, -3.33747360e-02, -5.21661817e-02, -6.74724509e-02, -7.77628842e-02, -8.00243748e-02, -6.42496853e-02, -4.38124530e-02, -1.97027426e-02, -1.45897731e-02, -1.07427056e-02, -3.08235222e-02, -4.82656988e-02, -6.67692677e-02, -7.35152908e-02, -6.85574283e-02, -5.71811573e-02, -4.12138780e-02, -2.20396726e-02, -6.24121310e-04], [0.00000000e+00, -2.00643401e-02, -4.39827328e-02, -6.62722434e-02, -8.60268414e-02, -1.01730306e-01, -9.86277741e-02, -9.82914922e-02, -5.22335876e-02, -1.54622435e-02, -1.57487554e-02, -3.06190808e-03, -4.81481586e-02, -8.92480491e-02, -8.63776477e-02, -9.98130440e-02, -8.95491230e-02, -7.33553695e-02, -5.34401725e-02, -3.11601812e-02, -7.33715103e-03], [0.00000000e+00, -2.50053614e-02, -5.11695772e-02, -7.65997026e-02, -1.00809054e-01, -1.22877573e-01, -1.18738178e-01, -1.55236782e-01, -7.45388001e-02, 1.92779182e-03, -1.94380016e-02, 1.94922939e-02, -7.66669920e-02, -1.53909722e-01, -1.10846875e-01, -1.19746768e-01, -1.07680300e-01, -8.59905101e-02, -6.22042294e-02, -3.71802472e-02, -1.13867485e-02], [0.00000000e+00, -2.63645827e-02, -5.37984901e-02, -8.11337022e-02, -1.08298371e-01, -1.35146441e-01, -1.34825430e-01, -1.85836050e-01, -1.10730875e-01, -3.18861095e-02, 4.14395701e-02, -1.52711946e-02, -1.31840763e-01, -1.96794707e-01, -1.33453212e-01, -1.34989129e-01, -1.17922385e-01, -9.21637323e-02, -6.58369237e-02, -3.91646838e-02, -1.22685698e-02], [0.00000000e+00, -2.64622244e-02, -5.40483999e-02, -8.16190336e-02, -1.09162854e-01, -1.36656677e-01, -1.37081504e-01, -1.89522811e-01, -1.17723634e-01, -4.88765748e-02, -5.04529015e-03, -5.76414497e-02, -1.45712183e-01, -2.03062804e-01, -1.36859828e-01, -1.37107390e-01, -1.19124650e-01, -9.28263279e-02, -6.61800709e-02, -3.93088682e-02, -1.22842049e-02], [0.00000000e+00, -2.58466495e-02, -5.24858827e-02, -7.86086164e-02, -1.03856343e-01, -1.27529509e-01, -1.23794779e-01, -1.68810613e-01, -8.22602627e-02, 1.74236964e-02, 9.38708725e-02, 4.23208284e-02, -8.46343723e-02, -1.70476759e-01, -1.17547884e-01, -1.24569752e-01, -1.11518670e-01, -8.84736806e-02, -6.38037151e-02, -3.81874381e-02, -1.19867610e-02], [0.00000000e+00, -2.42186547e-02, -4.84175525e-02, -7.09428614e-02, -9.07754575e-02, -1.06117824e-01, -9.50228292e-02, -1.29781980e-01, -3.08573454e-02, 7.39058739e-02, 1.30478117e-01, 8.28181149e-02, -2.70389535e-02, -1.20837502e-01, -8.02081725e-02, -9.70274506e-02, -9.35853383e-02, -7.77422806e-02, -5.77817530e-02, -3.53067886e-02, -1.12414659e-02], [0.00000000e+00, -2.16818717e-02, -4.22363856e-02, -5.96909893e-02, -7.24805224e-02, -7.81867829e-02, -6.11838569e-02, -9.05679744e-02, 9.95934969e-03, 1.07503875e-01, 1.52073917e-01, 1.05894634e-01, 8.68652263e-03, -7.98571818e-02, -4.16548658e-02, -6.40511838e-02, -6.99337160e-02, -6.26305633e-02, -4.89098800e-02, -3.09284566e-02, -1.00919381e-02], [0.00000000e+00, -1.84940182e-02, -3.47054606e-02, -4.65278129e-02, -5.22037664e-02, -4.93977115e-02, -2.95395230e-02, -5.82421092e-02, 3.91025654e-02, 1.29337956e-01, 1.67436703e-01, 1.21969296e-01, 3.20823547e-02, -5.00287386e-02, -9.22993907e-03, -3.27186625e-02, -4.52706958e-02, -4.57409325e-02, -3.84701291e-02, -2.55751405e-02, -8.64950254e-03], [0.00000000e+00, -1.49431380e-02, -2.65887341e-02, -3.29162158e-02, -3.22994323e-02, -2.29081781e-02, -2.60259636e-03, -3.29856530e-02, 6.02631314e-02, 1.45003704e-01, 1.79361264e-01, 1.34292814e-01, 4.88007115e-02, -2.82328554e-02, 1.64212421e-02, -5.72391847e-03, -2.23438861e-02, -2.90246794e-02, -2.76054402e-02, -1.97779758e-02, -7.03945406e-03], [0.00000000e+00, -1.12771143e-02, -1.84737590e-02, -1.98228664e-02, -1.40092305e-02, 1.84580818e-04, 1.95817303e-02, -1.32608487e-02, 7.62783168e-02, 1.57076433e-01, 1.89083905e-01, 1.44259188e-01, 6.15722813e-02, -1.17505212e-02, 3.65938109e-02, 1.66937711e-02, -2.18970818e-03, -1.35507683e-02, -1.70890527e-02, -1.39519424e-02, -5.37036892e-03], [0.00000000e+00, -7.67615215e-03, -1.07348257e-02, -7.75276739e-03, 2.22351695e-03, 1.98662250e-02, 3.77611177e-02, 2.42018661e-03, 8.89036172e-02, 1.66855206e-01, 1.97260700e-01, 1.52590263e-01, 7.17981256e-02, 1.18005972e-03, 5.26852303e-02, 3.51638855e-02, 1.51012176e-02, 2.69654076e-04, -7.33815554e-03, -8.36639665e-03, -3.72176313e-03], [0.00000000e+00, -4.50552324e-03, -4.32262850e-03, 1.73559158e-03, 1.42670366e-02, 3.35040699e-02, 4.97279358e-02, 1.85410528e-02, 9.39950666e-02, 1.46646579e-01, 9.13474746e-02, 1.37004651e-01, 7.74648339e-02, 1.59777072e-02, 6.25334939e-02, 4.74577418e-02, 2.72155518e-02, 1.06174952e-02, 3.94103899e-04, -3.68465400e-03, -2.19830733e-03], [0.00000000e+00, -1.74629916e-03, 5.44471813e-04, 8.22933499e-03, 2.15699287e-02, 4.04232250e-02, 5.69678048e-02, 5.52408259e-02, 9.04381272e-02, 1.08204635e-01, 9.14439984e-02, 1.06884511e-01, 8.17241884e-02, 5.55282924e-02, 6.78528399e-02, 5.47188925e-02, 3.35251483e-02, 1.69615982e-02, 5.72048628e-03, -8.81437278e-05, -7.36518436e-04], [0.00000000e+00, 4.07838765e-05, 3.63933766e-03, 1.20080876e-02, 2.51274691e-02, 4.25687176e-02, 6.25685606e-02, 7.33480475e-02, 8.37515545e-02, 9.52500287e-02, 9.15135660e-02, 9.66442834e-02, 8.66659913e-02, 8.10325633e-02, 7.18836713e-02, 5.45548434e-02, 3.55884875e-02, 2.00142359e-02, 8.71200201e-03, 2.04407846e-03, -6.53680674e-06], [0.00000000e+00, 2.40054729e-04, 4.44975227e-03, 1.27572519e-02, 2.49362989e-02, 4.03831326e-02, 5.80039988e-02, 7.61280192e-02, 8.37404162e-02, 8.89634569e-02, 9.15651607e-02, 9.13586235e-02, 8.83589144e-02, 8.27804032e-02, 6.75666471e-02, 5.00483249e-02, 3.36733366e-02, 1.96758691e-02, 9.00603204e-03, 2.18370401e-03, 0.00000000e+00], [0.00000000e+00, 0.00000000e+00, 2.78776980e-03, 1.05086036e-02, 2.13238822e-02, 3.45577738e-02, 4.91570145e-02, 6.36787133e-02, 7.63710088e-02, 8.54072310e-02, 8.92960200e-02, 8.75702197e-02, 8.07095447e-02, 6.97999389e-02, 5.63787286e-02, 4.20734776e-02, 2.83073312e-02, 1.61614525e-02, 6.56194125e-03, 1.00721924e-04, 0.00000000e+00], [0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 5.49667845e-03, 1.47563319e-02, 2.57955743e-02, 3.76689418e-02, 4.91861917e-02, 5.90108907e-02, 6.58478416e-02, 6.87018515e-02, 6.73174642e-02, 6.20270643e-02, 5.35456385e-02, 4.29400416e-02, 3.14129728e-02, 2.00795162e-02, 9.84001885e-03, 1.53992995e-03, 0.00000000e+00, 0.00000000e+00]] ) np.testing.assert_allclose(fd, fd_test, rtol=1e-4)
def test_rv4(): magnitude = 7.0 rake = 90.0 width = np.array([28]) rupx = np.array([0, 0]) rupy = np.array([0, 32]) zp = np.array([0]) dip = np.array([30]) # Convert to lat/lon proj = OrthographicProjection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) # Dummy Origin origin = Origin({'lat': 0, 'lon': 0, 'depth': 0, 'mag': 0, 'id': 'rv4', 'netid': 'us', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) # Rupture rup = QuadRupture.fromTrace( np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='') L = rup.getLength() # Figure out epicenter tmp = rup.getQuadrilaterals()[0] pp0 = Vector.fromPoint(point.Point( tmp[0].longitude, tmp[0].latitude, tmp[0].depth)) pp1 = Vector.fromPoint(point.Point( tmp[1].longitude, tmp[1].latitude, tmp[1].depth)) pp2 = Vector.fromPoint(point.Point( tmp[2].longitude, tmp[2].latitude, tmp[2].depth)) pp3 = Vector.fromPoint(point.Point( tmp[3].longitude, tmp[3].latitude, tmp[3].depth)) dxp = 6 / L dyp = (width - 8) / width mp0 = pp0 + (pp1 - pp0) * dxp mp1 = pp3 + (pp2 - pp3) * dxp rp = mp0 + (mp1 - mp0) * dyp epilat, epilon, epidepth = ecef2latlon(rp.x, rp.y, rp.z) # Fix Origin: origin = Origin({'lat': epilat, 'lon': epilon, 'depth': epidepth, 'mag': magnitude, 'id': 'rv4', 'netid': 'us', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) x = np.linspace(-50, 50, 11) y = np.linspace(-50, 50, 11) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) deps = np.zeros_like(slon) test1 = Bayless2013(origin, rup, slat, slon, deps, T=2.0) # Test fd fd = test1.getFd() fd_test = np.array( [[0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.72143257e-03, 1.34977260e-03, 4.33616224e-15, 1.24446253e-03, 1.16142357e-03, 2.25464716e-03, 7.05281751e-04, 0.00000000e+00], [0.00000000e+00, 0.00000000e+00, 7.62610242e-03, 1.25133844e-02, 5.61896104e-03, 7.63126014e-15, 4.52266194e-03, 4.67970900e-03, 1.02820316e-02, 5.13160096e-03, -6.13926251e-03], [0.00000000e+00, 4.00495234e-03, 2.37608386e-02, 2.37139333e-02, 9.55224050e-03, 5.66364910e-15, 7.70344813e-03, 7.36466362e-03, 1.48239704e-02, 8.40388145e-03, -1.58592485e-02], [8.08385547e-19, 9.38150101e-03, 3.38610620e-02, 3.85351492e-02, 1.91044918e-02, 3.98697802e-15, 1.54321666e-02, 1.21913760e-02, 2.04435166e-02, 1.04931859e-02, -1.85935894e-02], [2.12025421e-18, 1.37316085e-02, 4.40193799e-02, 6.16562477e-02, 4.77612496e-02, 2.60257085e-15, 3.86322888e-02, 1.97965887e-02, 2.64882038e-02, 1.23335908e-02, -2.07389932e-02], [2.64338576e-18, 1.45898292e-02, 4.89104213e-02, 7.70703166e-02, 9.55225258e-02, 1.01875104e-01, 7.73459329e-02, 2.50275508e-02, 2.93537540e-02, 1.30949577e-02, -2.15685454e-02], [2.64330042e-18, 1.45898262e-02, 4.89104186e-02, 7.70703146e-02, 9.55225248e-02, 1.01910945e-01, 7.74050835e-02, 2.52307946e-02, 2.92970736e-02, 1.30880504e-02, -2.15685424e-02], [2.64318867e-18, 1.45898259e-02, 4.89104184e-02, 7.70703144e-02, 9.55225247e-02, 1.01933432e-01, 7.74421258e-02, 2.53572923e-02, 2.92615130e-02, 1.30837284e-02, -2.15685422e-02], [2.64305117e-18, 1.45898284e-02, 4.89104206e-02, 7.70703161e-02, 9.55225256e-02, 1.01942593e-01, 7.74571359e-02, 2.54081640e-02, 2.92472117e-02, 1.30819985e-02, -2.15685446e-02], [2.30141673e-18, 1.40210825e-02, 4.56205547e-02, 6.63109661e-02, 5.79266964e-02, 2.33044622e-15, 4.69672564e-02, 2.18401553e-02, 2.72864925e-02, 1.25728575e-02, -2.10227772e-02], [1.10672535e-18, 1.04777076e-02, 3.59041065e-02, 4.24614318e-02, 2.24217216e-02, 3.66914762e-15, 1.81728517e-02, 1.39301504e-02, 2.14956836e-02, 1.08711460e-02, -1.90802849e-02]] ) np.testing.assert_allclose(fd, fd_test, rtol=2e-4)
def test_ss3_move_hypo1(): magnitude = 7.2 dip = np.array([90]) rake = 180.0 width = np.array([15]) rupx = np.array([0, 0]) rupy = np.array([0, 80]) zp = np.array([0.0]) epix = np.array([1.0]) epiy = np.array([-1.0]) # Convert to lat/lon proj = OrthographicProjection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) epilon, epilat = proj(epix, epiy, reverse=True) # Origin origin = Origin({'lat': epilat[0], 'lon': epilon[0], 'depth': -1, 'mag': magnitude, 'id': 'ss3', 'netid': '', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) rup = QuadRupture.fromTrace( np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='ss3') x = np.linspace(0, 20, 6) y = np.linspace(0, 90, 11) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) deps = np.zeros_like(slon) test1 = Bayless2013(origin, rup, slat, slon, deps, T=1.0) phyp = copy.deepcopy(test1.phyp[0]) plat, plon, pdep = ecef2latlon(phyp.x, phyp.y, phyp.z) px, py = proj(plon, plat, reverse=False) np.testing.assert_allclose(plat, 38.004233219183604, rtol=1e-4) np.testing.assert_allclose(plon, -120.98636122402166, rtol=1e-4) np.testing.assert_allclose(pdep, 7.4999999989205968, rtol=1e-4) # -------------------------------------------------------------------------- # Also for multiple segments # -------------------------------------------------------------------------- dip = np.array([90., 90., 90.]) rake = 180.0 width = np.array([15., 15., 10.]) rupx = np.array([0., 0., 10., 20.]) rupy = np.array([0., 20., 60., 80.]) zp = np.array([0., 0., 0.]) epix = np.array([0.]) epiy = np.array([0.]) # Convert to lat/lon proj = OrthographicProjection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) epilon, epilat = proj(epix, epiy, reverse=True) rup = QuadRupture.fromTrace( np.array(tlon[0:3]), np.array(tlat[0:3]), np.array(tlon[1:4]), np.array(tlat[1:4]), zp, width, dip, origin, reference='') event = {'lat': epilat[0], 'lon': epilon[0], 'depth': 1.0, 'mag': magnitude, 'id': '', 'netid': '', 'network': '', 'locstring': 'test', 'mech': 'SS'} event['time'] = HistoricTime.utcfromtimestamp(int(time.time())) x = np.linspace(0, 20, 6) y = np.linspace(0, 90, 11) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) deps = np.zeros_like(slon) origin = Origin(event) origin.rake = rake test1 = Bayless2013(origin, rup, slat, slon, deps, T=1.0) # 1st pseudo-hyp phyp = copy.deepcopy(test1.phyp[0]) plat, plon, pdep = ecef2latlon(phyp.x, phyp.y, phyp.z) px, py = proj(plon, plat, reverse=False) np.testing.assert_allclose(plat, 38.004233219183604, rtol=1e-4) np.testing.assert_allclose(plon, -120.98636122402166, rtol=1e-4) np.testing.assert_allclose(pdep, 7.4999999989205968, rtol=1e-4) # 2nd pseudo-hyp phyp = copy.deepcopy(test1.phyp[1]) plat, plon, pdep = ecef2latlon(phyp.x, phyp.y, phyp.z) px, py = proj(plon, plat, reverse=False) np.testing.assert_allclose(plat, 38.184097835787796, rtol=1e-4) np.testing.assert_allclose(plon, -120.98636122402166, rtol=1e-4) np.testing.assert_allclose(pdep, 7.4999999989103525, rtol=1e-4) # 3rd pseudo-hyp phyp = copy.deepcopy(test1.phyp[2]) plat, plon, pdep = ecef2latlon(phyp.x, phyp.y, phyp.z) px, py = proj(plon, plat, reverse=False) np.testing.assert_allclose(plat, 38.543778594535752, rtol=1e-4) np.testing.assert_allclose(plon, -120.87137783362499, rtol=1e-4) np.testing.assert_allclose(pdep, 4.9999999995063993, rtol=1e-4)
def test_ss3_m6(): magnitude = 6.0 dip = np.array([90]) rake = 180.0 width = np.array([15]) rupx = np.array([0, 0]) rupy = np.array([0, 80]) zp = np.array([0]) epix = np.array([0]) epiy = np.array([0.2 * rupy[1]]) # Convert to lat/lon proj = OrthographicProjection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) epilon, epilat = proj(epix, epiy, reverse=True) # Origin: origin = Origin({'lat': epilat[0], 'lon': epilon[0], 'depth': 10, 'mag': magnitude, 'id': 'ss3', 'netid': '', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) rup = QuadRupture.fromTrace( np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='ss3') x = np.linspace(0, 20, 6) y = np.linspace(0, 90, 11) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) deps = np.zeros_like(slon) test1 = Bayless2013(origin, rup, slat, slon, deps, T=1.0) # Test fd fd = test1.getFd() fd_test = np.array( [[0.05853668, 0.05032323, 0.0306438, 0.00839635, -0.01102162, -0.02621319], [0.01720501, -0.00687296, -0.03804823, -0.05547473, -0.0644932, -0.06947135], [-0.03000065, -0.07006634, -0.07708165, -0.07865941, -0.0792369, -0.07950887], [0.0398062, 0.02571145, -0.0018651, -0.0255418, -0.04176278, -0.05235095], [0.0696989, 0.06389524, 0.04890304, 0.02983134, 0.01098535, -0.00545921], [0.088278, 0.08511069, 0.07628596, 0.06350294, 0.04875897, 0.03373495], [0.10179334, 0.09978475, 0.09401676, 0.0851842, 0.07422509, 0.06210369], [0.11242209, 0.11102701, 0.10696056, 0.10055471, 0.09229027, 0.08271454], [0.12118279, 0.12015315, 0.11712653, 0.11228058, 0.10588323, 0.09825795], [0.12785957, 0.12706892, 0.12473264, 0.12095384, 0.11589197, 0.10974684], [0.12785908, 0.12724852, 0.12543819, 0.12249026, 0.11850249, 0.11360047]]) np.testing.assert_allclose( fd, fd_test, rtol=1e-4)
def test_multisegment_discordant(): # The one thing that isn't check above is discordancy for segments # with multiple quads. For this, we need a synthetic example. x0 = np.array([0, 1, -1, 10, 9, 7]) y0 = np.array([0, 10, 20, 40, 35, 30]) z0 = np.array([0, 0, 0, 0, 0, 0]) x1 = np.array([1, -1, 0, 9, 7, 6]) y1 = np.array([10, 20, 30, 35, 30, 25]) z1 = np.array([0, 0, 0, 0, 0, 0]) x2 = np.array([3, 1, 2, 7, 5, 4]) y2 = np.array([10, 20, 30, 35, 30, 25]) z2 = np.array([10, 10, 10, 10, 10, 10]) x3 = np.array([2, 3, 1, 8, 7, 5]) y3 = np.array([0, 10, 20, 40, 35, 30]) z3 = np.array([10, 10, 10, 10, 10, 10]) epilat = 32.15270 epilon = -115.30500 proj = OrthographicProjection(epilon - 1, epilon + 1, epilat + 1, epilat - 1) lon0, lat0 = proj(x0, y0, reverse=True) lon1, lat1 = proj(x1, y1, reverse=True) lon2, lat2 = proj(x2, y2, reverse=True) lon3, lat3 = proj(x3, y3, reverse=True) # Make an Origin object; most of the 'event' values don't matter for # this example origin = Origin({ 'lat': 0, 'lon': 0, 'depth': 0, 'mag': 7.2, 'id': '', 'netid': '', 'network': '', 'locstring': '', 'time': HistoricTime.utcfromtimestamp(time.time()) }) rup = QuadRupture.fromVertices(lon0, lat0, z0, lon1, lat1, z1, lon2, lat2, z2, lon3, lat3, z3, origin, group_index=[0, 0, 0, 1, 1, 1]) # Sites buf = 0.25 lat = np.linspace(np.nanmin(rup.lats) - buf, np.nanmax(rup.lats) + buf, 20) lon = np.linspace(np.nanmin(rup.lons) - buf, np.nanmax(rup.lons) + buf, 20) lons, lats = np.meshgrid(lon, lat) dep = np.zeros_like(lons) x, y = proj(lon, lat) rupx, rupy = proj(rup.lons, rup.lats) # Calculate U and T dtypes = ['U', 'T'] dists = get_distance(dtypes, lats, lons, dep, rup) targetU = np.array( [[ -28.53228275, -28.36479713, -28.20139732, -28.0407734, -27.88135558, -27.72144153, -27.55935946, -27.39362017, -27.22300147, -27.04653062, -26.86338215, -26.67275638, -26.47381287, -26.26569449, -26.04762427, -25.81902477, -25.57961136, -25.32943282, -25.06885791, -24.79852214 ], [ -23.53750292, -23.3748086, -23.21793537, -23.06521934, -22.91449689, -22.76331684, -22.60928211, -22.45042208, -22.28542121, -22.11355532, -21.93435402, -21.74720475, -21.55115107, -21.34497916, -21.12749377, -20.89781118, -20.6555466, -20.40086149, -20.13439948, -19.85716145 ], [ -18.53499939, -18.37689929, -18.22732841, -18.08427516, -17.94468687, -17.80472632, -17.66045115, -17.50880802, -17.3484421, -17.17963435, -17.0032098, -16.81921732, -16.62638972, -16.42258419, -16.20564846, -15.9741218, -15.72753538, -15.4663671, -15.19180844, -14.9054813 ], [ -13.52283359, -13.36797542, -13.22589288, -13.09466537, -12.97028551, -12.84653536, -12.71591089, -12.57212088, -12.41335561, -12.24319318, -12.06681006, -11.88598424, -11.69798166, -11.49796348, -11.28169605, -11.04691388, -10.79343174, -10.52262594, -10.23677602, -9.93851158 ], [ -8.49936685, -8.34357094, -8.20650964, -8.08786858, -7.98403171, -7.88628837, -7.78005273, -7.64833307, -7.48359988, -7.29992491, -7.11862682, -6.94410189, -6.76618701, -6.5727842, -6.35634881, -6.11465447, -5.84925708, -5.56369035, -5.26212482, -4.94857454 ], [ -3.46638168, -3.30047216, -3.15914418, -3.04618465, -2.96252939, -2.90194067, -2.84436315, -2.75029014, -2.56983592, -2.33744275, -2.1512136, -1.99833104, -1.84066354, -1.6541107, -1.43071517, -1.17252753, -0.88592286, -0.57817222, -0.25582315, 0.07585567 ], [ 1.56416954, 1.75393848, 1.9183586, 2.04909316, 2.13723278, 2.17776584, 2.18272501, 2.20967639, 2.37405656, 2.65073289, 2.80205222, 2.90973407, 3.05124404, 3.2505182, 3.50336116, 3.7967575, 4.11742779, 4.45465822, 4.80070204, 5.15033407 ], [ 6.5633489, 6.78740885, 6.99419348, 7.17551069, 7.31963558, 7.4113505, 7.43666779, 7.40177458, 7.40517136, 7.58520044, 7.62013169, 7.71596777, 7.90558457, 8.17213015, 8.49008681, 8.83763176, 9.19937294, 9.56556659, 9.9305469, 10.29132309 ], [ 11.48996073, 11.74301446, 11.99016964, 12.22782156, 12.44984059, 12.6446727, 12.78798484, 12.82584849, 12.61992833, 12.26579742, 12.32166685, 12.54665462, 12.86628045, 13.23578462, 13.62571822, 14.01882924, 14.40617707, 14.78388296, 15.15089889, 15.5076165 ], [ 16.31383216, 16.57376544, 16.83189511, 17.08626411, 17.33309437, 17.56429108, 17.76005623, 17.85853532, 17.57101025, 17.32637346, 17.45075419, 17.77199513, 18.16933168, 18.58284635, 18.9891851, 19.37985879, 19.75324557, 20.11079653, 20.4549905, 20.78837053 ], [ 21.03975749, 21.28450315, 21.5243142, 21.75603974, 21.97469496, 22.17298057, 22.34310053, 22.49668569, 22.73940191, 22.70030633, 22.95351405, 23.35967832, 23.75891016, 24.14867803, 24.51536915, 24.85878249, 25.18398203, 25.49615514, 25.79932964, 26.09638269 ], [ 25.70484089, 25.92709225, 26.14280395, 26.35119497, 26.55363501, 26.75827099, 26.9915523, 27.31779086, 27.77993211, 27.71070831, 28.13624949, 28.723482, 29.25285078, 29.66404032, 30.00169474, 30.30044315, 30.57916576, 30.84804427, 31.1126134, 31.37586841 ], [ 30.35406633, 30.5585145, 30.75843356, 30.95627127, 31.15811912, 31.3763124, 31.63114968, 31.94156189, 32.23691802, 32.38759301, 32.86915665, 33.83467935, 34.46125278, 34.89905345, 35.25111257, 35.55095664, 35.82150686, 36.07720619, 36.32643896, 36.57385362 ], [ 35.0222379, 35.21734711, 35.41081942, 35.60589495, 35.80774808, 36.02313791, 36.25826988, 36.51619168, 36.81025966, 37.21777129, 37.86674108, 38.66578072, 39.25203723, 39.78060643, 40.20815617, 40.5606039, 40.86634527, 41.14457482, 41.40732554, 41.66197722 ], [ 39.73046099, 39.92514041, 40.12152415, 40.32316112, 40.5350467, 40.76393316, 41.01937758, 41.3172128, 41.68596492, 42.16604148, 42.77622755, 43.447503, 44.03771478, 44.55012468, 45.00551259, 45.40376857, 45.75505135, 46.07204699, 46.36554362, 46.64361367 ], [ 44.4876174, 44.68959464, 44.89710008, 45.11420443, 45.34646809, 45.60143197, 45.88932906, 46.22363997, 46.61975585, 47.0884227, 47.62307543, 48.1913408, 48.74937117, 49.26945799, 49.74327902, 50.17123158, 50.55810895, 50.91098842, 51.23731582, 51.54375617 ], [ 49.29279265, 49.50696882, 49.73006999, 49.96625305, 50.22080319, 50.50022572, 50.81209441, 51.1642666, 51.56290694, 52.00913021, 52.49553006, 53.00565389, 53.51861282, 54.01614414, 54.48672101, 54.9254339, 55.33212663, 55.70951516, 56.06170563, 56.39317058 ], [ 54.13906629, 54.3671694, 54.60643024, 54.86053563, 55.13377911, 55.43088558, 55.75658576, 56.1148189, 56.50752978, 56.93329478, 57.38640012, 57.85715119, 58.33367994, 58.80451404, 59.26065475, 59.69644542, 60.10938419, 60.49940252, 60.86803179, 61.21767916 ], [ 59.01741908, 59.25887491, 59.51248349, 59.78119592, 60.06816694, 60.37651862, 60.70895927, 61.0672529, 61.45160192, 61.86010542, 62.28853397, 62.73062937, 63.17894547, 63.62598375, 64.06523791, 64.49185106, 64.90281064, 65.2967858, 65.67377362, 66.03469546 ], [ 63.9193099, 64.17236414, 64.4376317, 64.71732366, 65.01362255, 65.32847988, 65.66334836, 66.0188704, 66.39457546, 66.7886684, 67.19800022, 67.61828012, 68.04451487, 68.47157851, 68.89476917, 69.31022713, 69.71515194, 70.10782673, 70.4875021, 70.85420436 ]]) np.testing.assert_allclose(targetU, dists['U'], atol=0.01) targetT = np.array([ [ -2.27427469e+01, -1.97498544e+01, -1.67512900e+01, -1.37464632e+01, -1.07350712e+01, -7.71715083e+00, -4.69305811e+00, -1.66336318e+00, 1.37131605e+00, 4.41047613e+00, 7.45381136e+00, 1.05011799e+01, 1.35524779e+01, 1.66074913e+01, 1.96657949e+01, 2.27267294e+01, 2.57894503e+01, 2.88530154e+01, 3.19164798e+01, 3.49789747e+01 ], [ -2.30778766e+01, -2.00896906e+01, -1.70950973e+01, -1.40931667e+01, -1.10834219e+01, -8.06600712e+00, -5.04171582e+00, -2.01179123e+00, 1.02248614e+00, 4.06025218e+00, 7.10129626e+00, 1.01459367e+01, 1.31946312e+01, 1.62475702e+01, 1.93044511e+01, 2.23644788e+01, 2.54265185e+01, 2.84892997e+01, 3.15515954e+01, 3.46123426e+01 ], [ -2.33971472e+01, -2.04144525e+01, -1.74245193e+01, -1.44256870e+01, -1.14169177e+01, -8.39830615e+00, -5.37141115e+00, -2.33902937e+00, 6.95823925e-01, 3.73133431e+00, 6.76769593e+00, 9.80663091e+00, 1.28500821e+01, 1.58991008e+01, 1.89534737e+01, 2.20119662e+01, 2.50728111e+01, 2.81341606e+01, 3.11943854e+01, 3.42522163e+01 ], [ -2.36965870e+01, -2.07206976e+01, -1.77370901e+01, -1.47426715e+01, -1.17347885e+01, -8.71247709e+00, -5.67801094e+00, -2.63761285e+00, 4.00625914e-01, 3.43182302e+00, 6.45782532e+00, 9.48491128e+00, 1.25187545e+01, 1.55616657e+01, 1.86127822e+01, 2.16694756e+01, 2.47286680e+01, 2.77876297e+01, 3.08443066e+01, 3.38973527e+01 ], [ -2.39698399e+01, -2.10022612e+01, -1.80281475e+01, -1.50423801e+01, -1.20388157e+01, -9.01204040e+00, -5.96160398e+00, -2.89867328e+00, 1.52194374e-01, 3.17268218e+00, 6.17334725e+00, 9.17699572e+00, 1.21964990e+01, 1.52330975e+01, 1.82821226e+01, 2.13375815e+01, 2.43943933e+01, 2.74490375e+01, 3.04994435e+01, 3.35446330e+01 ], [ -2.42070742e+01, -2.12471979e+01, -1.82855675e+01, -1.53163304e+01, -1.23296744e+01, -9.31127857e+00, -6.24535210e+00, -3.12882361e+00, -2.24460581e-02, 2.95354485e+00, 5.89215412e+00, 8.86387424e+00, 1.18748249e+01, 1.49128245e+01, 1.79640055e+01, 2.10182501e+01, 2.40696313e+01, 2.71153177e+01, 3.01543919e+01, 3.31869788e+01 ], [ -2.43971375e+01, -2.14368866e+01, -1.84826148e+01, -1.55321207e+01, -1.25786621e+01, -9.60654678e+00, -6.58612151e+00, -3.48118311e+00, -3.16555025e-01, 2.61618307e+00, 5.53740540e+00, 8.52666510e+00, 1.15623361e+01, 1.46149780e+01, 1.76674294e+01, 2.07125025e+01, 2.37483764e+01, 2.67756033e+01, 2.97955606e+01, 3.28097430e+01 ], [ -2.45384925e+01, -2.15583842e+01, -1.85874288e+01, -1.56290738e+01, -1.26867853e+01, -9.76140655e+00, -6.84407754e+00, -3.90089971e+00, -8.41806596e-01, 2.14754495e+00, 5.18583472e+00, 8.26271822e+00, 1.13266091e+01, 1.43684333e+01, 1.73916223e+01, 2.04017469e+01, 2.34034936e+01, 2.64002111e+01, 2.93941282e+01, 3.23866586e+01 ], [ -2.46576775e+01, -2.16355610e+01, -1.86129545e+01, -1.55919156e+01, -1.25763765e+01, -9.57306672e+00, -6.59044329e+00, -3.62352541e+00, -5.92041388e-01, 2.33255341e+00, 5.29498494e+00, 8.24834463e+00, 1.11833819e+01, 1.41167617e+01, 1.70571082e+01, 2.00065102e+01, 2.29645946e+01, 2.59302937e+01, 2.89023967e+01, 3.18797332e+01 ], [ -2.48161623e+01, -2.17489533e+01, -1.86651328e+01, -1.55589864e+01, -1.24224388e+01, -9.24466730e+00, -6.01521475e+00, -2.75148770e+00, 3.89519039e-01, 2.99589525e+00, 5.45696689e+00, 8.01247078e+00, 1.07291540e+01, 1.35565782e+01, 1.64461360e+01, 1.93723515e+01, 2.23222250e+01, 2.52881249e+01, 2.82650171e+01, 3.12494172e+01 ], [ -2.50857405e+01, -2.20002811e+01, -1.88926336e+01, -1.57550887e+01, -1.25770789e+01, -9.34497451e+00, -6.04430316e+00, -2.67290100e+00, 5.40854953e-01, 2.30509492e+00, 3.58183843e+00, 6.23701436e+00, 9.28727128e+00, 1.23205706e+01, 1.53428945e+01, 1.83666035e+01, 2.13934954e+01, 2.44218171e+01, 2.74496472e+01, 3.04757209e+01 ], [ -2.55082697e+01, -2.24454912e+01, -1.93710045e+01, -1.62824768e+01, -1.31767102e+01, -1.00469827e+01, -6.86985653e+00, -3.54681638e+00, 1.07062999e-01, 3.34891657e-01, -1.70694750e-01, 3.57896940e+00, 7.17013928e+00, 1.05232789e+01, 1.37976070e+01, 1.70230221e+01, 2.02076136e+01, 2.33576919e+01, 2.64794914e+01, 2.95785985e+01 ], [ -2.60778515e+01, -2.30695744e+01, -2.00684150e+01, -1.70790651e+01, -1.41074315e+01, -1.11587507e+01, -8.23273307e+00, -5.33306966e+00, -2.80144302e+00, -1.84760416e+00, -1.05368779e+00, 1.26163211e+00, 4.90086292e+00, 8.53883059e+00, 1.20996577e+01, 1.55589098e+01, 1.89237978e+01, 2.22114952e+01, 2.54390313e+01, 2.86203790e+01 ], [ -2.67537229e+01, -2.38123298e+01, -2.08964272e+01, -1.80168638e+01, -1.51896230e+01, -1.24401995e+01, -9.81536176e+00, -7.41008520e+00, -5.38073414e+00, -3.78262975e+00, -2.29669890e+00, -3.53057240e-01, 3.13642477e+00, 6.97021789e+00, 1.07026969e+01, 1.42945488e+01, 1.77655640e+01, 2.11406146e+01, 2.44409375e+01, 2.76832489e+01 ], [ -2.74832153e+01, -2.46028623e+01, -2.17593854e+01, -1.89653378e+01, -1.62381218e+01, -1.36022404e+01, -1.10914555e+01, -8.74572618e+00, -6.58963863e+00, -4.58336507e+00, -2.57607747e+00, -2.67233150e-01, 2.82788692e+00, 6.36737407e+00, 9.93334021e+00, 1.34440609e+01, 1.68846862e+01, 2.02577163e+01, 2.35710668e+01, 2.68337230e+01 ], [ -2.82199728e+01, -2.53838486e+01, -2.25869234e+01, -1.98388981e+01, -1.71512612e+01, -1.45365893e+01, -1.20059297e+01, -9.56220853e+00, -7.18799023e+00, -4.83006994e+00, -2.39120744e+00, 2.51308627e-01, 3.17331949e+00, 6.33022626e+00, 9.61428455e+00, 1.29426788e+01, 1.62705993e+01, 1.95770961e+01, 2.28539081e+01, 2.60992146e+01 ], [ -2.89332200e+01, -2.61222251e+01, -2.33461951e+01, -2.06105222e+01, -1.79200485e+01, -1.52776479e+01, -1.26817390e+01, -1.01225741e+01, -7.57801870e+00, -5.01122873e+00, -2.37434916e+00, 3.78303328e-01, 3.27093827e+00, 6.29527723e+00, 9.41912399e+00, 1.26046423e+01, 1.58204753e+01, 1.90448689e+01, 2.22643265e+01, 2.54712657e+01 ], [ -2.96082809e+01, -2.68067500e+01, -2.40331802e+01, -2.12894659e+01, -1.85760763e+01, -1.58910124e+01, -1.32284735e+01, -1.05774862e+01, -7.92111801e+00, -5.23724922e+00, -2.50179068e+00, 3.05790568e-01, 3.19666197e+00, 6.16975035e+00, 9.21353475e+00, 1.23109519e+01, 1.54443017e+01, 1.85982825e+01, 2.17611016e+01, 2.49243957e+01 ], [ -3.02420504e+01, -2.74395034e+01, -2.46578094e+01, -2.18967353e+01, -1.91546206e+01, -1.64278219e+01, -1.37101816e+01, -1.09927140e+01, -8.26378719e+00, -5.51007519e+00, -2.71836365e+00, 1.22111758e-01, 3.01754598e+00, 5.96851903e+00, 8.97043180e+00, 1.20150997e+01, 1.50927299e+01, 1.81935916e+01, 2.13090724e+01, 2.44321477e+01 ], [ -3.08377073e+01, -2.80281994e+01, -2.52335334e+01, -2.24524366e+01, -1.96825082e+01, -1.69199811e+01, -1.41595768e+01, -1.13945492e+01, -8.61701306e+00, -5.81861191e+00, -2.99148017e+00, -1.29317230e-01, 2.77170749e+00, 5.71249079e+00, 8.69110042e+00, 1.17033684e+01, 1.47437429e+01, 1.78061436e+01, 2.08846464e+01, 2.39739290e+01 ] ]) np.testing.assert_allclose(targetT, dists['T'], atol=0.01)
def get_extent(rupture=None, config=None): """ Method to compute map extent from rupture. There are numerous methods for getting the extent: - It can be specified directly in the config file, - it can be hard coded for specific magnitude ranges in the config file, or - it can be based on the MultiGMPE for the event. All methods except for the first requires a rupture object. If no config is provided then a rupture is required and the extent is based on a generic set of active/stable. Args: rupture (Rupture): A ShakeMap Rupture instance. config (ConfigObj): ShakeMap config object. Returns: tuple: lonmin, lonmax, latmin, latmax rounded to the nearest arc-minute.. """ # ------------------------------------------------------------------------- # Check to see what parameters are specified in the extent config # ------------------------------------------------------------------------- spans = {} bounds = [] if config is not None: if 'extent' in config: if 'magnitude_spans' in config['extent']: if len(config['extent']['magnitude_spans']): if isinstance(config['extent']['magnitude_spans'], dict): spans = config['extent']['magnitude_spans'] if 'bounds' in config['extent']: if 'extent' in config['extent']['bounds']: if config['extent']['bounds']['extent'][0] != -999.0: bounds = config['extent']['bounds']['extent'] # ------------------------------------------------------------------------- # Simplest option: extent was specified in the config, use that and exit. # ------------------------------------------------------------------------- if len(bounds): xmin, ymin, xmax, ymax = bounds return (xmin, xmax, ymin, ymax) if not rupture or not isinstance(rupture, Rupture): raise TypeError('get_extent() requires a rupture object if the extent ' 'is not specified in the config object.') # Find the central point origin = rupture.getOrigin() if isinstance(rupture, (QuadRupture, EdgeRupture)): # For an extended rupture, it is the midpoint between the extent of the # verticies lats = rupture.lats lons = rupture.lons # Remove nans lons = lons[~np.isnan(lons)] lats = lats[~np.isnan(lats)] clat = 0.5 * (np.nanmax(lats) + np.nanmin(lats)) clon = 0.5 * (np.nanmax(lons) + np.nanmin(lons)) else: # For a point source, it is just the epicenter clat = origin.lat clon = origin.lon mag = origin.mag # ------------------------------------------------------------------------- # Second simplest option: spans are hardcoded based on magnitude # ------------------------------------------------------------------------- if len(spans): xmin = None xmax = None ymin = None ymax = None for spankey, span in spans.items(): if mag > span[0] and mag <= span[1]: ymin = clat - span[2] / 2 ymax = clat + span[2] / 2 xmin = clon - span[3] / 2 xmax = clon + span[3] / 2 break if xmin is not None: return (xmin, xmax, ymin, ymax) # ------------------------------------------------------------------------- # Use MultiGMPE to get spans # ------------------------------------------------------------------------- if config is not None: gmpe = MultiGMPE.from_config(config) gmice = get_object_from_config('gmice', 'modeling', config) else: # Put in some default values for conf config = { 'extent': { 'mmi': { 'threshold': 4.5, 'mindist': 100, 'maxdist': 1000 } } } # Generic GMPEs choices based only on active vs stable # as defaults... stable = is_stable(origin.lon, origin.lat) if not stable: ASK14 = AbrahamsonEtAl2014() CB14 = CampbellBozorgnia2014() CY14 = ChiouYoungs2014() gmpes = [ASK14, CB14, CY14] site_gmpes = None weights = [1 / 3.0, 1 / 3.0, 1 / 3.0] gmice = WGRW12() else: Fea96 = FrankelEtAl1996MwNSHMP2008() Tea97 = ToroEtAl1997MwNSHMP2008() Sea02 = SilvaEtAl2002MwNSHMP2008() C03 = Campbell2003MwNSHMP2008() TP05 = TavakoliPezeshk2005MwNSHMP2008() AB06p = AtkinsonBoore2006Modified2011() Pea11 = PezeshkEtAl2011() Atk08p = Atkinson2008prime() Sea01 = SomervilleEtAl2001NSHMP2008() gmpes = [ Fea96, Tea97, Sea02, C03, TP05, AB06p, Pea11, Atk08p, Sea01 ] site_gmpes = [AB06p] weights = [0.16, 0.0, 0.0, 0.17, 0.17, 0.3, 0.2, 0.0, 0.0] gmice = AK07() gmpe = MultiGMPE.from_list(gmpes, weights, default_gmpes_for_site=site_gmpes) min_mmi = config['extent']['mmi']['threshold'] default_imt = imt.SA(1.0) sd_types = [const.StdDev.TOTAL] # Distance context dx = DistancesContext() # This imposes minimum/ maximum distances of: # 80 and 800 km; could make this configurable d_min = config['extent']['mmi']['mindist'] d_max = config['extent']['mmi']['maxdist'] dx.rjb = np.logspace(np.log10(d_min), np.log10(d_max), 2000) # Details don't matter for this; assuming vertical surface rupturing fault # with epicenter at the surface. dx.rrup = dx.rjb dx.rhypo = dx.rjb dx.repi = dx.rjb dx.rx = np.zeros_like(dx.rjb) dx.ry0 = np.zeros_like(dx.rjb) dx.rvolc = np.zeros_like(dx.rjb) # Sites context sx = SitesContext() # Set to soft soil conditions sx.vs30 = np.full_like(dx.rjb, 180) sx = MultiGMPE.set_sites_depth_parameters(sx, gmpe) sx.vs30measured = np.full_like(sx.vs30, False, dtype=bool) sx = Sites._addDepthParameters(sx) sx.backarc = np.full_like(sx.vs30, False, dtype=bool) # Rupture context rx = RuptureContext() rx.mag = origin.mag rx.rake = 0.0 # From WC94... rx.width = 10**(-0.76 + 0.27 * rx.mag) rx.dip = 90.0 rx.ztor = origin.depth rx.hypo_depth = origin.depth gmpe_imt_mean, _ = gmpe.get_mean_and_stddevs(sx, rx, dx, default_imt, sd_types) # Convert to MMI gmpe_to_mmi, _ = gmice.getMIfromGM(gmpe_imt_mean, default_imt) # Minimum distance that exceeds threshold MMI? dists_exceed_mmi = dx.rjb[gmpe_to_mmi > min_mmi] if len(dists_exceed_mmi): mindist_km = np.max(dists_exceed_mmi) else: mindist_km = d_min # Get a projection proj = OrthographicProjection(clon - 4, clon + 4, clat + 4, clat - 4) if isinstance(rupture, (QuadRupture, EdgeRupture)): ruptx, rupty = proj(lons, lats) else: ruptx, rupty = proj(clon, clat) xmin = np.nanmin(ruptx) - mindist_km ymin = np.nanmin(rupty) - mindist_km xmax = np.nanmax(ruptx) + mindist_km ymax = np.nanmax(rupty) + mindist_km # Put a limit on range of aspect ratio dx = xmax - xmin dy = ymax - ymin ar = dy / dx if ar > 1.2: # Inflate x dx_target = dy / 1.2 ddx = dx_target - dx xmax = xmax + ddx / 2 xmin = xmin - ddx / 2 if ar < 0.83: # Inflate y dy_target = dx * 0.83 ddy = dy_target - dy ymax = ymax + ddy / 2 ymin = ymin - ddy / 2 lonmin, latmin = proj(np.array([xmin]), np.array([ymin]), reverse=True) lonmax, latmax = proj(np.array([xmax]), np.array([ymax]), reverse=True) # # Round coordinates to the nearest minute -- that should make the # output grid register with common grid resolutions (60c, 30c, # 15c, 7.5c) # logging.debug("Extent: %f, %f, %f, %f" % (lonmin, lonmax, latmin, latmax)) return _round_coord(lonmin[0]), _round_coord(lonmax[0]), \ _round_coord(latmin[0]), _round_coord(latmax[0])
def _get_extent_from_multigmpe(rupture, config=None): """ Use MultiGMPE to determine extent """ (clon, clat) = _rupture_center(rupture) origin = rupture.getOrigin() if config is not None: gmpe = MultiGMPE.from_config(config) gmice = get_object_from_config('gmice', 'modeling', config) if imt.SA in gmice.DEFINED_FOR_INTENSITY_MEASURE_TYPES: default_imt = imt.SA(1.0) elif imt.PGV in gmice.DEFINED_FOR_INTENSITY_MEASURE_TYPES: default_imt = imt.PGV() else: default_imt = imt.PGA() else: # Put in some default values for conf config = { 'extent': { 'mmi': { 'threshold': 4.5, 'mindist': 100, 'maxdist': 1000 } } } # Generic GMPEs choices based only on active vs stable # as defaults... stable = is_stable(origin.lon, origin.lat) if not stable: ASK14 = AbrahamsonEtAl2014() CB14 = CampbellBozorgnia2014() CY14 = ChiouYoungs2014() gmpes = [ASK14, CB14, CY14] site_gmpes = None weights = [1/3.0, 1/3.0, 1/3.0] gmice = WGRW12() else: Fea96 = FrankelEtAl1996MwNSHMP2008() Tea97 = ToroEtAl1997MwNSHMP2008() Sea02 = SilvaEtAl2002MwNSHMP2008() C03 = Campbell2003MwNSHMP2008() TP05 = TavakoliPezeshk2005MwNSHMP2008() AB06p = AtkinsonBoore2006Modified2011() Pea11 = PezeshkEtAl2011() Atk08p = Atkinson2008prime() Sea01 = SomervilleEtAl2001NSHMP2008() gmpes = [Fea96, Tea97, Sea02, C03, TP05, AB06p, Pea11, Atk08p, Sea01] site_gmpes = [AB06p] weights = [0.16, 0.0, 0.0, 0.17, 0.17, 0.3, 0.2, 0.0, 0.0] gmice = AK07() gmpe = MultiGMPE.from_list( gmpes, weights, default_gmpes_for_site=site_gmpes) default_imt = imt.SA(1.0) min_mmi = config['extent']['mmi']['threshold'] sd_types = [const.StdDev.TOTAL] # Distance context dx = DistancesContext() # This imposes minimum/ maximum distances of: # 80 and 800 km; could make this configurable d_min = config['extent']['mmi']['mindist'] d_max = config['extent']['mmi']['maxdist'] dx.rjb = np.logspace(np.log10(d_min), np.log10(d_max), 2000) # Details don't matter for this; assuming vertical surface rupturing fault # with epicenter at the surface. dx.rrup = dx.rjb dx.rhypo = dx.rjb dx.repi = dx.rjb dx.rx = np.zeros_like(dx.rjb) dx.ry0 = np.zeros_like(dx.rjb) dx.rvolc = np.zeros_like(dx.rjb) # Sites context sx = SitesContext() # Set to soft soil conditions sx.vs30 = np.full_like(dx.rjb, 180) sx = MultiGMPE.set_sites_depth_parameters(sx, gmpe) sx.vs30measured = np.full_like(sx.vs30, False, dtype=bool) sx = Sites._addDepthParameters(sx) sx.backarc = np.full_like(sx.vs30, False, dtype=bool) # Rupture context rx = RuptureContext() rx.mag = origin.mag rx.rake = 0.0 # From WC94... rx.width = 10**(-0.76 + 0.27*rx.mag) rx.dip = 90.0 rx.ztor = origin.depth rx.hypo_depth = origin.depth gmpe_imt_mean, _ = gmpe.get_mean_and_stddevs( sx, rx, dx, default_imt, sd_types) # Convert to MMI gmpe_to_mmi, _ = gmice.getMIfromGM(gmpe_imt_mean, default_imt) # Minimum distance that exceeds threshold MMI? dists_exceed_mmi = dx.rjb[gmpe_to_mmi > min_mmi] if len(dists_exceed_mmi): mindist_km = np.max(dists_exceed_mmi) else: mindist_km = d_min # Get a projection proj = OrthographicProjection(clon - 4, clon + 4, clat + 4, clat - 4) if isinstance(rupture, (QuadRupture, EdgeRupture)): ruptx, rupty = proj( rupture.lons[~np.isnan(rupture.lons)], rupture.lats[~np.isnan(rupture.lats)] ) else: ruptx, rupty = proj(clon, clat) xmin = np.nanmin(ruptx) - mindist_km ymin = np.nanmin(rupty) - mindist_km xmax = np.nanmax(ruptx) + mindist_km ymax = np.nanmax(rupty) + mindist_km # Put a limit on range of aspect ratio dx = xmax - xmin dy = ymax - ymin ar = dy / dx if ar > 1.2: # Inflate x dx_target = dy / 1.2 ddx = dx_target - dx xmax = xmax + ddx / 2 xmin = xmin - ddx / 2 if ar < 0.83: # Inflate y dy_target = dx * 0.83 ddy = dy_target - dy ymax = ymax + ddy / 2 ymin = ymin - ddy / 2 lonmin, latmin = proj(np.array([xmin]), np.array([ymin]), reverse=True) lonmax, latmax = proj(np.array([xmax]), np.array([ymax]), reverse=True) # # Round coordinates to the nearest minute -- that should make the # output grid register with common grid resolutions (60c, 30c, # 15c, 7.5c) # logging.debug("Extent: %f, %f, %f, %f" % (lonmin, lonmax, latmin, latmax)) return _round_coord(lonmin[0]), _round_coord(lonmax[0]), \ _round_coord(latmin[0]), _round_coord(latmax[0])
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 fromTrace(cls, xp0, yp0, xp1, yp1, zp, widths, dips, origin, strike=None, group_index=None, reference=""): """ Create a QuadRupture instance from a set of vertices that define the top of the rupture, and an array of widths/dips. Each rupture quadrilaterial is defined by specifying the latitude, longitude, and depth of the two vertices on the top edges, which must have the dame depths. The other verticies are then constructed from the top edges and the width and dip of the quadrilateral. Args: xp0 (array): Array or list of longitudes (floats) of p0. yp0 (array): Array or list of latitudes (floats) of p0. xp1 (array): Array or list of longitudes (floats) of p1. yp1 (array): Array or list of latitudes (floats) of p1. zp (array): Array or list of depths for each of the top of rupture rectangles (km). widths (array): Array of widths for each of rectangle (km). dips (array): Array of dips for each of rectangle (degrees). origin (Origin): Reference to a ShakeMap origin object. strike (array): If None then strike is computed from verticies of top edge of each quadrilateral. If the array has only a single value, then all quadrilaterals are constructed assuming this strike direction. If an array with the same length as the trace coordinates then it specifies the strike for each quadrilateral. group_index (list): List of integers to indicate group index. If None then each quadrilateral is assumed to be in a different group since there is no guarantee that any of them are continuous. reference (str): String explaining where the rupture definition came from (publication style reference, etc.). Returns: QuadRupture instance. Raises: ShakeLibException: if the input arrays are not all the same length, or if the strike array is not length 1 or the same length as the input arrays. """ if not (len(xp0) == len(yp0) == len(xp1) == len(yp1) == len(zp) == len(dips) == len(widths)): raise ShakeLibException( 'Number of xp0,yp0,xp1,yp1,zp,widths,dips points must be ' 'equal.') if strike is not None and len(xp0) != len(strike) and len(strike) != 1: raise ShakeLibException( 'Strike must be None or an array of one value or the ' 'same length as trace coordinates.') if group_index is None: group_index = np.array(range(len(xp0))) # Convert dips to radians dips = np.radians(dips) # Ensure that all input sequences are numpy arrays xp0 = np.array(xp0, dtype='d') xp1 = np.array(xp1, dtype='d') yp0 = np.array(yp0, dtype='d') yp1 = np.array(yp1, dtype='d') zp = np.array(zp, dtype='d') widths = np.array(widths, dtype='d') dips = np.array(dips, dtype='d') # Get a projection object west = np.min((xp0.min(), xp1.min())) east = np.max((xp0.max(), xp1.max())) south = np.min((yp0.min(), yp1.min())) north = np.max((yp0.max(), yp1.max())) # Projected coordinates are in km proj = OrthographicProjection(west, east, north, south) xp2 = np.zeros_like(xp0) xp3 = np.zeros_like(xp0) yp2 = np.zeros_like(xp0) yp3 = np.zeros_like(xp0) zpdown = np.zeros_like(zp) for i in range(0, len(xp0)): # Project the top edge coordinates p0x, p0y = proj(xp0[i], yp0[i]) p1x, p1y = proj(xp1[i], yp1[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(dips[i]) * widths[i] dx = np.cos(dips[i]) * widths[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] = zp[i] + dz # --------------------------------------------------------------------- # Create GeoJSON object # --------------------------------------------------------------------- coords = [] u_groups = np.unique(group_index) n_groups = len(u_groups) for i in range(n_groups): ind = np.where(u_groups[i] == group_index)[0] lons = np.concatenate([ xp0[ind[0]].reshape((1, )), xp1[ind], xp2[ind][::-1], xp3[ind][::-1][-1].reshape((1, )), xp0[ind[0]].reshape((1, )) ]) lats = np.concatenate([ yp0[ind[0]].reshape((1, )), yp1[ind], yp2[ind][::-1], yp3[ind][::-1][-1].reshape((1, )), yp0[ind[0]].reshape((1, )) ]) deps = np.concatenate([ zp[ind[0]].reshape((1, )), zp[ind], zpdown[ind][::-1], zpdown[ind][::-1][-1].reshape((1, )), zp[ind[0]].reshape((1, )) ]) poly = [] for lon, lat, dep in zip(lons, lats, deps): poly.append([lon, lat, dep]) coords.append(poly) d = { "type": "FeatureCollection", "metadata": { "reference": reference }, "features": [{ "type": "Feature", "properties": { "rupture type": "rupture extent" }, "geometry": { "type": "MultiPolygon", "coordinates": [coords] } }] } # Add origin information to metadata odict = origin.__dict__ for k, v in odict.items(): if isinstance(v, HistoricTime): d['metadata'][k] = v.strftime(constants.TIMEFMT) else: d['metadata'][k] = v return cls(d, origin)
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
def __computeLD(self): """ Computes LD -- the rupture length de-normalization term. """ # Use an orthographic projection latmin = self._lat.min() latmax = self._lat.max() lonmin = self._lon.min() lonmax = self._lon.max() proj = OrthographicProjection(lonmin, lonmax, latmax, latmin) # Get epi projection epi_x, epi_y = proj(self._hyp.longitude, self._hyp.latitude) # Get the lines for the top edge of the rupture qds = self._rup.getQuadrilaterals() nq = len(qds) top_lat = np.array([[]]) top_lon = np.array([[]]) top_dep = np.array([[]]) for j in range(0, nq): top_lat = np.append(top_lat, qds[j][0].latitude) top_lat = np.append(top_lat, qds[j][1].latitude) top_lon = np.append(top_lon, qds[j][0].longitude) top_lon = np.append(top_lon, qds[j][1].longitude) top_dep = np.append(top_dep, qds[j][0].depth) top_dep = np.append(top_dep, qds[j][1].depth) top_x, top_y = proj(top_lon, top_lat) Lrup_max = 400 slat = self._lat slon = self._lon LD = np.zeros_like(slat) Ls = np.zeros_like(slat) ni, nj = LD.shape for i in range(ni): for j in range(nj): # ------------------------------------------------------------- # Compute Ls # ------------------------------------------------------------- # Convert to local orthographic site_x, site_y = proj(slon[i, j], slat[i, j]) # Shift so center is at epicenter site_x2 = site_x - epi_x site_y2 = site_y - epi_y top_x2 = top_x - epi_x top_y2 = top_y - epi_y # Angle to rotate to put site on x-axis alpha = np.arctan2(site_y2, site_x2) axis = [0, 0, 1] rmat = _rotation_matrix(axis, -alpha) llr = [None] * len(top_lat) # Apply rotation to each point on trace for k in range(len(top_lat)): llr[k] = np.dot(rmat, [top_x2[k], top_y2[k], 0]) site3 = np.dot(rmat, [site_x2, site_y2, 0]) Li = np.min([np.max([a[0] for a in llr]), site3[0]]) # ------------------------------------------------------------- # Compute LD and save results into matrices # ------------------------------------------------------------- Lrup = np.sqrt(Li * Li + self._Wrup * self._Wrup) LD[i, j] = np.log(Lrup) / np.log(Lrup_max) Ls[i, j] = Li self._LD = LD self._Ls = Ls
def test_ss3(): magnitude = 7.2 dip = np.array([90]) rake = 180.0 width = np.array([15]) rupx = np.array([0, 0]) rupy = np.array([0, 80]) zp = np.array([0]) epix = np.array([0]) epiy = np.array([0.2 * rupy[1]]) # Convert to lat/lon proj = OrthographicProjection(-122, -120, 39, 37) tlon, tlat = proj(rupx, rupy, reverse=True) epilon, epilat = proj(epix, epiy, reverse=True) # Origin: origin = Origin({'lat': epilat[0], 'lon': epilon[0], 'depth': 10, 'mag': magnitude, 'id': 'ss3', 'netid': 'us', 'network': '', 'locstring': '', 'rake': rake, 'time': HistoricTime.utcfromtimestamp(int(time.time()))}) rup = QuadRupture.fromTrace( np.array([tlon[0]]), np.array([tlat[0]]), np.array([tlon[1]]), np.array([tlat[1]]), zp, width, dip, origin, reference='ss3') x = np.linspace(-60, 60, 21) y = np.linspace(-60, 138, 34) site_x, site_y = np.meshgrid(x, y) slon, slat = proj(site_x, site_y, reverse=True) deps = np.zeros_like(slon) test1 = Bayless2013(origin, rup, slat, slon, deps, T=1.0) # Test fd fd = test1.getFd() fd_test = np.array( [[0.00000000e+00, 0.00000000e+00, 2.14620746e-03, 6.47899336e-03, 1.23119791e-02, 1.91676140e-02, 2.64009788e-02, 3.32427846e-02, 3.88863288e-02, 4.26104002e-02, 4.39120296e-02, 4.26104002e-02, 3.88863288e-02, 3.32427846e-02, 2.64009788e-02, 1.91676140e-02, 1.23119791e-02, 6.47899336e-03, 2.14620746e-03, 0.00000000e+00, 0.00000000e+00], [0.00000000e+00, 8.57780996e-04, 3.99405791e-03, 9.31948105e-03, 1.65406113e-02, 2.51316805e-02, 3.43205435e-02, 4.31274592e-02, 5.04747209e-02, 5.53634169e-02, 5.70796092e-02, 5.53634169e-02, 5.04747209e-02, 4.31274592e-02, 3.43205435e-02, 2.51316805e-02, 1.65406113e-02, 9.31948105e-03, 3.99405791e-03, 8.57780996e-04, 0.00000000e+00], [-7.32594549e-04, 1.80425497e-04, 3.76908220e-03, 1.00175179e-02, 1.86854835e-02, 2.92291145e-02, 4.07487277e-02, 5.20057177e-02, 6.15509770e-02, 6.79776087e-02, 7.02477931e-02, 6.79776087e-02, 6.15509770e-02, 5.20057177e-02, 4.07487277e-02, 2.92291145e-02, 1.86854835e-02, 1.00175179e-02, 3.76908220e-03, 1.80425497e-04, -7.32594549e-04], [-3.29238561e-03, -2.60643191e-03, 1.16635260e-03, 8.15185259e-03, 1.82290773e-02, 3.08983182e-02, 4.51608038e-02, 5.94769126e-02, 7.18919113e-02, 8.03888307e-02, 8.34165399e-02, 8.03888307e-02, 7.18919113e-02, 5.94769126e-02, 4.51608038e-02, 3.08983182e-02, 1.82290773e-02, 8.15185259e-03, 1.16635260e-03, -2.60643191e-03, -3.29238561e-03], [-7.68543266e-03, -7.63179286e-03, -4.08866637e-03, 3.27605236e-03, 1.45558215e-02, 2.94068040e-02, 4.68176355e-02, 6.49397159e-02, 7.72066272e-02, 8.50445368e-02, 8.77974692e-02, 8.50445368e-02, 7.72066272e-02, 6.49397159e-02, 4.68176355e-02, 2.94068040e-02, 1.45558215e-02, 3.27605236e-03, -4.08866637e-03, -7.63179286e-03, -7.68543266e-03], [-1.38078234e-02, -1.49011067e-02, -1.21731364e-02, -5.02168047e-03, 6.98177526e-03, 2.38268531e-02, 4.30419205e-02, 6.00041964e-02, 7.44541603e-02, 8.42939552e-02, 8.77989590e-02, 8.42939552e-02, 7.44541603e-02, 6.00041964e-02, 4.30419205e-02, 2.38268531e-02, 6.98177526e-03, -5.02168047e-03, -1.21731364e-02, -1.49011067e-02, -1.38078234e-02], [-2.13780396e-02, -2.42165379e-02, -2.30613142e-02, -1.70011475e-02, -5.15036128e-03, 1.25885635e-02, 3.24536739e-02, 5.25619351e-02, 7.05100243e-02, 8.31900906e-02, 8.78003567e-02, 8.31900906e-02, 7.05100243e-02, 5.25619351e-02, 3.24536739e-02, 1.25885635e-02, -5.15036128e-03, -1.70011475e-02, -2.30613142e-02, -2.42165379e-02, -2.13780396e-02], [-2.98882710e-02, -3.50862342e-02, -3.63793490e-02, -3.25716319e-02, -2.22546618e-02, -3.59274163e-03, 1.83064517e-02, 4.20112440e-02, 6.46115966e-02, 8.14746164e-02, 8.78016623e-02, 8.14746164e-02, 6.46115966e-02, 4.20112440e-02, 1.83064517e-02, -3.59274163e-03, -2.22546618e-02, -3.25716319e-02, -3.63793490e-02, -3.50862342e-02, -2.98882710e-02], [-3.85810679e-02, -4.66488633e-02, -5.12430987e-02, -5.10089462e-02, -4.20856023e-02, -2.36905234e-02, -6.33876287e-04, 2.66765430e-02, 5.53289928e-02, 7.86066125e-02, 8.78028757e-02, 7.86066125e-02, 5.53289928e-02, 2.66765430e-02, -6.33876287e-04, -2.36905234e-02, -4.20856023e-02, -5.10089462e-02, -5.12430987e-02, -4.66488633e-02, -3.85810679e-02], [-4.64803335e-02, -5.76615888e-02, -6.61458422e-02, -7.06512643e-02, -6.38427394e-02, -4.77258398e-02, -2.55483969e-02, 4.05840724e-03, 3.98470070e-02, 7.33053399e-02, 8.78039969e-02, 7.33053399e-02, 3.98470070e-02, 4.05840724e-03, -2.55483969e-02, -4.77258398e-02, -6.38427394e-02, -7.06512643e-02, -6.61458422e-02, -5.76615888e-02, -4.64803335e-02], [-5.25038299e-02, -6.66129442e-02, -7.90147081e-02, -8.87629178e-02, -8.59653118e-02, -7.42828398e-02, -5.64316505e-02, -2.87083225e-02, 1.25945312e-02, 6.19971667e-02, 8.78050260e-02, 6.19971667e-02, 1.25945312e-02, -2.87083225e-02, -5.64316505e-02, -7.42828398e-02, -8.59653118e-02, -8.87629178e-02, -7.90147081e-02, -6.66129442e-02, -5.25038299e-02], [-5.69779111e-02, -7.36791817e-02, -8.97495345e-02, -1.04799583e-01, -1.07737239e-01, -1.02875880e-01, -9.46568471e-02, -7.95630162e-02, -4.96285112e-02, 6.59954795e-03, 5.25569882e-02, 6.59954795e-03, -4.96285112e-02, -7.95630162e-02, -9.46568471e-02, -1.02875880e-01, -1.07737239e-01, -1.04799583e-01, -8.97495345e-02, -7.36791817e-02, -5.69779111e-02], [-5.90357675e-02, -7.69727119e-02, -9.48442826e-02, -1.12607620e-01, -1.18744885e-01, -1.18201834e-01, -1.17217017e-01, -1.15152899e-01, -1.09694433e-01, -8.82341332e-02, -1.61624035e-02, -8.82341332e-02, -1.09694433e-01, -1.15152899e-01, -1.17217017e-01, -1.18201834e-01, -1.18744885e-01, -1.12607620e-01, -9.48442826e-02, -7.69727119e-02, -5.90357675e-02], [-5.92189452e-02, -7.72680305e-02, -9.53051857e-02, -1.13322519e-01, -1.19770917e-01, -1.19670660e-01, -1.19486798e-01, -1.19092639e-01, -1.17989113e-01, -1.12555820e-01, -4.50009776e-02, -1.12555820e-01, -1.17989113e-01, -1.19092639e-01, -1.19486798e-01, -1.19670660e-01, -1.19770917e-01, -1.13322519e-01, -9.53051857e-02, -7.72680305e-02, -5.92189452e-02], [-5.79249958e-02, -7.51927112e-02, -9.20842554e-02, -1.08361430e-01, -1.12722790e-01, -1.09732675e-01, -1.04531672e-01, -9.44729544e-02, -7.23277773e-02, -2.05699911e-02, 3.58249631e-02, -2.05699911e-02, -7.23277773e-02, -9.44729544e-02, -1.04531672e-01, -1.09732675e-01, -1.12722790e-01, -1.08361430e-01, -9.20842554e-02, -7.51927112e-02, -5.79249958e-02], [-5.42527703e-02, -6.93641123e-02, -8.31684773e-02, -9.49114165e-02, -9.41989454e-02, -8.48645354e-02, -7.00894708e-02, -4.58286259e-02, -6.37563061e-03, 4.68887998e-02, 7.77968419e-02, 4.68887998e-02, -6.37563061e-03, -4.58286259e-02, -7.00894708e-02, -8.48645354e-02, -9.41989454e-02, -9.49114165e-02, -8.31684773e-02, -6.93641123e-02, -5.42527703e-02], [-4.82490057e-02, -5.99997941e-02, -6.91786120e-02, -7.44891242e-02, -6.73705808e-02, -5.13001284e-02, -2.84188057e-02, 3.60143816e-03, 4.47470123e-02, 8.58663851e-02, 1.04548354e-01, 8.58663851e-02, 4.47470123e-02, 3.60143816e-03, -2.84188057e-02, -5.13001284e-02, -6.73705808e-02, -7.44891242e-02, -6.91786120e-02, -5.99997941e-02, -4.82490057e-02], [-4.03203010e-02, -4.79063206e-02, -5.16352259e-02, -4.98707253e-02, -3.67295509e-02, -1.57342058e-02, 1.13668830e-02, 4.46551184e-02, 8.10450840e-02, 1.11780747e-01, 1.24226598e-01, 1.11780747e-01, 8.10450840e-02, 4.46551184e-02, 1.13668830e-02, -1.57342058e-02, -3.67295509e-02, -4.98707253e-02, -5.16352259e-02, -4.79063206e-02, -4.03203010e-02], [-3.10250239e-02, -3.40796094e-02, -3.22089254e-02, -2.37094100e-02, -5.85463114e-03, 1.77402761e-02, 4.57786845e-02, 7.69637052e-02, 1.07537652e-01, 1.30906328e-01, 1.39800436e-01, 1.30906328e-01, 1.07537652e-01, 7.69637052e-02, 4.57786845e-02, 1.77402761e-02, -5.85463114e-03, -2.37094100e-02, -3.22089254e-02, -3.40796094e-02, -3.10250239e-02], [-2.09301700e-02, -1.94475962e-02, -1.22970199e-02, 2.07296407e-03, 2.31516868e-02, 4.74574033e-02, 7.44743481e-02, 1.02380049e-01, 1.27776301e-01, 1.46003379e-01, 1.52690015e-01, 1.46003379e-01, 1.27776301e-01, 1.02380049e-01, 7.44743481e-02, 4.74574033e-02, 2.31516868e-02, 2.07296407e-03, -1.22970199e-02, -1.94475962e-02, -2.09301700e-02], [-1.05257992e-02, -4.74329696e-03, 7.12107274e-03, 2.63431361e-02, 4.93709790e-02, 7.31527220e-02, 9.82233938e-02, 1.22728059e-01, 1.43894925e-01, 1.58465026e-01, 1.63685984e-01, 1.58465026e-01, 1.43894925e-01, 1.22728059e-01, 9.82233938e-02, 7.31527220e-02, 4.93709790e-02, 2.63431361e-02, 7.12107274e-03, -4.74329696e-03, -1.05257992e-02], [-1.89098657e-04, 9.52392382e-03, 2.54577716e-02, 4.85730869e-02, 7.26048516e-02, 9.51726659e-02, 1.17988523e-01, 1.39380421e-01, 1.57176612e-01, 1.69076915e-01, 1.73274075e-01, 1.69076915e-01, 1.57176612e-01, 1.39380421e-01, 1.17988523e-01, 9.51726659e-02, 7.26048516e-02, 4.85730869e-02, 2.54577716e-02, 9.52392382e-03, -1.89098657e-04], [9.81732797e-03, 2.30419581e-02, 4.24234701e-02, 6.86213308e-02, 9.30164618e-02, 1.14050063e-01, 1.34620894e-01, 1.53304069e-01, 1.68420867e-01, 1.78321253e-01, 1.81774183e-01, 1.78321253e-01, 1.68420867e-01, 1.53304069e-01, 1.34620894e-01, 1.14050063e-01, 9.30164618e-02, 6.86213308e-02, 4.24234701e-02, 2.30419581e-02, 9.81732797e-03], [1.93290725e-02, 3.56493099e-02, 5.79271157e-02, 8.65611122e-02, 1.10914315e-01, 1.30317702e-01, 1.48798006e-01, 1.65173224e-01, 1.78147031e-01, 1.86513895e-01, 1.89408199e-01, 1.86513895e-01, 1.78147031e-01, 1.65173224e-01, 1.48798006e-01, 1.30317702e-01, 1.10914315e-01, 8.65611122e-02, 5.79271157e-02, 3.56493099e-02, 1.93290725e-02], [2.68168937e-02, 4.52356810e-02, 6.92261217e-02, 9.89630241e-02, 1.23093435e-01, 1.40640067e-01, 1.56998943e-01, 1.71215219e-01, 1.82297185e-01, 1.89360704e-01, 1.91789146e-01, 1.89360704e-01, 1.82297185e-01, 1.71215219e-01, 1.56998943e-01, 1.40640067e-01, 1.23093435e-01, 9.89630241e-02, 6.92261217e-02, 4.52356810e-02, 2.68168937e-02], [3.19403269e-02, 5.15051953e-02, 7.61032066e-02, 1.05705197e-01, 1.31722206e-01, 1.47466588e-01, 1.61892450e-01, 1.74235616e-01, 1.83735386e-01, 1.89735533e-01, 1.91788616e-01, 1.89735533e-01, 1.83735386e-01, 1.74235616e-01, 1.61892450e-01, 1.47466588e-01, 1.31722206e-01, 1.05705197e-01, 7.61032066e-02, 5.15051953e-02, 3.19403269e-02], [3.48604070e-02, 5.49292382e-02, 7.94274234e-02, 1.08149011e-01, 1.38923419e-01, 1.53070440e-01, 1.65849067e-01, 1.76646162e-01, 1.84871647e-01, 1.90029617e-01, 1.91787948e-01, 1.90029617e-01, 1.84871647e-01, 1.76646162e-01, 1.65849067e-01, 1.53070440e-01, 1.38923419e-01, 1.08149011e-01, 7.94274234e-02, 5.49292382e-02, 3.48604070e-02], [3.53402022e-02, 5.53653759e-02, 7.91965502e-02, 1.06486934e-01, 1.36563003e-01, 1.57713955e-01, 1.69087164e-01, 1.78598269e-01, 1.85784340e-01, 1.90264452e-01, 1.91787141e-01, 1.90264452e-01, 1.85784340e-01, 1.78598269e-01, 1.69087164e-01, 1.57713955e-01, 1.36563003e-01, 1.06486934e-01, 7.91965502e-02, 5.53653759e-02, 3.53402022e-02], [3.32889822e-02, 5.28319225e-02, 7.55769079e-02, 1.01077605e-01, 1.28592068e-01, 1.57023616e-01, 1.71766715e-01, 1.80199729e-01, 1.86528091e-01, 1.90454829e-01, 1.91786196e-01, 1.90454829e-01, 1.86528091e-01, 1.80199729e-01, 1.71766715e-01, 1.57023616e-01, 1.28592068e-01, 1.01077605e-01, 7.55769079e-02, 5.28319225e-02, 3.32889822e-02], [2.87295370e-02, 4.74613283e-02, 6.88388861e-02, 9.23568989e-02, 1.17254645e-01, 1.42483223e-01, 1.66695764e-01, 1.81528776e-01, 1.87141877e-01, 1.90611190e-01, 1.91785112e-01, 1.90611190e-01, 1.87141877e-01, 1.81528776e-01, 1.66695764e-01, 1.42483223e-01, 1.17254645e-01, 9.23568989e-02, 6.88388861e-02, 4.74613283e-02, 2.87295370e-02], [2.17650266e-02, 3.94568191e-02, 5.93023344e-02, 8.07720575e-02, 1.03124482e-01, 1.25394282e-01, 1.46405870e-01, 1.64828303e-01, 1.79288925e-01, 1.88553222e-01, 1.91747252e-01, 1.88553222e-01, 1.79288925e-01, 1.64828303e-01, 1.46405870e-01, 1.25394282e-01, 1.03124482e-01, 8.07720575e-02, 5.93023344e-02, 3.94568191e-02, 2.17650266e-02], [1.25495284e-02, 2.90572166e-02, 4.72972116e-02, 6.67423656e-02, 8.66951873e-02, 1.06290296e-01, 1.24520131e-01, 1.40293247e-01, 1.52531693e-01, 1.60303860e-01, 1.62970689e-01, 1.60303860e-01, 1.52531693e-01, 1.40293247e-01, 1.24520131e-01, 1.06290296e-01, 8.66951873e-02, 6.67423656e-02, 4.72972116e-02, 2.90572166e-02, 1.25495284e-02], [1.26441934e-03, 1.65114811e-02, 3.31390978e-02, 5.06407706e-02, 6.83765492e-02, 8.55839448e-02, 1.01408074e-01, 1.14955639e-01, 1.25373662e-01, 1.31946425e-01, 1.34193829e-01, 1.31946425e-01, 1.25373662e-01, 1.14955639e-01, 1.01408074e-01, 8.55839448e-02, 6.83765492e-02, 5.06407706e-02, 3.31390978e-02, 1.65114811e-02, 1.26441934e-03], [0.00000000e+00, 2.06213867e-03, 1.71162845e-02, 3.27888240e-02, 4.85026462e-02, 6.35932476e-02, 7.73387997e-02, 8.90069217e-02, 9.79166934e-02, 1.03509489e-01, 1.05416736e-01, 1.03509489e-01, 9.79166934e-02, 8.90069217e-02, 7.73387997e-02, 6.35932476e-02, 4.85026462e-02, 3.27888240e-02, 1.71162845e-02, 2.06213867e-03, 0.00000000e+00]] ) np.testing.assert_allclose(fd, fd_test, rtol=1e-4)
def _get_quad_slip_ds_ss(q, rake, cp, p): """ Compute the DIP SLIP and STRIKE SLIP components of the unit slip vector in ECEF coords for a quad and rake angle. :param q: A quadrilateral. :param rake: Direction of motion of the hanging wall relative to the foot wall, as measured by the angle (deg) from the strike vector. :param cp: A 3x(n sub rupture) array giving center points of each sub rupture in ECEF coords. :param p: A 3x(n sub rupture) array giving the unit vectors of the propagation vector on each sub rupture in ECEF coords. :returns: List of dip slip and strike slip components (each is a matrix) of the unit slip vector in ECEF space. """ # Get quad vertices, strike, dip P0, P1 = q[0:2] strike = P0.azimuth(P1) dip = utils.get_quad_dip(q) # Slip unit vectors in 'local' (i.e., z-up, x-east) coordinates d1_local = utils.get_local_unit_slip_vector_DS(strike, dip, rake) s1_local = utils.get_local_unit_slip_vector_SS(strike, dip, rake) # Convert to a column array d1_col = np.array([[d1_local.x], [d1_local.y], [d1_local.z]]) s1_col = np.array([[s1_local.x], [s1_local.y], [s1_local.z]]) # Define 'local' coordinate system qlats = [a.latitude for a in q] qlons = [a.longitude for a in q] proj = OrthographicProjection(np.min(qlons), np.max(qlons), np.min(qlats), np.max(qlats)) # Convert p and cp to geographic coords p0lat, p0lon, p0z = ecef2latlon(cp[0, ], cp[1, ], cp[2, ]) p1lat, p1lon, p1z = ecef2latlon(cp[0, ] + p[0, ], cp[1, ] + p[1, ], cp[2, ] + p[2, ]) # Convert p to 'local' coords p0x, p0y = proj(p0lon, p0lat) p1x, p1y = proj(p1lon, p1lat) px = p1x - p0x py = p1y - p0y pz = p1z - p0z # Apply sign changes in 'local' coords s1mat = np.array([[np.abs(s1_col[0]) * np.sign(px)], [np.abs(s1_col[1]) * np.sign(py)], [np.abs(s1_col[2]) * np.sign(pz)]]) # [np.abs(s1_col[2])*np.ones_like(pz)]]) dipsign = -np.sign(np.sin(np.radians(rake))) d1mat = np.array([[d1_col[0] * np.ones_like(px) * dipsign], [d1_col[1] * np.ones_like(py) * dipsign], [d1_col[2] * np.ones_like(pz) * dipsign]]) # Need to track 'origin' s0 = np.array([[0], [0], [0]]) # Convert from 'local' to geographic coords s1_ll = proj(s1mat[0, ], s1mat[1, ], reverse=True) d1_ll = proj(d1mat[0, ], d1mat[1, ], reverse=True) s0_ll = proj(s0[0], s0[1], reverse=True) # And then back to ECEF: s1_ecef = latlon2ecef(s1_ll[1], s1_ll[0], s1mat[2, ]) d1_ecef = latlon2ecef(d1_ll[1], d1_ll[0], d1mat[2, ]) s0_ecef = latlon2ecef(s0_ll[1], s0_ll[0], s0[2]) s00 = s0_ecef[0].reshape(-1) s01 = s0_ecef[1].reshape(-1) s02 = s0_ecef[2].reshape(-1) d_mat = np.array([ d1_ecef[0].reshape(-1) - s00, d1_ecef[1].reshape(-1) - s01, d1_ecef[2].reshape(-1) - s02 ]) s_mat = np.array([ s1_ecef[0].reshape(-1) - s00, s1_ecef[1].reshape(-1) - s01, s1_ecef[2].reshape(-1) - s02 ]) return d_mat, s_mat
def test_san_fernando(): # This is a challenging rupture due to overlapping and discordant # segments, as brought up by Graeme Weatherill. Our initial # implementation put the origin on the wrong side of the rupture. x0 = np.array([7.1845, 7.8693]) y0 = np.array([-10.3793, -16.2096]) z0 = np.array([3.0000, 0.0000]) x1 = np.array([-7.8506, -7.5856]) y1 = np.array([-4.9073, -12.0682]) z1 = np.array([3.0000, 0.0000]) x2 = np.array([-4.6129, -5.5149]) y2 = np.array([3.9887, -4.3408]) z2 = np.array([16.0300, 8.0000]) x3 = np.array([10.4222, 9.9400]) y3 = np.array([-1.4833, -8.4823]) z3 = np.array([16.0300, 8.0000]) epilat = 34.44000 epilon = -118.41000 proj = OrthographicProjection(epilon - 1, epilon + 1, epilat + 1, epilat - 1) lon0, lat0 = proj(x0, y0, reverse=True) lon1, lat1 = proj(x1, y1, reverse=True) lon2, lat2 = proj(x2, y2, reverse=True) lon3, lat3 = proj(x3, y3, reverse=True) # Rupture requires an origin even when not used: origin = Origin({ 'id': 'test', 'lat': 0, 'lon': 0, 'depth': 5.0, 'mag': 7.0, 'netid': '', 'network': '', 'locstring': '', 'time': HistoricTime.utcfromtimestamp(int(time.time())) }) rup = QuadRupture.fromVertices(lon0, lat0, z0, lon1, lat1, z1, lon2, lat2, z2, lon3, lat3, z3, origin) # Make a origin object; most of the 'event' values don't matter event = { 'lat': 0, 'lon': 0, 'depth': 0, 'mag': 6.61, 'id': '', 'locstring': '', 'type': 'ALL', 'netid': '', 'network': '', 'time': HistoricTime.utcfromtimestamp(int(time.time())) } origin = Origin(event) # Grid of sites buf = 0.25 lat = np.linspace(np.nanmin(rup._lat) - buf, np.nanmax(rup._lat) + buf, 10) lon = np.linspace(np.nanmin(rup._lon) - buf, np.nanmax(rup._lon) + buf, 10) lons, lats = np.meshgrid(lon, lat) dep = np.zeros_like(lons) x, y = proj(lon, lat) rupx, rupy = proj(rup._lon[~np.isnan(rup._lon)], rup._lat[~np.isnan(rup._lat)]) # Calculate U and T dtypes = ['U', 'T'] dists = get_distance(dtypes, lats, lons, dep, rup) targetU = np.array( [[ 29.37395812, 22.56039569, 15.74545461, 8.92543078, 2.09723735, -4.73938823, -11.58093887, -18.42177264, -25.25743913, -32.08635501 ], [ 31.84149137, 25.03129417, 18.22007124, 11.40292429, 4.57583886, -2.26009972, -9.09790123, -15.92911065, -22.75071243, -29.56450963 ], [ 34.30623138, 27.49382948, 20.67774678, 13.85111535, 7.0115472, 0.16942111, -6.65327488, -13.45181115, -20.24352643, -27.03530618 ], [ 36.78170249, 29.96380633, 23.1270492, 16.23906653, 9.32934682, 2.41729624, -4.2732657, -10.94940844, -17.703852, -24.4792072 ], [ 39.29233805, 32.49155866, 25.68380903, 18.73823089, 12.08780156, 5.99219619, -1.38387344, -8.28331275, -15.08759643, -21.87909368 ], [ 41.84662959, 35.09745097, 28.42432401, 21.98993679, 15.2994003, 8.38037254, 1.3900846, -5.5601922, -12.4250749, -19.24690137 ], [ 44.41552101, 37.69652131, 31.0257236, 24.38573309, 17.67059825, 10.84688716, 3.96604399, -2.920931, -9.78152208, -16.6132751 ], [ 46.97201328, 40.2558351, 33.55821495, 26.85923974, 20.12416451, 13.33640001, 6.50905851, -0.33349597, -7.17138975, -13.99568321 ], [ 49.51154107, 42.79053584, 36.07536907, 29.35382731, 22.61099757, 15.83894006, 9.04135415, 2.22928601, -4.58574545, -11.3959888 ], [ 52.03832734, 45.31289877, 38.58842009, 31.85764151, 25.11309728, 18.35066231, 11.57145669, 4.78070229, -2.01505508, -8.81029694 ]]) np.testing.assert_allclose(dists['U'], targetU, atol=0.01) targetT = np.array( [[ -40.32654805, -38.14066537, -35.95781299, -33.79265063, -31.65892948, -29.56075203, -27.48748112, -25.41823592, -23.33452174, -21.22822801 ], [ -32.28894353, -30.06603457, -27.83163648, -25.61482279, -23.45367121, -21.36959238, -19.34738882, -17.33510593, -15.28949735, -13.20224592 ], [ -24.30254163, -22.03532096, -19.70590091, -17.35907062, -15.10840929, -13.02682541, -11.13554925, -9.25705749, -7.26675455, -5.19396824 ], [ -16.41306482, -14.1418547, -11.68888578, -8.9318195, -6.39939727, -4.10984325, -2.85061088, -1.29211846, 0.68929792, 2.78115216 ], [ -8.63784529, -6.5089946, -4.32108309, -1.44275161, -0.05102145, -0.20890633, 3.92700516, 6.36977183, 8.55572399, 10.72128633 ], [ -0.88135778, 1.06766314, 2.77955566, 3.8241835, 5.99212478, 8.76823285, 11.54715599, 14.0961506, 16.4200502, 18.65346494 ], [ 6.98140207, 8.91888936, 10.77724993, 12.6499521, 14.79454638, 17.18482779, 19.63520498, 22.03525644, 24.35152986, 26.60592498 ], [ 14.95635952, 16.95134069, 18.94768299, 20.99811237, 23.15975573, 25.42700742, 27.74302905, 30.0547134, 32.33583361, 34.58421221 ], [ 22.9921068, 25.0353212, 27.09829391, 29.20364631, 31.3678744, 33.58684524, 35.8383652, 38.09736043, 40.34713771, 42.58152772 ], [ 31.05186177, 33.1252095, 35.21960344, 37.34488267, 39.50633206, 41.70076344, 43.91762786, 46.14415669, 48.37021739, 50.59029205 ]]) np.testing.assert_allclose(dists['T'], targetT, atol=0.01) # new method: ddict = _computeGC2(rup, lons, lats, dep) np.testing.assert_allclose(ddict['T'], targetT, atol=0.01) np.testing.assert_allclose(ddict['U'], targetU, atol=0.01)