def getPhaseInfo(depth, distance, phaseList, plotFlag): ''' Routine to calculate phase arrivals example: getPhaseInfo(600,60,"P",False) ''' from obspy.taup import TauPyModel #specify earth model model = TauPyModel(model="iasp91") # the source - receiver distance in degrees #distance = 67.62 #distance = 45 #distance = 75.73 # the source depth in km #depth = 500 #depth = 37.5 # list of phases you are interested in #phaseList = ["P", "S", "PKiKP"] arrivals = model.get_travel_times(source_depth_in_km=depth, distance_in_degree=distance, phase_list=phaseList) # to get the travel time for a phase... arr = arrivals[0] pTime = arr.time print "The pwave arrives at: " + str(pTime) # if you want to plot the raypaths... this is totally cool! if plotFlag: arrivals = model.get_ray_paths(source_depth_in_km=depth, distance_in_degree=distance) arrivals.plot()
def test_plot_window_figure(tmpdir): reset_matplotlib() obs_tr = read(obsfile).select(channel="*R")[0] syn_tr = read(synfile).select(channel="*R")[0] config_file = os.path.join(DATA_DIR, "window", "27_60.BHZ.config.yaml") config = wio.load_window_config_yaml(config_file) cat = read_events(quakeml) inv = read_inventory(staxml) from obspy.taup import TauPyModel model = TauPyModel(model='iasp91') arrivals = model.get_ray_paths(500, 140, phase_list=['Pdiff', 'SS']) print(arrivals) ws = WindowSelector(obs_tr, syn_tr, config, event=cat, station=inv) windows = ws.select_windows() assert len(windows) > 0 win.plot_window_figure(str(tmpdir), obs_tr.id, ws, True, figure_format="png")
def main(): # MAIN PROGRAM BODY OT,stlat,stlon,evlat,evlon,depth = getoptions() origin_time = UTCDateTime(str(OT)) result = client.distaz(stalat=stlat, stalon=stlon, evtlat=evlat,evtlon=evlon) model = TauPyModel(model="AK135") arrivals = model.get_travel_times(source_depth_in_km=depth,distance_in_degree=result['distance'])#, #phase_list = ['P','PcP','PP','PKiKP','S','SS','ScS','SKiKS']) print "Distance = {0:.1f} arc degrees.".format(result['distance']) print "{0:.0f} Km distance.".format(result['distance']*111.25) print "{0:.0f} deg back Azimuth.".format(result['backazimuth']) table = client.traveltime(evloc=(evlat,evlon),staloc=[(stlat,stlon)],evdepth=depth) print "Selected phase list:\n" print (table.decode()) # Print the phases, travel time and forecasted arrival time. phasename = [] phasetime = [] arrivaltime = [] print "For origin time {}, ".format(origin_time) print "TauP big list of phases and arrival times:" for i in range(0,len(arrivals)): phasename.append(arrivals[i].name) phasetime.append(arrivals[i].time) at = origin_time+(arrivals[i].time) arrivaltime.append(at) print 'Phase: {0} \t arrives in {1:.2f} sec. at time {2:02.0f}:{3:02.0f}:{4:02.0f}.{5:02.0f}' \ .format(arrivals[i].name,arrivals[i].time,at.hour,at.minute,at.second,at.microsecond/10000) arrivalpaths = model.get_ray_paths(source_depth_in_km=depth,distance_in_degree=result['distance'])#,\ # phase_list = ['P','PcP','PP','PKiKP','S','SS','ScS','SKiKS']) arrivalpaths.plot()
def test_single_path_ak135(self): """ Test the raypath for a single phase. This time for model AK135. """ filename = os.path.join( DATA, "taup_path_-o_stdout_-h_10_-ph_P_-deg_35_-mod_ak135") expected = np.genfromtxt(filename, comments='>') m = TauPyModel(model="ak135") arrivals = m.get_ray_paths(source_depth_in_km=10.0, distance_in_degree=35.0, phase_list=["P"]) self.assertEqual(len(arrivals), 1) # Interpolate both paths to 100 samples and make sure they are # approximately equal. sample_points = np.linspace(0, 35, 100) interpolated_expected = np.interp( sample_points, expected[:, 0], expected[:, 1]) interpolated_actual = np.interp( sample_points, np.round(np.degrees(arrivals[0].path['dist']), 2), np.round(6371 - arrivals[0].path['depth'], 2)) self.assertTrue(np.allclose(interpolated_actual, interpolated_expected, rtol=1E-4, atol=0))
def test_regional_models(self): """ Tests small regional models as this used to not work. Note: It looks like too much work to get a 1-layer model working. The problem is first in finding the moho, and second in coarsely- sampling slowness. Also, why bother. """ model_names = ["2_layer_model", "5_layer_model"] expected_results = [ [("p", 18.143), ("Pn", 19.202), ("PcP", 19.884), ("sP", 22.054), ("ScP", 23.029), ("PcS", 26.410), ("s", 31.509), ("Sn", 33.395), ("ScS", 34.533)], [("Pn", 17.358), ("P", 17.666), ("p", 17.804), ("P", 17.869), ("PcP", 18.039), ("ScP", 19.988), ("sP", 22.640), ("sP", 22.716), ("sP", 22.992), ("PcS", 23.051), ("sP", 24.039), ("sP", 24.042), ("Sn", 30.029), ("S", 30.563), ("s", 30.801), ("S", 30.913), ("ScS", 31.208)]] for model_name, expects in zip(model_names, expected_results): with TemporaryWorkingDirectory(): folder = os.path.abspath(os.curdir) build_taup_model( filename=os.path.join(DATA, os.path.pardir, model_name + ".tvel"), output_folder=folder, verbose=False) model = TauPyModel(os.path.join(folder, model_name + ".npz")) arrvials = model.get_ray_paths(source_depth_in_km=18.0, distance_in_degree=1.0) self.assertEqual(len(arrvials), len(expects)) for arrival, expect in zip(arrvials, expects): self.assertEqual(arrival.name, expect[0]) self.assertAlmostEqual(arrival.time, expect[1], 3)
def test_arrivals_class(self): """ Tests list operations on the Arrivals class. See #1518. """ model = TauPyModel(model='iasp91') arrivals = model.get_ray_paths(source_depth_in_km=0, distance_in_degree=1, phase_list=['Pn', 'PmP']) self.assertEqual(len(arrivals), 2) # test copy self.assertTrue(isinstance(arrivals.copy(), Arrivals)) # test sum self.assertTrue(isinstance(arrivals + arrivals, Arrivals)) self.assertTrue(isinstance(arrivals + arrivals[0], Arrivals)) # test multiplying self.assertTrue(isinstance(arrivals * 2, Arrivals)) arrivals *= 3 self.assertEqual(len(arrivals), 6) self.assertTrue(isinstance(arrivals, Arrivals)) # test slicing self.assertTrue(isinstance(arrivals[2:5], Arrivals)) # test appending arrivals.append(arrivals[0]) self.assertEqual(len(arrivals), 7) self.assertTrue(isinstance(arrivals, Arrivals)) # test assignment arrivals[0] = arrivals[-1] self.assertTrue(isinstance(arrivals, Arrivals)) arrivals[2:5] = arrivals[1:4] self.assertTrue(isinstance(arrivals, Arrivals)) # test assignment with wrong type with self.assertRaises(TypeError): arrivals[0] = 10. with self.assertRaises(TypeError): arrivals[2:5] = [0, 1, 2] with self.assertRaises(TypeError): arrivals.append(arrivals) # test add and mul with wrong type with self.assertRaises(TypeError): arrivals + [ 2, ] with self.assertRaises(TypeError): arrivals += [ 2, ] with self.assertRaises(TypeError): arrivals * [ 2, ] with self.assertRaises(TypeError): arrivals *= [ 2, ]
def test_ppointvsobspytaup_S2P(self): slowness = 12.33 evdep = 12.4 evdist = 67.7 pp1 = self.model.ppoint_distance(200, slowness, phase='P') model = TauPyModel(model='iasp91') arrivals = model.get_ray_paths(evdep, evdist, ('S250p', )) arrival = arrivals[0] index = np.searchsorted(arrival.path['depth'][::-1], 200) pdist = arrival.path['dist'] pp2 = degrees2kilometers((pdist[-1] - pdist[-index - 1]) * 180 / np.pi) self.assertLess(abs(pp1 - pp2) / pp2, 0.2)
def PsRayp(layers, dist, dep): model = TauPyModel(model="iasp91") ph_list = makepheaselist(layers) arrs = model.get_ray_paths(dist, dep, ph_list) arr_num = len(arrs) print(arr_num, len(ph_list)) rayp_list = np.zeros([arr_num, 2]) for i in range(arr_num): rayp_list[i][0] = srad2skm(arrs[i].ray_param) rayp_list[i][1] = int(arrs[i].name.strip('Ps')) rayp_list.sort(axis=0) return(rayp_list)
def test_ppointvsobspytaup_S2P(self): slowness = 12.33 evdep = 12.4 evdist = 67.7 pp1 = self.model.ppoint_distance(200, slowness, phase="P") model = TauPyModel(model="iasp91") arrivals = model.get_ray_paths(evdep, evdist, ("S250p",)) arrival = arrivals[0] index = np.searchsorted(arrival.path["depth"][::-1], 200) pdist = arrival.path["dist"] pp2 = degrees2kilometers((pdist[-1] - pdist[-index - 1]) * 180 / np.pi) self.assertLess(abs(pp1 - pp2) / pp2, 0.2)
def test_ppointvsobspytaup_P2S(self): slowness = 6.28 evdep = 12.4 evdist = 67.7 depth = 200 pp1 = self.model.ppoint_distance(depth, slowness) model = TauPyModel(model="iasp91") arrivals = model.get_ray_paths(evdep, evdist, ("P250s",)) arrival = arrivals[0] index = np.searchsorted(arrival.path["depth"][::-1], depth) pdist = arrival.path["dist"] pp2 = degrees2kilometers((pdist[-1] - pdist[-index - 1]) * 180 / np.pi) self.assertLess(abs(pp1 - pp2) / pp2, 0.1)
def test_ppointvsobspytaup_P2S(self): slowness = 6.28 evdep = 12.4 evdist = 67.7 depth = 200 pp1 = self.model.ppoint_distance(depth, slowness) model = TauPyModel(model='iasp91') arrivals = model.get_ray_paths(evdep, evdist, ('P250s', )) arrival = arrivals[0] index = np.searchsorted(arrival.path['depth'][::-1], depth) pdist = arrival.path['dist'] pp2 = degrees2kilometers((pdist[-1] - pdist[-index - 1]) * 180 / np.pi) self.assertLess(abs(pp1 - pp2) / pp2, 0.1)
def test_high_slowness_crust(self): """ Check handling of sources located in a high slowness layer. """ model_name = "high_slowness_crust" with TemporaryWorkingDirectory(): folder = os.path.abspath(os.curdir) build_taup_model( filename=os.path.join(DATA, os.path.pardir, model_name + ".nd"), output_folder=folder, verbose=False) model = TauPyModel(os.path.join(folder, model_name + ".npz")) arrivals = model.get_ray_paths(20.0, 0.84, phase_list=["sS"]) assert len(arrivals) == 0
def test_many_identically_named_phases(self): """ Regression test to make sure obspy.taup works with models that produce many identically names seismic phases. """ with TemporaryWorkingDirectory(): folder = os.path.abspath(os.curdir) model_name = "smooth_geodynamic_model" build_taup_model( filename=os.path.join(DATA, model_name + ".tvel"), output_folder=folder, verbose=False) m = TauPyModel(os.path.join(folder, model_name + ".npz")) arr = m.get_ray_paths(172.8000, 46.762440693494824, ["SS"]) self.assertGreater(len(arr), 10)
def test_arrivals_class(self): """ Tests list operations on the Arrivals class. See #1518. """ model = TauPyModel(model='iasp91') arrivals = model.get_ray_paths(source_depth_in_km=0, distance_in_degree=1, phase_list=['Pn', 'PmP']) self.assertEqual(len(arrivals), 2) # test copy self.assertTrue(isinstance(arrivals.copy(), Arrivals)) # test sum self.assertTrue(isinstance(arrivals + arrivals, Arrivals)) self.assertTrue(isinstance(arrivals + arrivals[0], Arrivals)) # test multiplying self.assertTrue(isinstance(arrivals * 2, Arrivals)) arrivals *= 3 self.assertEqual(len(arrivals), 6) self.assertTrue(isinstance(arrivals, Arrivals)) # test slicing self.assertTrue(isinstance(arrivals[2:5], Arrivals)) # test appending arrivals.append(arrivals[0]) self.assertEqual(len(arrivals), 7) self.assertTrue(isinstance(arrivals, Arrivals)) # test assignment arrivals[0] = arrivals[-1] self.assertTrue(isinstance(arrivals, Arrivals)) arrivals[2:5] = arrivals[1:4] self.assertTrue(isinstance(arrivals, Arrivals)) # test assignment with wrong type with self.assertRaises(TypeError): arrivals[0] = 10. with self.assertRaises(TypeError): arrivals[2:5] = [0, 1, 2] with self.assertRaises(TypeError): arrivals.append(arrivals) # test add and mul with wrong type with self.assertRaises(TypeError): arrivals + [2, ] with self.assertRaises(TypeError): arrivals += [2, ] with self.assertRaises(TypeError): arrivals * [2, ] with self.assertRaises(TypeError): arrivals *= [2, ]
def test_small_regional_model(self): """ Tests a small regional model as this used to not work. """ with TemporaryWorkingDirectory(): folder = os.path.abspath(os.curdir) model_name = "regional_model" build_taup_model( filename=os.path.join(DATA, os.path.pardir, model_name + ".tvel"), output_folder=folder, verbose=False) m = TauPyModel(os.path.join(folder, model_name + ".npz")) arr = m.get_ray_paths(source_depth_in_km=18.0, distance_in_degree=1.0) self.assertEqual(len(arr), 9) for a, d in zip(arr, [("p", 18.143), ("Pn", 19.202), ("PcP", 19.884), ("sP", 22.054), ("ScP", 23.029), ("PcS", 26.410), ("s", 31.509), ("Sn", 33.395), ("ScS", 34.533)]): self.assertEqual(a.name, d[0]) self.assertAlmostEqual(a.time, d[1], 3)
def test_regional_models(self): """ Tests small regional models as this used to not work. Note: It looks like too much work to get a 1-layer model working. The problem is first in finding the moho, and second in coarsely- sampling slowness. Also, why bother. """ model_names = ["2_layer_model", "5_layer_model", "2_layer_no_discontinuity_model"] expected_results = [ [("p", 18.143), ("P", 19.202), ("Pn", 19.202), ("P", 19.884), ("sP", 22.054), ("pP", 23.023), ("pP", 23.038), ("sP", 25.656), ("sP", 25.759), ("s", 31.509), ("S", 33.395), ("Sn", 33.395), ("S", 34.533), ("sS", 39.991), ("sS", 40.009), ("PP", 3110.537), ("SP", 4267.568), ("PS", 4269.707), ("SS", 5426.732)], [("P", 17.358), ("Pn", 17.358), ("P", 17.666), ("p", 17.804), ("P", 17.869), ("P", 18.039), ("pP", 21.125), ("pP", 21.164), ("sP", 22.640), ("sP", 22.716), ("sP", 22.992), ("sP", 23.766), ("sP", 23.918), ("sP", 24.039), ("sP", 24.041), ("S", 30.029), ("Sn", 30.029), ("S", 30.563), ("s", 30.800), ("S", 30.913), ("S", 31.208), ("sS", 36.547), ("sS", 36.613), ("PP", 3147.085), ("SP", 4294.699), ("PS", 4296.826), ("SS", 5444.434)], [("p", 18.143), ("sP", 22.054), ("s", 31.509), ("PP", 3562.683), ("SP", 4881.292), ("PS", 4883.430), ("SS", 6202.037)] ] for model_name, expects in zip(model_names, expected_results): with TemporaryWorkingDirectory(): folder = os.path.abspath(os.curdir) build_taup_model( filename=os.path.join(DATA, os.path.pardir, model_name + ".tvel"), output_folder=folder, verbose=False) model = TauPyModel(os.path.join(folder, model_name + ".npz")) arrivals = model.get_ray_paths(source_depth_in_km=18.0, distance_in_degree=1.0) assert len(arrivals) == len(expects) for arrival, expect in zip(arrivals, expects): assert arrival.name == expect[0] assert round(abs(arrival.time-expect[1]), 2) == 0
def test_small_regional_model(self): """ Tests a small regional model as this used to not work. """ with TemporaryWorkingDirectory(): folder = os.path.abspath(os.curdir) model_name = "regional_model" build_taup_model(filename=os.path.join(DATA, os.path.pardir, model_name + ".tvel"), output_folder=folder, verbose=False) m = TauPyModel(os.path.join(folder, model_name + ".npz")) arr = m.get_ray_paths(source_depth_in_km=18.0, distance_in_degree=1.0) self.assertEqual(len(arr), 9) for a, d in zip(arr, [("p", 18.143), ("Pn", 19.202), ("PcP", 19.884), ("sP", 22.054), ("ScP", 23.029), ("PcS", 26.410), ("s", 31.509), ("Sn", 33.395), ("ScS", 34.533)]): self.assertEqual(a.name, d[0]) self.assertAlmostEqual(a.time, d[1], 3)
def calculate_depths(i): #start = time.time() lhs = np.ones(( len(discon),)) model = TauPyModel(model="iasp91") #for i in range(f): for j in range(len(discon)): phase = 'S'+ str(discon[j]) + 'p' arrivals = model.get_ray_paths(source_depth_in_km=source_info[i,1], distance_in_degree=source_info[i,0] , phase_list=[phase]) piercing_points = model.get_pierce_points(source_depth_in_km=source_info[i,1], distance_in_degree=source_info[i,0] , phase_list=[phase]) piercing_points_S = model.get_pierce_points(source_depth_in_km=source_info[i,1], distance_in_degree=source_info[i,0] , phase_list=['S']) if piercing_points: t_sp = piercing_points[0].pierce[-1][1] t_s = piercing_points_S[0].pierce[-1][1] lhs[j] = t_s - t_sp file_name = file_info[i] return (lhs, file_name)
def _compare_against_ak135_tables_kennet(self, filename, phases): """ Helper function to compare against the AK135 traveltime tables of Kennet. This test is also done in the Java TauP version. """ values = self._read_ak135_test_files(filename) m = TauPyModel(model="ak135") for value in values: # Parameters are not strictly defined for a non-existent travel # time. if value["time"] == 0.0: continue arrivals = m.get_ray_paths(source_depth_in_km=value["depth"], distance_in_degree=value["dist"], phase_list=phases) arrivals = sorted(arrivals, key=lambda x: x.time) arr = arrivals[0] # These are the same tolerances as in the Java tests suite. self.assertTrue(abs(arr.time - value["time"]) < 0.07) self.assertTrue( abs(arr.ray_param_sec_degree - value["ray_param"]) < 0.11)
def _compare_against_ak135_tables_kennet(self, filename, phases): """ Helper function to compare against the AK135 traveltime tables of Kennet. This test is also done in the Java TauP version. """ values = self._read_ak135_test_files(filename) m = TauPyModel(model="ak135") for value in values: # Parameters are not strictly defined for a non-existent travel # time. if value["time"] == 0.0: continue arrivals = m.get_ray_paths( source_depth_in_km=value["depth"], distance_in_degree=value["dist"], phase_list=phases) arrivals = sorted(arrivals, key=lambda x: x.time) arr = arrivals[0] # These are the same tolerances as in the Java tests suite. self.assertTrue(abs(arr.time - value["time"]) < 0.07) self.assertTrue(abs(arr.ray_param_sec_degree - value["ray_param"]) < 0.11)
y, color=color, linewidth=0.3, linestyle='solid', alpha=0.1) if len(x) > 0 and len( y) > 0: # this function prevents text being overwritten plottext(x[0], y[0], phase, 'top', 'right', color, textlist) plottext(x[len(x) - 1], y[len(y) - 1], phase, 'top', 'left', color, textlist) # Add the inset picture of the globe at x, y, width, height, as a fraction of the parent plot ax1 = fig.add_axes([0.63, 0.48, 0.4, 0.4], polar=True) # Plot all pre-determined phases for phase, distance in GLOBE_PHASES: arrivals = model.get_ray_paths(EQZ, distance, phase_list=[phase]) ax1 = arrivals.plot_rays(plot_type='spherical', legend=False, label_arrivals=False, plot_all=True, phase_list=PHASES, show=False, ax=ax1) # Annotate regions of the globe ax1.text(0, 0, 'Solid\ninner\ncore', horizontalalignment='center', verticalalignment='center', bbox=dict(facecolor='white', edgecolor='none', alpha=0.7))
def test_paths_for_crustal_phases(self): """ Tests that Pn and PmP are correctly modelled and not mixed up. See #1392. """ model = TauPyModel(model='iasp91') paths = model.get_ray_paths(source_depth_in_km=0, distance_in_degree=1, phase_list=['Pn', 'PmP']) self.assertEqual(len(paths), 2) self.assertEqual(paths[0].name, "PmP") self.assertAlmostEqual(paths[0].time, 21.273, 3) self.assertEqual(paths[1].name, "Pn") self.assertAlmostEqual(paths[1].time, 21.273, 3) self.assertAlmostEqual(paths[0].time, 21.273, 3) # Values of visually checked paths to guard against regressions. pmp_path = [ [0.0, 0.0], [8.732364066174294e-07, 0.005402127286288305], [0.00020293803558129412, 1.2550644943312363], [0.000405124234951687, 2.5047268613761844], [0.0008098613580518535, 5.004051595465171], [0.0016207981804224497, 10.002701063643144], [0.00243369214394241, 15.001350531821117], [0.0032485517460744207, 20.0], [0.0034500021984838003, 20.9375], [0.0036515675727796315, 21.875], [0.004055043605178164, 23.75], [0.004863380445624696, 27.5], [0.006485622554890742, 35.0], [0.008803860898528547, 35.018603858353345], [0.011122099242166353, 35.0], [0.012744341351432398, 27.5], [0.01355267819187893, 23.75], [0.013956154224277463, 21.875], [0.014157719598573294, 20.9375], [0.014359170050982674, 20.0], [0.015174029653114684, 15.001350531821117], [0.015986923616634643, 10.002701063643144], [0.01679786043900524, 5.004051595465171], [0.017202597562105407, 2.5047268613761844], [0.0174047837614758, 1.2550644943312363], [0.017606848560650475, 0.005402127286288305], [0.017607721797057094, 0.0]] pn_path = [ [0.0, 0.0], [8.732421799574388e-07, 0.005402127286288305], [0.00020293937754080365, 1.2550644943312363], [0.0004051269144571584, 2.5047268613761844], [0.0008098667167377564, 5.004051595465171], [0.0016208089138889542, 10.002701063643144], [0.002433708274208186, 15.001350531821117], [0.003248573295310095, 20.0], [0.0034500255976490177, 20.9375], [0.0036515928239481774, 21.875], [0.004055072566590625, 23.75], [0.004863416852584004, 27.5], [0.0064856739540738425, 35.0], [0.0064856739540738425, 35.0], [0.010967618565869454, 35.0], [0.010967618565869454, 35.0], [0.012589875667359293, 27.5], [0.013398219953352672, 23.75], [0.01380169969599512, 21.875], [0.01400326692229428, 20.9375], [0.014204719224633202, 20.0], [0.015019584245735112, 15.001350531821117], [0.015832483606054343, 10.002701063643144], [0.01664342580320554, 5.004051595465171], [0.017048165605486137, 2.5047268613761844], [0.017250353142402492, 1.2550644943312363], [0.017452419277763337, 0.005402127286288305], [0.017453292519943295, 0.0]] np.testing.assert_allclose([_i[0] for _i in pmp_path], paths[0].path["dist"]) np.testing.assert_allclose([_i[1] for _i in pmp_path], paths[0].path["depth"]) np.testing.assert_allclose([_i[0] for _i in pn_path], paths[1].path["dist"]) np.testing.assert_allclose([_i[1] for _i in pn_path], paths[1].path["depth"])
def write_input(eq_lat,eq_lon,eq_dep,ievt,stations,phase,delays_file,Tmin,taup_model,filename,raytheory=False,tt_from_raydata=True,**kwargs): ''' write an input file for globalseis finite frequency tomography software. each earthquake and datatype (P,S,etc...) has it's own input file args-------------------------------------------------------------------------- eq_lat: earthquake latitude (deg) eq_lon: earthquake longitude (deg) eq_dep: earthquake depth (km) stations: stations array (lons,lats) delays_file: h5py datafile containing cross correlation delay times Tmin: minimum period at which cross correlation measurements were made taup_model: name of TauPyModel used to calculate 1D travel times filename: raytheory: True or False tt_from_raydata: If True, writes cross correlation times to 'xcor*', which will then be added to 1D travel times from raydata kwargs------------------------------------------------------------------------ plot_figure: plot a figure showing source receiver geometry and delay map t_sig: estimated standard error in cross correlation measurement. add_noise: add gaussian noise to traveltime measurements of magnitude t_sig fake_SKS_header: test the SKS header ''' #define variables used in finite frequency tomography (kwargs)---------------- idate = kwargs.get('idate','15001') #event date YYDDD where DDD is between 1 and 365 iotime = kwargs.get('iotime','010101') #vent origin time (HHMMSS) kluster = kwargs.get('kluster','0') #0 if no clustering used stationcode = kwargs.get('stationcode','XXXX') #station code (no more than 16 chars) netw = kwargs.get('netw','PLUMENET ') #network code nobst = kwargs.get('nobst','1') #number of travel time measurements nobsa = kwargs.get('nobsa','0') #number of amplitude measurements kpole = kwargs.get('kpole','0') #number of polar crossings (0 for P and S) sampling_rate = kwargs.get('sampling_rate',10.0) n_bands = kwargs.get('n_bands',1) # spectral bands used (TODO setup more than one) kunit = kwargs.get('kunit',1) #unit of noise (1 = nm) rms0 = kwargs.get('rms0',0) #don't know what this is plot_figure = kwargs.get('plot_figure',False) dist_min = kwargs.get('dist_min',30.0) dist_max = kwargs.get('dist_max',90.0) t_sig = kwargs.get('t_sig',0.0) add_noise = kwargs.get('add_noise',False) fake_SKS_header = kwargs.get('fake_SKS_header',False) filter_type = kwargs.get('filter_type','none') ievt=int(ievt) #double check ievt is an integer (in case it was read from a file) debug = False #create taup model------------------------------------------------------------ tt_model = TauPyModel(taup_model) #get filter parameters-------------------------------------------------------- print 'Tmin = ', Tmin filter_type, freqmin,freqmax, window = get_filter_params(delays_file,phase,Tmin,filter_type=filter_type) omega,amp = get_filter_freqs(filter_type,freqmin,freqmax,sampling_rate) window_len = window[1] - window[0] #write header----------------------------------------------------------------- f = open(filename,'w') f.write('{}'.format(filename)+'\n') f.write('{}'.format('None'+'\n')) fdelays = open('xcor_{}'.format(filename),'w') #ray information-------------------------------------------------------------- if phase == 'P': gm_component = 'BHZ ' #ground motion component f.write('P'+'\n') f.write('P'+'\n') f.write('6371 1 1'+'\n') f.write('3482 2 1'+'\n') f.write('6371 5 0'+'\n') elif phase == 'S' and fake_SKS_header == False: gm_component = 'BHT ' #ground motion component f.write('S'+'\n') f.write('S'+'\n') f.write('6371 1 2'+'\n') f.write('3482 2 2'+'\n') f.write('6371 5 0'+'\n') elif phase == 'SKS' or fake_SKS_header == True: gm_component = 'BHR ' #ground motion component f.write('SKS'+'\n') f.write('SKS'+'\n') f.write('6371 1 2'+'\n') f.write('3482 4 1'+'\n') f.write('1217.1 2 1'+'\n') f.write('3482 4 2'+'\n') f.write('6371 5 0'+'\n') #this is hardwired for now (based on range of rays found with ray tracing software) #TODO make distance range more adaptable if phase == 'P': dist_min = 30.0 #dist_max = 98.3859100 dist_max = 97.0 elif phase == 'S': dist_min = 30.0 #dist_max = 99.0557175 dist_max = 97.0 elif phase == 'SKS': #dist_min = 66.0320663 #dist_max = 144.349365 dist_min = 68.0 dist_max = 142.0 #write spectral band information----------------------------------------------- if raytheory: n_bands=0 f.write('{}'.format(n_bands)+'\n') else: f.write('{}'.format(n_bands)+'\n') f.write('{}'.format(len(omega))+'\n') for i in range(0,len(omega)): f.write('{} {}'.format(omega[i],amp[i])+'\n') #event delay map-------------------------------------------------------------- #lats_i = np.arange(-30.0,30.0,0.1) #lons_i = np.arange(-30.0,30.0,0.1) lats_i = np.arange(-45.0,45.0,0.1) lons_i = np.arange(-45.0,45.0,0.1) if plot_figure: event_map,figure_axis = make_event_delay_map(eq_lat,eq_lon,phase,delays_file,Tmin,lats_i=lats_i,lons_i=lons_i,plot=True,return_axis=False,nevent=ievt) else: if debug: print 'func:write_input- making event delay map for', phase #print 'eq_lat,eq_lon,phase,Tmin lats_i,lons_i',eq_lat,eq_lon,phase,Tmin,lats_i,lons_i event_map = make_event_delay_map(eq_lat,eq_lon,phase,delays_file,Tmin,lats_i=lats_i, lons_i=lons_i,return_axis=False,plot=True,nevent=ievt) #find delays at stations------------------------------------------------------ if plot_figure: station_delays = get_station_delays(event_map,stations,lats_i,lons_i,pass_figure_axis=True,figure_axis=figure_axis) else: station_delays = get_station_delays(event_map,stations,lats_i,lons_i) #add noise (optional)--------------------------------------------------------- if t_sig != 0: noise = np.random.normal(0,t_sig,len(station_delays)) if add_noise: station_delays += noise station_lons = stations[0,:] station_lats = stations[1,:] n_stations = len(station_lats) station_elevation = 0.0 for i in range(0,n_stations): dist_deg, rotation_angle = get_event_params(eq_lat,eq_lon) #find event distance event_distaz = gps2dist_azimuth(eq_lat,eq_lon,station_lats[i],station_lons[i],a=6371000.0,f=0.0) event_dist_deg = kilometer2degrees((event_distaz[0]/1000.0)) #skip station if too close or too far from source if event_dist_deg <= dist_min or event_dist_deg >= dist_max: continue #get ray theoretical travel time #if phase == 'S': # phase_list = ['s','S','Sdiff'] #elif phase == 'P': # phase_list = ['p','P','Pdiff'] ray_theory_arr = tt_model.get_travel_times(eq_dep,event_dist_deg,phase_list=[phase]) ### TRY TO GET TRAVEL TIME IN CORE ######################################################### ray_theory_path = tt_model.get_ray_paths(eq_dep,event_dist_deg,phase_list=[phase]) phase_path = ray_theory_path[0] path_time = phase_path.path['time'] path_dt = np.diff(path_time) path_depth = phase_path.path['depth'] time_in_core = 0 for p_i in range(0,len(path_dt)): if path_depth[p_i] >= 2889.0: time_in_core += path_dt[p_i] ############################################################################################ if debug: print '_________________________________________________________________________________' print 'arrivals from taup_get_travel_time for event parameters [depth,delta(deg),phase]:' print '[{},{},{}]'.format(eq_dep,event_dist_deg,phase),ray_theory_arr print 'time in core: ', time_in_core print '_________________________________________________________________________________' ray_theory_travel_time = ray_theory_arr[0].time delay_time = station_delays[i] tobs = ray_theory_travel_time - delay_time if debug: print 'distance, phase, raytheory travel time, observed delay:', event_dist_deg,phase,ray_theory_travel_time,delay_time print 'the travel time observation is ', tobs fdelays.write('{}'.format(delay_time)+'\n') if raytheory: n_bands = 0 nbt = 0 #spectral band number (must be 0 if ray theory) window_len = 0 kunit = 0 corcoeft=0 else: nbt = 1 #spectral band number #write line 1-------------------------------------------------------------- f.write('{} {} {} {} {} {} {} {} {} {} {} {} {} {} {} {}'.format(idate, iotime,ievt,kluster,stationcode,netw,gm_component,eq_lat,eq_lon,eq_dep, station_lats[i],station_lons[i],station_elevation,nobst,nobsa,kpole)+'\n') #write line 2-------------------------------------------------------------- f.write('{} {} '.format(kunit,rms0)) for j in range(0,n_bands+1): f.write('0') #used to be 0.0 f.write('\n') #write line 3--------------------------------------------------------------- if raytheory: f.write('{}'.format(1)+'\n') else: f.write('{}'.format(n_bands)+'\n') #write line 4--------------------------------------------------------------- corcoeft = 1.0 # cross correlation coefficient f.write('{} {} {} {} {} {} {}'.format(tobs,t_sig,corcoeft,nbt,window_len,time_in_core,'#tobs,tsig,corcoeft,nbt,window,tincore')+'\n') #write line 5-------------------------------------------------------------- f.write('{}'.format(0)+'\n')
class TauPyPlottingTestCase(unittest.TestCase): """ TauPy plotting tests. """ def setUp(self): self.image_dir = os.path.join(os.path.dirname(__file__), 'images') self.model = TauPyModel(model="iasp91") def test_spherical_many_phases(self): with ImageComparison(self.image_dir, "spherical_many_phases.png") as ic: self.model.get_ray_paths(500, 140).plot(plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_spherical_many_phases_buried_station(self): """ Same as test_spherical_many_phases but this time the receiver is buried. """ with ImageComparison(self.image_dir, "spherical_many_phases_buried_station.png") as ic: arrivals = self.model.get_ray_paths(500, 140, receiver_depth_in_km=200) arrivals.plot(plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_spherical_many_phases_no_other_way(self): """ Same as test_spherical_many_phases but this time no phases travelling the other way are plotted. """ with ImageComparison(self.image_dir, "spherical_many_phases_single_way.png") as ic: self.model.get_ray_paths(500, 140).plot(plot_type="spherical", plot_all=False, show=False) plt.savefig(ic.name) def test_spherical_more_then_360_degrees(self): """ Test a plot where rays travel more than 360.0 degrees. """ with ImageComparison(self.image_dir, "spherical_more_then_360.png") as ic: self.model.get_ray_paths(0, 10, phase_list=["PPPPPP"]).plot( plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_spherical_diff_phases(self): with ImageComparison(self.image_dir, "spherical_diff_phases.png") as ic: self.model.get_ray_paths( 700, 140, phase_list=["Pdiff", "Sdiff", "pSdiff", "sSdiff", "pPdiff", "sPdiff"]).plot( plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases(self): with ImageComparison(self.image_dir, "cartesian_many_phases.png") as ic: self.model.get_ray_paths(500, 140).plot(plot_type="cartesian", plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases_buried_station(self): """ Same as test_cartesian_many_phases but this time the receiver is buried. """ with ImageComparison(self.image_dir, "cartesian_many_phases_buried_station.png") as ic: arrivals = self.model.get_ray_paths(500, 140, receiver_depth_in_km=200) arrivals.plot(plot_type="cartesian", plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases_no_other_way(self): """ Same as test_cartesian_many_phases but this time no phases travelling the other way are plotted. """ with ImageComparison(self.image_dir, "cartesian_many_phases_single_way.png") as ic: self.model.get_ray_paths(500, 140).plot(plot_type="cartesian", plot_all=False, show=False) plt.savefig(ic.name) def test_cartesian_multiple_station_markers(self): """ Cartesian plot with two station markers. """ with ImageComparison(self.image_dir, "cartesian_multiple_stations.png") as ic: self.model.get_ray_paths(350, 100).plot(plot_type="cartesian", plot_all=True, show=False) plt.savefig(ic.name)
from obspy.taup import TauPyModel model = TauPyModel(model='iasp91') arrivals = model.get_ray_paths(500, 140, phase_list=['Pdiff', 'SS']) arrivals.plot_rays(plot_type='spherical', phase_list=['Pdiff', 'SS'], legend=True)
def main(fnam_nd: str, times: tuple, phase_list=("P", "S"), depth=40., plot_rays=False): """ Compute distance of an event, given S-P time :param fnam_nd: name of TauP compatible model file :param times: list of S-P time :param phase_list: list of phases between which the time difference is measured (usually P and S) :param depth: assumed depth of event :param plot_rays: create a plot with the ray paths """ fnam_npz = "./taup_tmp/" \ + psplit(fnam_nd)[-1][:-3] + ".npz" build_taup_model(fnam_nd, output_folder="./taup_tmp") cache = OrderedDict() model = TauPyModel(model=fnam_npz, cache=cache) if plot_rays: fig, ax = plt.subplots(1, 1) for itime, tSmP in enumerate(times): dist = get_dist(model, tSmP=tSmP, depth=depth, phase_list=phase_list) if dist is None: print(f"{fnam_nd}, S-P time: {tSmP:5.1f}: NO SOLUTION FOUND!") else: print(f"{fnam_nd}, S-P time: {tSmP:5.1f}, " f"taup_distance: {dist:5.1f}") if plot_rays: if dist is None: ax.plot((-200), (-200), label="%4.1f sec, NO SOLUTION" % (tSmP), c="white", lw=0.0) else: arrivals = model.get_ray_paths(distance_in_degree=dist, source_depth_in_km=depth, phase_list=["P", "S"]) RADIUS_MARS = 3389.5 already_plotted = dict(P=False, S=False) ls = dict(P="solid", S="dashed") label = dict(P="%4.1f sec, %5.1f°" % (tSmP, dist), S=None) for arr in arrivals: if not already_plotted[arr.name]: already_plotted[arr.name] = True x = (RADIUS_MARS - arr.path["depth"]) * \ np.sin(arr.path["dist"]) y = (RADIUS_MARS - arr.path["depth"]) * \ np.cos(arr.path["dist"]) ax.plot(x, y, c="C%d" % itime, ls=ls[arr.name], label=label[arr.name], lw=1.2) if plot_rays: for layer_depth in model.model.get_branch_depths( ): # (0, 10, 50, 1000, # 1500): angles = np.linspace(0, 2 * np.pi, 1000) x_circle = (RADIUS_MARS - layer_depth) * np.sin(angles) y_circle = (RADIUS_MARS - layer_depth) * np.cos(angles) ax.plot(x_circle, y_circle, c="k", ls="dashed", lw=0.5, zorder=-1) for layer_depth in (model.model.cmb_depth, 0.0): angles = np.linspace(0, 2 * np.pi, 1000) x_circle = (RADIUS_MARS - layer_depth) * np.sin(angles) y_circle = (RADIUS_MARS - layer_depth) * np.cos(angles) ax.plot(x_circle, y_circle, c="k", ls="solid", lw=1.0) # for layer_depth in [1100.0]: # angles = np.linspace(0, 2 * np.pi, 1000) # x_circle = (RADIUS_MARS - layer_depth) * np.sin(angles) # y_circle = (RADIUS_MARS - layer_depth) * np.cos(angles) # ax.plot(x_circle, y_circle, c="k", ls="dotted", lw=0.3) ax.set_xlim(-100, RADIUS_MARS + 100) ax.set_ylim(1000, RADIUS_MARS + 100) ax.set_xlabel("radius / km") ax.set_ylabel("radius / km") ax.set_title("Ray path for model %s" % fnam_nd) ax.set_aspect("equal", "box") ax.legend(loc="lower left") plt.show()
#latsta= 37.2869 #sta='MILP' #lonsta=-121.8340 #latsta=37.4491 path = '/Users/dmelgar/FakeQuakes/M6_validation_pwave/output/waveforms/M6.000000/' #taup zs = 8.0 g = Geod(ellps='WGS84') azimuth, baz, dist = g.inv(-121.753508, 37.332028, lonsta, latsta) dist_in_degs = kilometer2degrees(dist / 1000.) velmod = TauPyModel( '/Users/dmelgar/FakeQuakes/M6_validation_pwave/structure/bbp_norcal.npz') Ppaths = velmod.get_ray_paths(zs, dist_in_degs, phase_list=['P', 'p']) p = Ppaths[0].time Spaths = velmod.get_ray_paths(zs, dist_in_degs, phase_list=['S', 's']) s = Spaths[0].time nlf = read(path + sta + '.LYN.sac') elf = read(path + sta + '.LYE.sac') zlf = read(path + sta + '.LYZ.sac') nbb = read(path + sta + '.bb.HNN.sac') ebb = read(path + sta + '.bb.HNE.sac') zbb = read(path + sta + '.bb.HNZ.sac') nhf = read(path + sta + '.HNN.sac') ehf = read(path + sta + '.HNE.sac') zhf = read(path + sta + '.HNZ.sac')
def stochastic_simulation(home, project_name, rupture_name, sta, sta_lon, sta_lat, component, model_name, rise_time_depths, moho_depth_in_km, total_duration=100, hf_dt=0.01, stress_parameter=50, kappa=0.04, Qexp=0.6, Pwave=False, Swave=True, high_stress_depth=1e4): ''' Run stochastic HF sims stress parameter is in bars ''' from numpy import genfromtxt, pi, logspace, log10, mean, where, exp, arange, zeros, argmin, rad2deg, arctan2, real from pyproj import Geod from obspy.geodetics import kilometer2degrees from obspy.taup import TauPyModel from mudpy.forward import get_mu, write_fakequakes_hf_waveforms_one_by_one, read_fakequakes_hypo_time from obspy import Stream, Trace from sys import stdout import warnings #print out what's going on: out = '''Running with input parameters: home = %s project_name = %s rupture_name = %s sta = %s sta_lon = %s sta_lat = %s model_name = %s rise_time_depths = %s moho_depth_in_km = %s total_duration = %s hf_dt = %s stress_parameter = %s kappa = %s Qexp = %s component = %s Pwave = %s Swave = %s high_stress_depth = %s ''' % (home, project_name, rupture_name, sta, str(sta_lon), str(sta_lat), model_name, str(rise_time_depths), str(moho_depth_in_km), str(total_duration), str(hf_dt), str(stress_parameter), str(kappa), str(Qexp), str(component), str(Pwave), str(Swave), str(high_stress_depth)) print(out) # rupture=rupture_name.split('.')[0]+'.'+rupture_name.split('.')[1] # log=home+project_name+'/output/waveforms/'+rupture+'/'+sta+'.HN'+component+'.1cpu.log' # logfile=open(log,'w') # logfile.write(out) #print 'stress is '+str(stress_parameter) #I don't condone it but this cleans up the warnings warnings.filterwarnings("ignore") #Load the source fault = genfromtxt(home + project_name + '/output/ruptures/' + rupture_name) #Onset times for each subfault onset_times = fault[:, 12] #load velocity structure structure = genfromtxt(home + project_name + '/structure/' + model_name) #Frequencies vector f = logspace(log10(hf_dt), log10(1 / (2 * hf_dt)) + 0.01, 50) omega = 2 * pi * f #Output time vector (0 is origin time) t = arange(0, total_duration, hf_dt) #Projection object for distance calculations g = Geod(ellps='WGS84') #Create taup velocity model object, paste on top of iaspei91 #taup_create.build_taup_model(home+project_name+'/structure/bbp_norcal.tvel',output_folder=home+project_name+'/structure/') velmod = TauPyModel(model=home + project_name + '/structure/iquique', verbose=True) #Get epicentral time epicenter, time_epi = read_fakequakes_hypo_time(home, project_name, rupture_name) #Moments slip = (fault[:, 8]**2 + fault[:, 9]**2)**0.5 subfault_M0 = slip * fault[:, 10] * fault[:, 11] * fault[:, 13] subfault_M0 = subfault_M0 * 1e7 #to dyne-cm M0 = subfault_M0.sum() relative_subfault_M0 = subfault_M0 / M0 Mw = (2. / 3) * (log10(M0 * 1e-7) - 9.1) #Corner frequency scaling i = where(slip > 0)[0] #Non-zero faults N = len(i) #number of subfaults dl = mean((fault[:, 10] + fault[:, 11]) / 2) #predominant length scale dl = dl / 1000 # to km #Tau=p perturbation tau_perturb = 0.1 #Deep faults receive a higher stress stress_multiplier = 3 print('... working on ' + component + ' component semistochastic waveform for station ' + sta) #initalize output seismogram tr = Trace() tr.stats.station = sta tr.stats.delta = hf_dt tr.stats.starttime = time_epi #info for sac header (added at the end) az, backaz, dist_m = g.inv(epicenter[0], epicenter[1], sta_lon, sta_lat) dist_in_km = dist_m / 1000. hf = zeros(len(t)) # out='''Parameters before we get into subfault calculations: # rupture_name = %s # epicenter = %s # time_epi = %s # M0 = %E # Mw = %10.4f # Num_Subfaults = %i # dl = %.2f # Dist_in_km = %10.4f # '''%(rupture_name,str(epicenter),str(time_epi),M0,Mw,int(N),dl,dist_in_km) # print out # logfile.write(out) #Loop over subfaults # earliestP=1e10 #something outrageously high # earliestP_kfault=1e10 for kfault in range(len(fault)): #Print status to screen if kfault % 150 == 0: if kfault == 0: stdout.write(' [') stdout.flush() stdout.write('.') stdout.flush() if kfault == len(fault) - 1: stdout.write(']\n') stdout.flush() #Include only subfaults with non-zero slip if subfault_M0[kfault] > 0: #Get subfault to station distance lon_source = fault[kfault, 1] lat_source = fault[kfault, 2] azimuth, baz, dist = g.inv(lon_source, lat_source, sta_lon, sta_lat) dist_in_degs = kilometer2degrees(dist / 1000.) #Source depth? z_source = fault[kfault, 3] #No change stress = stress_parameter #Is subfault in an SMGA? #radius_in_km=15.0 #smga_center_lon=-69.709200 #smga_center_lat=-19.683600 #in_smga=is_subfault_in_smga(lon_source,lat_source,smga_center_lon,smga_center_lat,radius_in_km) # ###Apply multiplier? #if in_smga==True: # stress=stress_parameter*stress_multiplier # print "%.4f,%.4f is in SMGA, stress is %d" % (lon_source,lat_source,stress) #else: # stress=stress_parameter #Apply multiplier? #if slip[kfault]>7.5: # stress=stress_parameter*stress_multiplier ##elif lon_source>-72.057 and lon_source<-71.2 and lat_source>-30.28: ## stress=stress_parameter*stress_multiplier #else: # stress=stress_parameter #Apply multiplier? #if z_source>high_stress_depth: # stress=stress_parameter*stress_multiplier #else: # stress=stress_parameter # Frankel 95 scaling of corner frequency #verified this looks the same in GP # Right now this applies the same factor to all faults fc_scale = (M0) / (N * stress * dl**3 * 1e21) #Frankel scaling small_event_M0 = stress * dl**3 * 1e21 #Get rho, alpha, beta at subfault depth zs = fault[kfault, 3] mu, alpha, beta = get_mu(structure, zs, return_speeds=True) rho = mu / beta**2 #Get radiation scale factor Spartition = 1 / 2**0.5 if component == 'N': component_angle = 0 elif component == 'E': component_angle = 90 rho = rho / 1000 #to g/cm**3 beta = (beta / 1000) * 1e5 #to cm/s alpha = (alpha / 1000) * 1e5 #Verified this produces same value as in GP CS = (2 * Spartition) / (4 * pi * (rho) * (beta**3)) CP = 2 / (4 * pi * (rho) * (alpha**3)) #Get local subfault rupture speed beta = beta / 100 #to m/s vr = get_local_rupture_speed(zs, beta, rise_time_depths) vr = vr / 1000 #to km/s dip_factor = get_dip_factor(fault[kfault, 5], fault[kfault, 8], fault[kfault, 9]) #Subfault corner frequency c0 = 2.0 #GP2015 value fc_subfault = (c0 * vr) / (dip_factor * pi * dl) #get subfault source spectrum #S=((relative_subfault_M0[kfault]*M0/N)*f**2)/(1+fc_scale*(f/fc_subfault)**2) S = small_event_M0 * (omega**2 / (1 + (f / fc_subfault)**2)) frankel_conv_operator = fc_scale * ( (fc_subfault**2 + f**2) / (fc_subfault**2 + fc_scale * f**2)) S = S * frankel_conv_operator #get high frequency decay P = exp(-pi * kappa * f) # if kfault==0: # out='''Parameters within subfault calculations: # kfault_lon = %10.4f # kfault_lat = %10.4f # CS = %s # CP = %s # S[0] = %s # frankel_conv_operator[0] = %s # '''%(fault[kfault,1],fault[kfault,2],str(CS),str(CP),str(S[0]),str(frankel_conv_operator[0])) # print out # logfile.write(out) #Get other geometric parameters necessar for radiation pattern strike = fault[kfault, 4] dip = fault[kfault, 5] ss = fault[kfault, 8] ds = fault[kfault, 9] rake = rad2deg(arctan2(ds, ss)) #Get ray paths for all direct P arrivals Ppaths = velmod.get_ray_paths(zs, dist_in_degs, phase_list=['P', 'p']) #Get ray paths for all direct S arrivals try: Spaths = velmod.get_ray_paths(zs, dist_in_degs, phase_list=['S', 's']) except: Spaths = velmod.get_ray_paths(zs + tau_perturb, dist_in_degs, phase_list=['S', 's']) #sometimes there's no S, weird I know. Check twice. if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs + tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs + 5 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs - 5 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs + 5 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs - 10 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs + 10 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs - 50 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs + 50 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs - 75 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: Spaths = velmod.get_ray_paths(zs + 75 * tau_perturb, dist_in_degs, phase_list=['S', 's']) if len(Spaths) == 0: print( 'ERROR: I give up, no direct S in spite of multiple attempts at subfault ' + str(kfault)) #Get direct s path and moho reflection mohoS = None directS = Spaths[0] directP = Ppaths[0] #print len(Spaths) if len(Spaths) == 1: #only direct S pass else: #turn_depth=zeros(len(Spaths)-1) #turning depth of other non-direct rays #for k in range(1,len(Spaths)): # turn_depth[k-1]=Spaths[k].path['depth'].max() ##If there's a ray that turns within 2km of Moho, callt hat guy the Moho reflection #deltaz=abs(turn_depth-moho_depth_in_km) #i=argmin(deltaz) #if deltaz[i]<2: #Yes, this is a moho reflection # mohoS=Spaths[i+1] #else: # mohoS=None mohoS = Spaths[-1] ####### Build Direct P ray ###### if Pwave == True: take_off_angle_P = directP.takeoff_angle #Get attenuation due to geometrical spreading (from the path length) path_length_P = get_path_length(directP, zs, dist_in_degs) path_length_P = path_length_P * 100 #to cm #Get effect of intrinsic attenuation for that ray (path integrated) Q_P = get_attenuation(f, structure, directP, Qexp, Qtype='P') #get quarter wavelength amplificationf actors # pass rho in kg/m^3 (this units nightmare is what I get for following Graves' code) I_P = get_amplification_factors(f, structure, zs, alpha, rho * 1000) #Build the entire path term G_P = (I_P * Q_P) / path_length_P #Get conically averaged radiation pattern terms RP = conically_avg_P_radiation_pattern(strike, dip, rake, azimuth, take_off_angle_P) RP = abs(RP) #Get partition of Pwave into Z and N,E components incidence_angle = directP.incident_angle Npartition, Epartition, Zpartition = get_P_wave_partition( incidence_angle, azimuth) if component == 'Z': Ppartition = Zpartition elif component == 'N': Ppartition = Npartition else: Ppartition = Epartition #And finally multiply everything together to get the subfault amplitude spectrum AP = CP * S * G_P * P * RP * Ppartition #Generate windowed time series duration = 1. / fc_subfault + 0.09 * (dist / 1000) w = windowed_gaussian(duration, hf_dt, window_type='saragoni_hart') #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_P = apply_spectrum(w, AP, f, hf_dt) #What time after OT should this time series start at? time_insert = directP.path['time'][-1] + onset_times[kfault] # if directP.time+onset_times[kfault] < earliestP: # earliestP=directP.time+onset_times[kfault] # earliestP_kfault=kfault i = argmin(abs(t - time_insert)) j = i + len(hf_seis_P) #Check seismogram doesn't go past last sample if i < len( hf ) - 1: #if i (the beginning of the seimogram) is less than the length if j > len( hf ): #seismogram goes past total_duration length, trim it len_paste = len(hf) - i j = len(hf) #Add seismogram hf[i:j] = hf[i:j] + real(hf_seis_P[0:len_paste]) else: #Lengths are fine hf[i:j] = hf[i:j] + real(hf_seis_P) else: #Seismogram starts after end of available space pass ####### Build Direct S ray ###### if Swave == True: take_off_angle_S = directS.takeoff_angle #Get attenuation due to geometrical spreading (from the path length) path_length_S = get_path_length(directS, zs, dist_in_degs) path_length_S = path_length_S * 100 #to cm #Get effect of intrinsic aptimeenuation for that ray (path integrated) Q_S = get_attenuation(f, structure, directS, Qexp) #get quarter wavelength amplificationf actors # pass rho in kg/m^3 (this units nightmare is what I get for following Graves' code) I_S = get_amplification_factors(f, structure, zs, beta, rho * 1000) #Build the entire path term G_S = (I_S * Q_S) / path_length_S #Get conically averaged radiation pattern terms if component == 'Z': RP_vert = conically_avg_vert_radiation_pattern( strike, dip, rake, azimuth, take_off_angle_S) #And finally multiply everything together to get the subfault amplitude spectrum AS = CS * S * G_S * P * RP_vert else: RP = conically_avg_radiation_pattern( strike, dip, rake, azimuth, take_off_angle_S, component_angle) RP = abs(RP) #And finally multiply everything together to get the subfault amplitude spectrum AS = CS * S * G_S * P * RP #Generate windowed time series duration = 1. / fc_subfault + 0.063 * (dist / 1000) w = windowed_gaussian(duration, hf_dt, window_type='saragoni_hart') #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_S = apply_spectrum(w, AS, f, hf_dt) #What time after OT should this time series start at? time_insert = directS.path['time'][-1] + onset_times[kfault] #print 'ts = '+str(time_insert)+' , Td = '+str(duration) #time_insert=Ppaths[0].path['time'][-1] i = argmin(abs(t - time_insert)) j = i + len(hf_seis_S) #Check seismogram doesn't go past last sample if i < len( hf ) - 1: #if i (the beginning of the seimogram) is less than the length if j > len( hf ): #seismogram goes past total_duration length, trim it len_paste = len(hf) - i j = len(hf) #Add seismogram hf[i:j] = hf[i:j] + real(hf_seis_S[0:len_paste]) else: #Lengths are fine hf[i:j] = hf[i:j] + real(hf_seis_S) else: #Beginning of seismogram is past end of available space pass ####### Build Moho reflected S ray ###### # if mohoS==None: # pass # else: # if kfault%100==0: # print '... ... building Moho reflected S wave' # take_off_angle_mS=mohoS.takeoff_angle # # #Get attenuation due to geometrical spreading (from the path length) # path_length_mS=get_path_length(mohoS,zs,dist_in_degs) # path_length_mS=path_length_mS*100 #to cm # # #Get effect of intrinsic aptimeenuation for that ray (path integrated) # Q_mS=get_attenuation(f,structure,mohoS,Qexp) # # #Build the entire path term # G_mS=(I*Q_mS)/path_length_mS # # #Get conically averaged radiation pattern terms # if component=='Z': # RP_vert=conically_avg_vert_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP_vert # else: # RP=conically_avg_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS,component_angle) # RP=abs(RP) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP # # #Generate windowed time series # duration=1./fc_subfault+0.063*(dist/1000) # w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') # #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) # # #Go to frequency domain, apply amplitude spectrum and ifft for final time series # hf_seis=apply_spectrum(w,A,f,hf_dt) # # #What time after OT should this time series start at? # time_insert=mohoS.path['time'][-1]+onset_times[kfault] # #print 'ts = '+str(time_insert)+' , Td = '+str(duration) # #time_insert=Ppaths[0].path['time'][-1] # i=argmin(abs(t-time_insert)) # j=i+len(hf_seis) # # #Add seismogram # hf[i:j]=hf[i:j]+hf_seis # # #Done, reset # mohoS=None # if kfault==0: # out=''' More: # fc_scale = %10.4f # subfaultM0 = %E # mu = %E # CS = %E # CP = %E # vr = %10.4f # dip_factor = %10.4f # fc_subfault = %10.4f # directS = %s # directP = %s # '''%(fc_scale,subfault_M0[kfault],mu,CS,CP,vr,dip_factor,fc_subfault,str(directS.time),str(directP.time)) # print out # logfile.write(out) # logfile.close() #Done tr.data = hf / 100 #convert to m/s**2 #Add station location, event location, and first P-wave arrival time to SAC header tr.stats.update({ 'sac': { 'stlo': sta_lon, 'stla': sta_lat, 'evlo': epicenter[0], 'evla': epicenter[1], 'evdp': epicenter[2], 'dist': dist_in_km, 'az': az, 'baz': backaz, 'mag': Mw } }) #,'idep':"ACC (m/s^2)" not sure why idep won't work #Return trace for writing to file # print "Earliest P wave Comes at " + str(earliestP) + "after OT, from location " + str(fault[earliestP_kfault,1]) + ", " + str(fault[earliestP_kfault,2]) + ", " +str(fault[earliestP_kfault,3]) return tr
def stochastic_simulation(home,project_name,rupture_name,sta,sta_lon,sta_lat,component,model_name, rise_time_depths,moho_depth_in_km,total_duration=100,hf_dt=0.01,stress_parameter=50, kappa=0.04,Qexp=0.6,Pwave=False,high_stress_depth=1e4): ''' Run stochastic HF sims stress parameter is in bars ''' from numpy import genfromtxt,pi,logspace,log10,mean,where,exp,arange,zeros,argmin,rad2deg,arctan2,real from pyproj import Geod from obspy.geodetics import kilometer2degrees from obspy.taup import TauPyModel from mudpy.forward import get_mu, write_fakequakes_hf_waveforms_one_by_one,read_fakequakes_hypo_time from obspy import Stream,Trace from sys import stdout import warnings #print out what's going on: out='''Running with input parameters: home = %s project_name = %s rupture_name = %s sta = %s sta_lon = %s sta_lat = %s model_name = %s rise_time_depths = %s moho_depth_in_km = %s total_duration = %s hf_dt = %s stress_parameter = %s kappa = %s Qexp = %s component = %s Pwave = %s high_stress_depth = %s '''%(home,project_name,rupture_name,sta,str(sta_lon),str(sta_lat),model_name,str(rise_time_depths), str(moho_depth_in_km),str(total_duration),str(hf_dt),str(stress_parameter), str(kappa),str(Qexp),str(component),str(Pwave),str(high_stress_depth)) print out # rupture=rupture_name.split('.')[0]+'.'+rupture_name.split('.')[1] # log=home+project_name+'/output/waveforms/'+rupture+'/'+sta+'.HN'+component+'.1cpu.log' # logfile=open(log,'w') # logfile.write(out) #print 'stress is '+str(stress_parameter) #I don't condone it but this cleans up the warnings warnings.filterwarnings("ignore") #Load the source fault=genfromtxt(home+project_name+'/output/ruptures/'+rupture_name) #Onset times for each subfault onset_times=fault[:,12] #load velocity structure structure=genfromtxt(home+project_name+'/structure/'+model_name) #Frequencies vector f=logspace(log10(hf_dt),log10(1/(2*hf_dt))+0.01,50) omega=2*pi*f #Output time vector (0 is origin time) t=arange(0,total_duration,hf_dt) #Projection object for distance calculations g=Geod(ellps='WGS84') #Create taup velocity model object, paste on top of iaspei91 #taup_create.build_taup_model(home+project_name+'/structure/bbp_norcal.tvel',output_folder=home+project_name+'/structure/') velmod=TauPyModel(model=home+project_name+'/structure/maule',verbose=True) #Get epicentral time epicenter,time_epi=read_fakequakes_hypo_time(home,project_name,rupture_name) #Moments slip=(fault[:,8]**2+fault[:,9]**2)**0.5 subfault_M0=slip*fault[:,10]*fault[:,11]*fault[:,13] subfault_M0=subfault_M0*1e7 #to dyne-cm M0=subfault_M0.sum() relative_subfault_M0=subfault_M0/M0 Mw=(2./3)*(log10(M0*1e-7)-9.1) #Corner frequency scaling i=where(slip>0)[0] #Non-zero faults N=len(i) #number of subfaults dl=mean((fault[:,10]+fault[:,11])/2) #predominant length scale dl=dl/1000 # to km #Tau=p perturbation tau_perturb=0.1 #Deep faults receive a higher stress stress_multiplier=3 print '... working on '+component+' component semistochastic waveform for station '+sta #initalize output seismogram tr=Trace() tr.stats.station=sta tr.stats.delta=hf_dt tr.stats.starttime=time_epi #info for sac header (added at the end) az,backaz,dist_m=g.inv(epicenter[0],epicenter[1],sta_lon,sta_lat) dist_in_km=dist_m/1000. hf=zeros(len(t)) # out='''Parameters before we get into subfault calculations: # rupture_name = %s # epicenter = %s # time_epi = %s # M0 = %E # Mw = %10.4f # Num_Subfaults = %i # dl = %.2f # Dist_in_km = %10.4f # '''%(rupture_name,str(epicenter),str(time_epi),M0,Mw,int(N),dl,dist_in_km) # print out # logfile.write(out) #Loop over subfaults # earliestP=1e10 #something outrageously high # earliestP_kfault=1e10 for kfault in range(len(fault)): #Print status to screen if kfault % 150 == 0: if kfault==0: stdout.write(' [') stdout.flush() stdout.write('.') stdout.flush() if kfault==len(fault)-1: stdout.write(']\n') stdout.flush() #Include only subfaults with non-zero slip if subfault_M0[kfault]>0: #Get subfault to station distance lon_source=fault[kfault,1] lat_source=fault[kfault,2] azimuth,baz,dist=g.inv(lon_source,lat_source,sta_lon,sta_lat) dist_in_degs=kilometer2degrees(dist/1000.) #Source depth? z_source=fault[kfault,3] #No change stress=stress_parameter #Is subfault in an SMGA? #radius_in_km=15.0 #smga_center_lon=-69.709200 #smga_center_lat=-19.683600 #in_smga=is_subfault_in_smga(lon_source,lat_source,smga_center_lon,smga_center_lat,radius_in_km) # ###Apply multiplier? #if in_smga==True: # stress=stress_parameter*stress_multiplier # print "%.4f,%.4f is in SMGA, stress is %d" % (lon_source,lat_source,stress) #else: # stress=stress_parameter #Apply multiplier? #if slip[kfault]>7.5: # stress=stress_parameter*stress_multiplier ##elif lon_source>-72.057 and lon_source<-71.2 and lat_source>-30.28: ## stress=stress_parameter*stress_multiplier #else: # stress=stress_parameter #Apply multiplier? #if z_source>high_stress_depth: # stress=stress_parameter*stress_multiplier #else: # stress=stress_parameter # Frankel 95 scaling of corner frequency #verified this looks the same in GP # Right now this applies the same factor to all faults fc_scale=(M0)/(N*stress*dl**3*1e21) #Frankel scaling small_event_M0 = stress*dl**3*1e21 #Get rho, alpha, beta at subfault depth zs=fault[kfault,3] mu,alpha,beta=get_mu(structure,zs,return_speeds=True) rho=mu/beta**2 #Get radiation scale factor Spartition=1/2**0.5 if component=='N' : component_angle=0 elif component=='E': component_angle=90 rho=rho/1000 #to g/cm**3 beta=(beta/1000)*1e5 #to cm/s alpha=(alpha/1000)*1e5 #Verified this produces same value as in GP CS=(2*Spartition)/(4*pi*(rho)*(beta**3)) CP=2/(4*pi*(rho)*(alpha**3)) #Get local subfault rupture speed beta=beta/100 #to m/s vr=get_local_rupture_speed(zs,beta,rise_time_depths) vr=vr/1000 #to km/s dip_factor=get_dip_factor(fault[kfault,5],fault[kfault,8],fault[kfault,9]) #Subfault corner frequency c0=2.0 #GP2015 value fc_subfault=(c0*vr)/(dip_factor*pi*dl) #get subfault source spectrum #S=((relative_subfault_M0[kfault]*M0/N)*f**2)/(1+fc_scale*(f/fc_subfault)**2) S=small_event_M0*(omega**2/(1+(f/fc_subfault)**2)) frankel_conv_operator= fc_scale*((fc_subfault**2+f**2)/(fc_subfault**2+fc_scale*f**2)) S=S*frankel_conv_operator #get high frequency decay P=exp(-pi*kappa*f) #get quarter wavelength amplificationf actors # pass rho in kg/m^3 (this units nightmare is what I get for following Graves' code) I=get_amplification_factors(f,structure,zs,beta,rho*1000) # if kfault==0: # out='''Parameters within subfault calculations: # kfault_lon = %10.4f # kfault_lat = %10.4f # CS = %s # CP = %s # S[0] = %s # frankel_conv_operator[0] = %s # '''%(fault[kfault,1],fault[kfault,2],str(CS),str(CP),str(S[0]),str(frankel_conv_operator[0])) # print out # logfile.write(out) #Get other geometric parameters necessar for radiation pattern strike=fault[kfault,4] dip=fault[kfault,5] ss=fault[kfault,8] ds=fault[kfault,9] rake=rad2deg(arctan2(ds,ss)) #Get ray paths for all direct P arrivals Ppaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['P','p']) #Get ray paths for all direct S arrivals try: Spaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['S','s']) except: Spaths=velmod.get_ray_paths(zs+tau_perturb,dist_in_degs,phase_list=['S','s']) #sometimes there's no S, weird I know. Check twice. if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+5*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-5*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+5*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-10*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+10*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-50*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+50*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-75*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+75*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: print 'ERROR: I give up, no direct S in spite of multiple attempts at subfault '+str(kfault) #Get direct s path and moho reflection mohoS=None directS=Spaths[0] directP=Ppaths[0] #print len(Spaths) if len(Spaths)==1: #only direct S pass else: #turn_depth=zeros(len(Spaths)-1) #turning depth of other non-direct rays #for k in range(1,len(Spaths)): # turn_depth[k-1]=Spaths[k].path['depth'].max() ##If there's a ray that turns within 2km of Moho, callt hat guy the Moho reflection #deltaz=abs(turn_depth-moho_depth_in_km) #i=argmin(deltaz) #if deltaz[i]<2: #Yes, this is a moho reflection # mohoS=Spaths[i+1] #else: # mohoS=None mohoS=Spaths[-1] ####### Build Direct P ray ###### if Pwave==True: take_off_angle_P=directP.takeoff_angle #Get attenuation due to geometrical spreading (from the path length) path_length_P=get_path_length(directP,zs,dist_in_degs) path_length_P=path_length_P*100 #to cm #Get effect of intrinsic attenuation for that ray (path integrated) Q_P=get_attenuation(f,structure,directS,Qexp,Qtype='P') #Build the entire path term G_P=(I*Q_P)/path_length_P #Get conically averaged radiation pattern terms RP=conically_avg_P_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_P) RP=abs(RP) #Get partition of Pwave into Z and N,E components incidence_angle=directP.incident_angle Npartition,Epartition,Zpartition=get_P_wave_partition(incidence_angle,azimuth) if component=='Z': Ppartition=Zpartition elif component=='N': Ppartition=Npartition else: Ppartition=Epartition #And finally multiply everything together to get the subfault amplitude spectrum AP=CP*S*G_P*P*RP*Ppartition #Generate windowed time series duration=1./fc_subfault+0.09*(dist/1000) w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_P=apply_spectrum(w,AP,f,hf_dt) #What time after OT should this time series start at? time_insert=directP.path['time'][-1]+onset_times[kfault] # if directP.time+onset_times[kfault] < earliestP: # earliestP=directP.time+onset_times[kfault] # earliestP_kfault=kfault i=argmin(abs(t-time_insert)) j=i+len(hf_seis_P) #Check seismogram doesn't go past last sample if i<len(hf)-1: #if i (the beginning of the seimogram) is less than the length if j>len(hf): #seismogram goes past total_duration length, trim it len_paste=len(hf)-i j=len(hf) #Add seismogram hf[i:j]=hf[i:j]+real(hf_seis_P[0:len_paste]) else: #Lengths are fine hf[i:j]=hf[i:j]+real(hf_seis_P) else: #Seismogram starts after end of available space pass ####### Build Direct S ray ###### take_off_angle_S=directS.takeoff_angle #Get attenuation due to geometrical spreading (from the path length) path_length_S=get_path_length(directS,zs,dist_in_degs) path_length_S=path_length_S*100 #to cm #Get effect of intrinsic aptimeenuation for that ray (path integrated) Q_S=get_attenuation(f,structure,directS,Qexp) #Build the entire path term G_S=(I*Q_S)/path_length_S #Get conically averaged radiation pattern terms if component=='Z': RP_vert=conically_avg_vert_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_S) #And finally multiply everything together to get the subfault amplitude spectrum AS=CS*S*G_S*P*RP_vert else: RP=conically_avg_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_S,component_angle) RP=abs(RP) #And finally multiply everything together to get the subfault amplitude spectrum AS=CS*S*G_S*P*RP #Generate windowed time series duration=1./fc_subfault+0.063*(dist/1000) w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_S=apply_spectrum(w,AS,f,hf_dt) #What time after OT should this time series start at? time_insert=directS.path['time'][-1]+onset_times[kfault] #print 'ts = '+str(time_insert)+' , Td = '+str(duration) #time_insert=Ppaths[0].path['time'][-1] i=argmin(abs(t-time_insert)) j=i+len(hf_seis_S) #Check seismogram doesn't go past last sample if i<len(hf)-1: #if i (the beginning of the seimogram) is less than the length if j>len(hf): #seismogram goes past total_duration length, trim it len_paste=len(hf)-i j=len(hf) #Add seismogram hf[i:j]=hf[i:j]+real(hf_seis_S[0:len_paste]) else: #Lengths are fine hf[i:j]=hf[i:j]+real(hf_seis_S) else: #Beginning of seismogram is past end of available space pass ####### Build Moho reflected S ray ###### # if mohoS==None: # pass # else: # if kfault%100==0: # print '... ... building Moho reflected S wave' # take_off_angle_mS=mohoS.takeoff_angle # # #Get attenuation due to geometrical spreading (from the path length) # path_length_mS=get_path_length(mohoS,zs,dist_in_degs) # path_length_mS=path_length_mS*100 #to cm # # #Get effect of intrinsic aptimeenuation for that ray (path integrated) # Q_mS=get_attenuation(f,structure,mohoS,Qexp) # # #Build the entire path term # G_mS=(I*Q_mS)/path_length_mS # # #Get conically averaged radiation pattern terms # if component=='Z': # RP_vert=conically_avg_vert_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP_vert # else: # RP=conically_avg_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS,component_angle) # RP=abs(RP) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP # # #Generate windowed time series # duration=1./fc_subfault+0.063*(dist/1000) # w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') # #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) # # #Go to frequency domain, apply amplitude spectrum and ifft for final time series # hf_seis=apply_spectrum(w,A,f,hf_dt) # # #What time after OT should this time series start at? # time_insert=mohoS.path['time'][-1]+onset_times[kfault] # #print 'ts = '+str(time_insert)+' , Td = '+str(duration) # #time_insert=Ppaths[0].path['time'][-1] # i=argmin(abs(t-time_insert)) # j=i+len(hf_seis) # # #Add seismogram # hf[i:j]=hf[i:j]+hf_seis # # #Done, reset # mohoS=None # if kfault==0: # out=''' More: # fc_scale = %10.4f # subfaultM0 = %E # mu = %E # CS = %E # CP = %E # vr = %10.4f # dip_factor = %10.4f # fc_subfault = %10.4f # directS = %s # directP = %s # '''%(fc_scale,subfault_M0[kfault],mu,CS,CP,vr,dip_factor,fc_subfault,str(directS.time),str(directP.time)) # print out # logfile.write(out) # logfile.close() #Done tr.data=hf/100 #convert to m/s**2 #Add station location, event location, and first P-wave arrival time to SAC header tr.stats.update({'sac':{'stlo':sta_lon,'stla':sta_lat,'evlo':epicenter[0],'evla':epicenter[1],'evdp':epicenter[2],'dist':dist_in_km,'az':az,'baz':backaz,'mag':Mw}}) #,'idep':"ACC (m/s^2)" not sure why idep won't work #Return trace for writing to file # print "Earliest P wave Comes at " + str(earliestP) + "after OT, from location " + str(fault[earliestP_kfault,1]) + ", " + str(fault[earliestP_kfault,2]) + ", " +str(fault[earliestP_kfault,3]) return tr
# radius of Earth in km radius = 6371. # regular time array in s, 1 s resolution time = np.arange(0., 2000.) # calculate through and save ray paths in interpolated time domain save_paths = [] for p, phase in enumerate(phases_to_plot): dists_collected = [] depths_collected = [] for r, dist in enumerate( np.arange(rays_dist_min[p], rays_dist_max[p], 1)): # resolution could be improved here # get raypaths rays = model.get_ray_paths(depth_earthquake, dist, phase_list=[phase]) # Loop through rays found, some phases have multiple paths for ray in rays: # Interpolate to regulard time array dists = np.interp(time, ray.path['time'], ray.path['dist'], left=np.nan, right=np.nan) depths = np.interp(time, ray.path['time'], ray.path['depth'], left=np.nan, right=np.nan) # save paths dists_collected.append(dists)
('p', -10), ('pP', -37.5), ('s', -3), ('sP', -49), ('ScS', -44), ('SKS', -82), ('SKKS', -120), ] model = TauPyModel(model='iasp91') fig, ax = plt.subplots(subplot_kw=dict(polar=True)) # Plot all pre-determined phases for phase, distance in PHASES: arrivals = model.get_ray_paths(700, distance, phase_list=[phase]) ax = arrivals.plot_rays(plot_type='spherical', legend=False, label_arrivals=True, plot_all=True, show=False, ax=ax) # Annotate regions ax.text(0, 0, 'Solid\ninner\ncore', horizontalalignment='center', verticalalignment='center', bbox=dict(facecolor='white', edgecolor='none', alpha=0.7)) ocr = (model.model.radius_of_planet - (model.model.s_mod.v_mod.iocb_depth + model.model.s_mod.v_mod.cmb_depth) / 2) ax.text(np.deg2rad(180), ocr, 'Fluid outer core', horizontalalignment='center', bbox=dict(facecolor='white', edgecolor='none', alpha=0.7))
FILTERLABEL, horizontalalignment='center', fontsize=10, multialignment='left', bbox=dict(boxstyle="round", facecolor='#f2f2f2', ec="0.5", pad=0.5, alpha=1)) if PLOT_PHASE_GLOBE: # Add the inset picture of the globe at x, y, width, height, as a fraction of the parent plot if plotted_arrivals: ax1 = fig1.add_axes([0.68, 0.48, 0.4, 0.4], polar=True) for phase_time, phase_name, arrival_legend, color_plot, arrival_vertline in plotted_arrivals: arrivals = model.get_ray_paths(EVT_Z, STA_DEGREES, phase_list=[phase_name]) if (len(arrivals)) > 1: m = (len(arrivals)) - 1 arrivals = arrivals[:-m or None] #If more than one of the same phase, use the earliers phase time ax1 = arrivals.plot_rays(plot_type='spherical', legend=True, label_arrivals=False, plot_all=True, show=False, ax=ax1) # Annotate regions of the globe ax1.text(0, 0,
def migrate_3d(self,window_start=-10.0,window_end=100.0,perturbation_model='none'): ''' Migrates receiver functions using a model with 3d heterogeneity. The only difference between migrate_3d and migrate_1d is that when migrate_3d calculates (time = time_phase - time_p), both time_phase and time_p have been calculated by ray tracing through a 3d model #NOTE: This only currently is intended for stations along the equator. ''' #preliminaries----------------------------------------------------------- eq_depth = self.ses3d_seismogram.sz/1000.0 dist = self.delta_deg d_start = 50.0 d_end = 800.0 dz = 5 depth = np.arange(d_start,d_end,dz) #taup model-------------------------------------------------------------- model = TauPyModel(model='pyrolite_5km') value = np.zeros((len(depth))) #read velocity perturbation model---------------------------------------- # note, the specific shape of the input arrays are taken to # match the output of velocity_conversion.py #------------------------------------------------------------------------ to_radians = np.pi/180.0 to_degrees = 180.0/np.pi npts_theta = 201 npts_rad = 288 theta = np.linspace(0,10.0*to_radians,npts_theta) rad = np.linspace(3490.0,6371.0,npts_rad) model_in = np.loadtxt(perturbation_model) #model_in = np.loadtxt(perturbation_model,skiprows=1) dvs_vector = model_in[:,6] dvp_vector = model_in[:,5] #dvs_vector = model_in[:,3] #dvp_vector = model_in[:,2] dvs_array = np.zeros((npts_theta,npts_rad)) dvp_array = np.zeros((npts_theta,npts_rad)) #define location of plume axis------------------------------------------- #TODO: change this so it's not necessary ax_theta = 45.0*to_radians #assign values from vector to array-------------------------------------- k = 0 for i in range(0,npts_rad): for j in range(0,npts_theta): dvs_array[j,i] = dvs_vector[k] dvp_array[j,i] = dvp_vector[k] k += 1 #create interpolators---------------------------------------------------- # to call the interpolators, give theta in radians and radius in km # where theta is the arc distance from a point to the plume axis #------------------------------------------------------------------------ dvs_interpolator = interp2d(rad,theta,dvs_array,fill_value=0.0) dvp_interpolator = interp2d(rad,theta,dvp_array,fill_value=0.0) #calculate P travel time (only need to do once)-------------------------- p_path = model.get_ray_paths(eq_depth,dist,phase_list=['P']) p_path = p_path[0] p_ref = p_path.time p_ray_dist = p_path.path['dist'] p_ray_depth = p_path.path['depth'] p_ray_time = p_path.path['time'] #interpolate p path------------------------------------------------------ i_len = 2000 ray_dist_new = np.linspace(0,p_ray_dist[(len(p_ray_dist)-1)],i_len) #time f = interp1d(p_ray_dist, p_ray_time) p_ray_time = f(ray_dist_new) #depth f = interp1d(p_ray_dist, p_ray_depth) p_ray_depth = f(ray_dist_new) p_ray_dist = ray_dist_new p_time_total = 0.0 path_len_total = 0.0 #integrate along P path to determine time-------------------------------- for i in range(0,len(p_ray_dist)-1): r_1 = 6371.0-p_ray_depth[i] r_2 = 6371.0-p_ray_depth[i+1] theta_1 = p_ray_dist[i] theta_2 = p_ray_dist[i+1] ray_seg_len = np.sqrt(r_1**2 + r_2**2 - 2*r_1*r_2*np.cos(theta_2-theta_1)) time_seg = p_ray_time[i+1] - p_ray_time[i] ray_seg_vel = ray_seg_len / time_seg #get heterogeneity for the current ray segment arc_dist1 = np.abs(ax_theta - theta_1) arc_dist2 = np.abs(ax_theta - theta_2) dv_1 = dvp_interpolator(r_1,arc_dist1) dv_2 = dvp_interpolator(r_2,arc_dist2) dv_here = (dv_1+dv_2)/2.0 #add time------------------------------------------------------------- #if using absolute velocity perturbations time_here = ray_seg_len / (ray_seg_vel + dv_here) #if using percente velocity perturbations plume_velocity = ray_seg_vel + ray_seg_vel*(dv_here/100.0) time_here = ray_seg_len / plume_velocity p_time_total += time_here path_len_total += ray_seg_len #calculate each pds time------------------------------------------------- for i in range(0,len(depth)): #get path data phase = 'P'+str(depth[i])+'s' pds_path = model.get_ray_paths(eq_depth,dist,phase_list=[phase]) pds_path = pds_path[0] pds_ray_dist = pds_path.path['dist'] pds_ray_depth = pds_path.path['depth'] pds_ray_time = pds_path.path['time'] #interpolate pds path---------------------------------------------------- i_len = 500 ray_dist_new = np.linspace(0,pds_ray_dist[(len(pds_ray_dist)-1)],i_len) #time f = interp1d(pds_ray_dist, pds_ray_time) pds_ray_time = f(ray_dist_new) #depth f = interp1d(pds_ray_dist, pds_ray_depth) pds_ray_depth = f(ray_dist_new) pds_ray_dist = ray_dist_new pds_time_total = 0.0 for j in range(0,len(pds_ray_dist)-1): r_1 = 6371.0-pds_ray_depth[j] r_2 = 6371.0-pds_ray_depth[j+1] theta_1 = pds_ray_dist[j] theta_2 = pds_ray_dist[j+1] time_seg = pds_ray_time[j+1] - pds_ray_time[j] ray_seg_len = np.sqrt(r_1**2 + r_2**2 - 2*r_1*r_2*np.cos(theta_2-theta_1)) ray_seg_vel = ray_seg_len / time_seg #get heterogeneity for the current ray segment arc_dist1 = np.abs(ax_theta - theta_1) arc_dist2 = np.abs(ax_theta - theta_2) #determine branch if ray_seg_vel < 8.0: dv_1 = dvs_interpolator(r_1,arc_dist1) dv_2 = dvs_interpolator(r_2,arc_dist2) dv_here = (dv_1+dv_2)/2.0 elif ray_seg_vel >= 8.0: dv_1 = dvp_interpolator(r_1,arc_dist1) dv_2 = dvp_interpolator(r_2,arc_dist2) dv_here = (dv_1+dv_2)/2.0 #add time---------------------------------------------------------- #if using absolute velocity perturbations time_here = ray_seg_len / (ray_seg_vel + dv_here) #if using percente velocity perturbations #plume_velocity = ray_seg_vel + ray_seg_vel*(dv_here/100.0) #time_here = ray_seg_len / plume_velocity pds_time_total += time_here path_len_total += ray_seg_len delay = pds_time_total-p_time_total #print "P time, Pds time, delay: ",phase,p_time_total,pds_time_total,delay #print "Predicted arrival times and delay :", p_path.time, pds_path.time, (pds_path.time-p_path.time) pds_delay = pds_time_total - pds_path.time print phase, pds_delay #map value at t = (p_time - pds_time) to depth------------------------ i_start = int((0.0 - window_start)/self.ses3d_seismogram.dt) i_t = int(delay/self.ses3d_seismogram.dt) + i_start print i_t self.pierce_dict[i]['value'] = self.prf[i_t]
def stochastic_simulation(home,project_name,rupture_name,GF_list,time_epi,model_name, rise_time_depths,moho_depth_in_km,total_duration=100,hf_dt=0.01,stress_parameter=50, kappa=0.04,Qexp=0.6,component='N',Pwave=False): ''' Run stochastic HF sims stress parameter is in bars ''' from numpy import genfromtxt,pi,logspace,log10,mean,where,exp,arange,zeros,argmin,rad2deg,arctan2 from pyproj import Geod from obspy.geodetics import kilometer2degrees from obspy.taup import taup_create,TauPyModel from mudpy.forward import get_mu from obspy import Stream,Trace from matplotlib import pyplot as plt #initalize output object st=Stream() #Load the source fault=genfromtxt(home+project_name+'/output/ruptures/'+rupture_name) #Onset times for each subfault onset_times=fault[:,12] #Load stations sta=genfromtxt(home+project_name+'/data/station_info/'+GF_list,usecols=[0],dtype='S') lonlat=genfromtxt(home+project_name+'/data/station_info/'+GF_list,usecols=[1,2]) #load velocity structure structure=genfromtxt(home+project_name+'/structure/'+model_name) #Frequencies vector f=logspace(log10(hf_dt),log10(1/(2*hf_dt))+0.01,50) omega=2*pi*f #Output time vector (0 is origin time) t=arange(0,total_duration,hf_dt) #Projection object for distance calculations g=Geod(ellps='WGS84') #Create taup velocity model object, paste on top of iaspei91 #taup_create.build_taup_model(home+project_name+'/structure/bbp_norcal.tvel',output_folder=home+project_name+'/structure/') velmod=TauPyModel(model=home+project_name+'/structure/bbp_norcal',verbose=True) #Moments slip=(fault[:,8]**2+fault[:,9]**2)**0.5 subfault_M0=slip*fault[:,10]*fault[:,11]*fault[:,13] subfault_M0=subfault_M0*1e7 #to dyne-cm M0=subfault_M0.sum() relative_subfault_M0=subfault_M0/M0 #Corner frequency scaling i=where(slip>0)[0] #Non-zero faults N=len(i) #number of subfaults dl=mean((fault[:,10]+fault[:,11])/2) #perdominant length scale dl=dl/1000 # to km # Frankel 95 scaling of corner frequency #verified this looks the same in GP # Right now this applies the same factor to all faults # Move inside the loop with right dl???? fc_scale=(M0)/(N*stress_parameter*dl**3*1e21) #Frankel scaling #Move this inisde loop? small_event_M0 = stress_parameter*dl**3*1e21 #Tau=p perturbation tau_perturb=0.1 #Loop over stations for ksta in range(len(lonlat)): print '... working on '+component+' component semistochastic waveform for station '+sta[ksta] #initalize output seismogram tr=Trace() tr.stats.station=sta[ksta] tr.stats.delta=hf_dt tr.stats.starttime=time_epi hf=zeros(len(t)) #Loop over subfaults for kfault in range(len(fault)): #Include only subfaults with non-zero slip if subfault_M0[kfault]>0: #Get subfault to station distance lon_source=fault[kfault,1] lat_source=fault[kfault,2] azimuth,baz,dist=g.inv(lon_source,lat_source,lonlat[ksta,0],lonlat[ksta,1]) dist_in_degs=kilometer2degrees(dist/1000.) #Get rho, alpha, beta at subfault depth zs=fault[kfault,3] mu,alpha,beta=get_mu(structure,zs,return_speeds=True) rho=mu/beta**2 #Get radiation scale factor Spartition=1/2**0.5 if component=='N' : component_angle=0 elif component=='E': component_angle=90 rho=rho/1000 #to g/cm**3 beta=(beta/1000)*1e5 #to cm/s alpha=(alpha/1000)*1e5 #Verified this produces same value as in GP CS=(2*Spartition)/(4*pi*(rho)*(beta**3)) CP=2/(4*pi*(rho)*(alpha**3)) #Get local subfault rupture speed beta=beta/100 #to m/s vr=get_local_rupture_speed(zs,beta,rise_time_depths) vr=vr/1000 #to km/s dip_factor=get_dip_factor(fault[kfault,5],fault[kfault,8],fault[kfault,9]) #Subfault corner frequency c0=2.0 #GP2015 value fc_subfault=(c0*vr)/(dip_factor*pi*dl) #get subfault source spectrum #S=((relative_subfault_M0[kfault]*M0/N)*f**2)/(1+fc_scale*(f/fc_subfault)**2) S=small_event_M0*(omega**2/(1+(f/fc_subfault)**2)) frankel_conv_operator= fc_scale*((fc_subfault**2+f**2)/(fc_subfault**2+fc_scale*f**2)) S=S*frankel_conv_operator #get high frequency decay P=exp(-pi*kappa*f) #get quarter wavelength amplificationf actors # pass rho in kg/m^3 (this units nightmare is what I get for following Graves' code) I=get_amplification_factors(f,structure,zs,beta,rho*1000) #Get other geometric parameters necessar for radiation pattern strike=fault[kfault,4] dip=fault[kfault,5] ss=fault[kfault,8] ds=fault[kfault,9] rake=rad2deg(arctan2(ds,ss)) #Get ray paths for all direct S arrivals Ppaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['P','p']) #Get ray paths for all direct S arrivals try: Spaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['S','s']) except: Spaths=velmod.get_ray_paths(zs+tau_perturb,dist_in_degs,phase_list=['S','s']) #Get direct s path and moho reflection mohoS=None directS=Spaths[0] directP=Ppaths[0] #print len(Spaths) if len(Spaths)==1: #only direct S pass else: #turn_depth=zeros(len(Spaths)-1) #turning depth of other non-direct rays #for k in range(1,len(Spaths)): # turn_depth[k-1]=Spaths[k].path['depth'].max() ##If there's a ray that turns within 2km of Moho, callt hat guy the Moho reflection #deltaz=abs(turn_depth-moho_depth_in_km) #i=argmin(deltaz) #if deltaz[i]<2: #Yes, this is a moho reflection # mohoS=Spaths[i+1] #else: # mohoS=None mohoS=Spaths[-1] ####### Build Direct P ray ###### if Pwave==True: take_off_angle_P=directP.takeoff_angle #Get attenuation due to geometrical spreading (from the path length) path_length_P=get_path_length(directP,zs,dist_in_degs) path_length_P=path_length_P*100 #to cm #Get effect of intrinsic aptimeenuation for that ray (path integrated) Q_P=get_attenuation(f,structure,directS,Qexp,Qtype='P') #Build the entire path term G_P=(I*Q_P)/path_length_P #Get conically averaged radiation pattern terms RP=conically_avg_P_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_P) RP=abs(RP) #Get partition of Pwave into Z and N,E components incidence_angle=directP.incident_angle Npartition,Epartition,Zpartition=get_P_wave_partition(incidence_angle,azimuth) if component=='Z': Ppartition=Zpartition elif component=='N': Ppartition=Npartition else: Ppartition=Epartition #And finally multiply everything together to get the subfault amplitude spectrum AP=CP*S*G_P*P*RP*Ppartition #Generate windowed time series duration=1./fc_subfault+0.09*(dist/1000) w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_P=apply_spectrum(w,AP,f,hf_dt) #What time after OT should this time series start at? time_insert=directP.path['time'][-1]+onset_times[kfault] i=argmin(abs(t-time_insert)) j=i+len(hf_seis_P) #Add seismogram hf[i:j]=hf[i:j]+hf_seis_P ####### Build Direct S ray ###### take_off_angle_S=directS.takeoff_angle #Get attenuation due to geometrical spreading (from the path length) path_length_S=get_path_length(directS,zs,dist_in_degs) path_length_S=path_length_S*100 #to cm #Get effect of intrinsic aptimeenuation for that ray (path integrated) Q_S=get_attenuation(f,structure,directS,Qexp) #Build the entire path term G_S=(I*Q_S)/path_length_S #Get conically averaged radiation pattern terms if component=='Z': RP_vert=conically_avg_vert_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_S) #And finally multiply everything together to get the subfault amplitude spectrum AS=CS*S*G_S*P*RP_vert else: RP=conically_avg_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_S,component_angle) RP=abs(RP) #And finally multiply everything together to get the subfault amplitude spectrum AS=CS*S*G_S*P*RP #Generate windowed time series duration=1./fc_subfault+0.063*(dist/1000) w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_S=apply_spectrum(w,AS,f,hf_dt) #What time after OT should this time series start at? time_insert=directS.path['time'][-1]+onset_times[kfault] #print 'ts = '+str(time_insert)+' , Td = '+str(duration) #time_insert=Ppaths[0].path['time'][-1] i=argmin(abs(t-time_insert)) j=i+len(hf_seis_S) #Add seismogram hf[i:j]=hf[i:j]+hf_seis_S ####### Build Moho reflected S ray ###### # if mohoS==None: # pass # else: # if kfault%100==0: # print '... ... building Moho reflected S wave' # take_off_angle_mS=mohoS.takeoff_angle # # #Get attenuation due to geometrical spreading (from the path length) # path_length_mS=get_path_length(mohoS,zs,dist_in_degs) # path_length_mS=path_length_mS*100 #to cm # # #Get effect of intrinsic aptimeenuation for that ray (path integrated) # Q_mS=get_attenuation(f,structure,mohoS,Qexp) # # #Build the entire path term # G_mS=(I*Q_mS)/path_length_mS # # #Get conically averaged radiation pattern terms # if component=='Z': # RP_vert=conically_avg_vert_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP_vert # else: # RP=conically_avg_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS,component_angle) # RP=abs(RP) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP # # #Generate windowed time series # duration=1./fc_subfault+0.063*(dist/1000) # w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') # #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) # # #Go to frequency domain, apply amplitude spectrum and ifft for final time series # hf_seis=apply_spectrum(w,A,f,hf_dt) # # #What time after OT should this time series start at? # time_insert=mohoS.path['time'][-1]+onset_times[kfault] # #print 'ts = '+str(time_insert)+' , Td = '+str(duration) # #time_insert=Ppaths[0].path['time'][-1] # i=argmin(abs(t-time_insert)) # j=i+len(hf_seis) # # #Add seismogram # hf[i:j]=hf[i:j]+hf_seis # # #Done, reset # mohoS=None #Done add to trace and stream tr.data=hf/100 #convert to m/s**2 st+=tr return st
def run_parallel_hfsims(home,project_name,rupture_name,N,M0,sta,sta_lon,sta_lat,component,model_name, rise_time_depths0,rise_time_depths1,moho_depth_in_km,total_duration, hf_dt,stress_parameter,kappa,Qexp,Pwave,Swave,high_stress_depth, Qmethod,scattering,Qc_exp,baseline_Qc,rank,size): ''' Run stochastic HF sims stress parameter is in bars ''' from numpy import genfromtxt,pi,logspace,log10,mean,where,exp,arange,zeros,argmin,rad2deg,arctan2,real,savetxt,c_ from pyproj import Geod from obspy.geodetics import kilometer2degrees from obspy.taup import TauPyModel from mudpy.forward import get_mu, read_fakequakes_hypo_time from mudpy import hfsims from obspy import Stream,Trace from sys import stdout from os import path,makedirs from mudpy.hfsims import is_subfault_in_smga import warnings rank=int(rank) if rank==0 and component=='N': #print out what's going on: out='''Running with input parameters: home = %s project_name = %s rupture_name = %s N = %s M0 (N-m) = %s sta = %s sta_lon = %s sta_lat = %s model_name = %s rise_time_depths = %s moho_depth_in_km = %s total_duration = %s hf_dt = %s stress_parameter = %s kappa = %s Qexp = %s component = %s Pwave = %s Swave = %s high_stress_depth = %s Qmethod = %s scattering = %s Qc_exp = %s baseline_Qc = %s '''%(home,project_name,rupture_name,str(N),str(M0/1e7),sta,str(sta_lon),str(sta_lat),model_name,str([rise_time_depths0,rise_time_depths1]), str(moho_depth_in_km),str(total_duration),str(hf_dt),str(stress_parameter),str(kappa),str(Qexp),str(component),str(Pwave),str(Swave), str(high_stress_depth),str(Qmethod),str(scattering),str(Qc_exp),str(baseline_Qc)) print(out) if rank==0: out=''' Rupture_Name = %s Station = %s Component (N,E,Z) = %s Sample rate = %sHz Duration = %ss '''%(rupture_name,sta,component,str(1/hf_dt),str(total_duration)) print(out) #print 'stress is '+str(stress_parameter) #I don't condone it but this cleans up the warnings warnings.filterwarnings("ignore") #Fix input formats: rise_time_depths=[rise_time_depths0,rise_time_depths1] #Load the source mpi_rupt=home+project_name+'/output/ruptures/mpi_rupt.'+str(rank)+'.'+rupture_name fault=genfromtxt(mpi_rupt) #Onset times for each subfault onset_times=fault[:,12] #load velocity structure structure=genfromtxt(home+project_name+'/structure/'+model_name) #Frequencies vector f=logspace(log10(1/total_duration),log10(1/(2*hf_dt))+0.01,100) omega=2*pi*f #Output time vector (0 is origin time) t=arange(0,total_duration,hf_dt) #Projection object for distance calculations g=Geod(ellps='WGS84') #Create taup velocity model object, paste on top of iaspei91 #taup_create.build_taup_model(home+project_name+'/structure/bbp_norcal.tvel',output_folder=home+project_name+'/structure/') # velmod=TauPyModel(model=home+project_name+'/structure/iquique',verbose=True) velmod = TauPyModel(model=home+project_name+'/structure/'+model_name.split('.')[0]+'.npz') #Get epicentral time epicenter,time_epi=read_fakequakes_hypo_time(home,project_name,rupture_name) #Moments slip=(fault[:,8]**2+fault[:,9]**2)**0.5 subfault_M0=slip*fault[:,10]*fault[:,11]*fault[:,13] subfault_M0=subfault_M0*1e7 #to dyne-cm relative_subfault_M0=subfault_M0/M0 Mw=(2./3)*(log10(M0*1e-7)-9.1) #Corner frequency scaling i=where(slip>0)[0] #Non-zero faults dl=mean((fault[:,10]+fault[:,11])/2) #predominant length scale dl=dl/1000 # to km #Tau=p perturbation tau_perturb=0.1 #Deep faults receive a higher stress stress_multiplier=1 #initalize output seismogram tr=Trace() tr.stats.station=sta tr.stats.delta=hf_dt tr.stats.starttime=time_epi #info for sac header (added at the end) az,backaz,dist_m=g.inv(epicenter[0],epicenter[1],sta_lon,sta_lat) dist_in_km=dist_m/1000. hf=zeros(len(t)) #Loop over subfaults for kfault in range(len(fault)): if rank==0: #Print status to screen if kfault % 25 == 0: if kfault==0: stdout.write(' [.') stdout.flush() stdout.write('.') stdout.flush() if kfault==len(fault)-1: stdout.write('.]\n') stdout.flush() #Include only subfaults with non-zero slip if subfault_M0[kfault]>0: #Get subfault to station distance lon_source=fault[kfault,1] lat_source=fault[kfault,2] azimuth,baz,dist=g.inv(lon_source,lat_source,sta_lon,sta_lat) dist_in_degs=kilometer2degrees(dist/1000.) #Source depth? z_source=fault[kfault,3] #No change stress=stress_parameter #Is subfault in an SMGA? #SMGA1 # radius_in_km=15.0 # smga_center_lon=-71.501 # smga_center_lat=-30.918 #SMGA2 # radius_in_km=15.0 # smga_center_lon=-71.863 # smga_center_lat=-30.759 #smga3 # radius_in_km=7.5 # smga_center_lon=-72.3923 # smga_center_lat=-30.58 #smga4 # radius_in_km=7.5 # smga_center_lon=-72.3923 # smga_center_lat=-30.61 # in_smga=is_subfault_in_smga(lon_source,lat_source,smga_center_lon,smga_center_lat,radius_in_km) # ###Apply multiplier? # if in_smga==True: # stress=stress_parameter*stress_multiplier # print("%.4f,%.4f is in SMGA, stress is %d" % (lon_source,lat_source,stress)) # else: # stress=stress_parameter #Apply multiplier? #if slip[kfault]>7.5: # stress=stress_parameter*stress_multiplier ##elif lon_source>-72.057 and lon_source<-71.2 and lat_source>-30.28: ## stress=stress_parameter*stress_multiplier #else: # stress=stress_parameter #Apply multiplier? #if z_source>high_stress_depth: # stress=stress_parameter*stress_multiplier #else: # stress=stress_parameter # Frankel 95 scaling of corner frequency #verified this looks the same in GP # Right now this applies the same factor to all faults fc_scale=(M0)/(N*stress*dl**3*1e21) #Frankel scaling small_event_M0 = stress*dl**3*1e21 #Get rho, alpha, beta at subfault depth zs=fault[kfault,3] mu,alpha,beta=get_mu(structure,zs,return_speeds=True) rho=mu/beta**2 #Get radiation scale factor Spartition=1/2**0.5 if component=='N' : component_angle=0 elif component=='E': component_angle=90 rho=rho/1000 #to g/cm**3 beta=(beta/1000)*1e5 #to cm/s alpha=(alpha/1000)*1e5 # print('rho = '+str(rho)) # print('beta = '+str(beta)) # print('alpha = '+str(alpha)) #Verified this produces same value as in GP CS=(2*Spartition)/(4*pi*(rho)*(beta**3)) CP=2/(4*pi*(rho)*(alpha**3)) #Get local subfault rupture speed beta=beta/100 #to m/s vr=hfsims.get_local_rupture_speed(zs,beta,rise_time_depths) vr=vr/1000 #to km/s dip_factor=hfsims.get_dip_factor(fault[kfault,5],fault[kfault,8],fault[kfault,9]) #Subfault corner frequency c0=2.0 #GP2015 value fc_subfault=(c0*vr)/(dip_factor*pi*dl) #get subfault source spectrum #S=((relative_subfault_M0[kfault]*M0/N)*f**2)/(1+fc_scale*(f/fc_subfault)**2) S=small_event_M0*(omega**2/(1+(f/fc_subfault)**2)) frankel_conv_operator= fc_scale*((fc_subfault**2+f**2)/(fc_subfault**2+fc_scale*f**2)) S=S*frankel_conv_operator #get high frequency decay P=exp(-pi*kappa*f) #Get other geometric parameters necessar for radiation pattern strike=fault[kfault,4] dip=fault[kfault,5] ss=fault[kfault,8] ds=fault[kfault,9] rake=rad2deg(arctan2(ds,ss)) #Get ray paths for all direct P arrivals Ppaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['P','p']) #Get ray paths for all direct S arrivals try: Spaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['S','s']) except: Spaths=velmod.get_ray_paths(zs+tau_perturb,dist_in_degs,phase_list=['S','s']) #sometimes there's no S, weird I know. Check twice. if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+5*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-5*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+5*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-10*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+10*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-50*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+50*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs-75*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: Spaths=velmod.get_ray_paths(zs+75*tau_perturb,dist_in_degs,phase_list=['S','s']) if len(Spaths)==0: print('ERROR: I give up, no direct S in spite of multiple attempts at subfault '+str(kfault)) #Which ray should I keep? #This is the fastest arriving P directP=Ppaths[0] #Get moho depth from velmod moho_depth = velmod.model.moho_depth # In this method here are the rules: #For S do not allow Moho turning rays, keep the fastest non Moho turning ray. If #only Moho rays are available, then keep the one that turns the shallowest. if Qmethod == 'no_moho': #get turning depths and arrival times of S rays turning_depths = zeros(len(Spaths)) S_ray_times = zeros(len(Spaths)) for kray in range(len(Spaths)): turning_depths[kray] = Spaths[kray].path['depth'].max() S_ray_times[kray] = Spaths[kray].path['time'].max() #Keep only rays that turn above Moho i=where(turning_depths < moho_depth)[0] if len(i) == 0: #all rays turn below Moho, keep shallowest turning i_min_depth = argmin(turning_depths) directS = Spaths[i_min_depth] else: #Keep fastest arriving ray that turns above Moho Spaths = [Spaths[j] for j in i] #Rays turning above Moho, NOTE: I hate list comprehension S_ray_times = S_ray_times[i] i_min_time = argmin(S_ray_times) directS = Spaths[i_min_time] elif Qmethod =='shallowest': #get turning depths and arrival times of S rays turning_depths = zeros(len(Spaths)) for kray in range(len(Spaths)): turning_depths[kray] = Spaths[kray].path['depth'].max() i_min_depth = argmin(turning_depths) directS = Spaths[i_min_depth] elif Qmethod == 'fastest' or Qmethod=='direct': #Pick first arriving S wave directS = Spaths[0] #directS=Spaths[0] #this is the old way, kept fastest S mohoS=None # #print len(Spaths) # if len(Spaths)==1: #only direct S # pass # else: # #turn_depth=zeros(len(Spaths)-1) #turning depth of other non-direct rays # #for k in range(1,len(Spaths)): # # turn_depth[k-1]=Spaths[k].path['depth'].max() # ##If there's a ray that turns within 2km of Moho, callt hat guy the Moho reflection # #deltaz=abs(turn_depth-moho_depth_in_km) # #i=argmin(deltaz) # #if deltaz[i]<2: #Yes, this is a moho reflection # # mohoS=Spaths[i+1] # #else: # # mohoS=None # mohoS=Spaths[-1] ####### Build Direct P ray ###### if Pwave==True: take_off_angle_P=directP.takeoff_angle # #Get attenuation due to geometrical spreading (from the path length) # path_length_P=hfsims.get_path_length(directP,zs,dist_in_degs) # path_length_P=path_length_P*100 #to cm # #Get effect of intrinsic attenuation for that ray (path integrated) # #Q_P=hfsims.get_attenuation(f,structure,directP,Qexp,Qtype='P') <- This causes problems and I don't know why underlying assumptions might be bad # Q_P=hfsims.get_attenuation(f,structure,directS,Qexp,Qtype='S') # #get quarter wavelength amplificationf actors # # pass rho in kg/m^3 (this units nightmare is what I get for following Graves' code) # I_P=hfsims.get_amplification_factors(f,structure,zs,alpha,rho*1000) # #Build the entire path term # G_P=(I_P*Q_P)/path_length_P #Get attenuation due to geometrical spreading (from the path length) path_length_S=hfsims.get_path_length(directS,zs,dist_in_degs) path_length_S=path_length_S*100 #to cm #Get effect of intrinsic aptimeenuation for that ray (path integrated) Q_S=hfsims.get_attenuation(f,structure,directS,Qexp) #get quarter wavelength amplificationf actors # pass rho in kg/m^3 (this units nightmare is what I get for following Graves' code) I_S=hfsims.get_amplification_factors(f,structure,zs,beta,rho*1000) #Build the entire path term # G_S=(I_S*Q_S)/path_length_S G_S=(1*Q_S)/path_length_S #Get conically averaged radiation pattern terms RP=hfsims.conically_avg_P_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_P) RP=abs(RP) #Get partition of Pwave into Z and N,E components incidence_angle=directP.incident_angle Npartition,Epartition,Zpartition=hfsims.get_P_wave_partition(incidence_angle,azimuth) if component=='Z': Ppartition=Zpartition elif component=='N': Ppartition=Npartition else: Ppartition=Epartition #And finally multiply everything together to get the subfault amplitude spectrum AP=CP*S*G_S*P*RP*Ppartition #Generate windowed time series duration=1./fc_subfault+0.09*(dist/1000) w=hfsims.windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_P=hfsims.apply_spectrum(w,AP,f,hf_dt) #save thigns to check # if sta=='AL2H': # path_out = '/Users/dmelgarm/FakeQuakes/ONC_debug/analysis/frequency/Pwave/' # path_out = path_out+str(kfault) # # savetxt(path_out+'.all',c_[f,AP]) # # savetxt(path_out+'.source',c_[f,CP*S]) # # savetxt(path_out+'.path',c_[f,G_P]) # # savetxt(path_out+'.site',c_[f,P]) #What time after OT should this time series start at? time_insert=directP.path['time'][-1]+onset_times[kfault] i=argmin(abs(t-time_insert)) j=i+len(hf_seis_P) #Check seismogram doesn't go past last sample if i<len(hf)-1: #if i (the beginning of the seimogram) is less than the length if j>len(hf): #seismogram goes past total_duration length, trim it len_paste=len(hf)-i j=len(hf) #Add seismogram hf[i:j]=hf[i:j]+real(hf_seis_P[0:len_paste]) else: #Lengths are fine hf[i:j]=hf[i:j]+real(hf_seis_P) else: #Seismogram starts after end of available space pass ####### Build Direct S ray ###### if Swave==True: take_off_angle_S=directS.takeoff_angle #Get attenuation due to geometrical spreading (from the path length) path_length_S=hfsims.get_path_length(directS,zs,dist_in_degs) path_length_S=path_length_S*100 #to cm #Get effect of intrinsic aptimeenuation for that ray (path integrated) if Qmethod == 'direct':#No ray tracing use bulka ttenuation along path Q_S = hfsims.get_attenuation_linear(f,structure,zs,dist,Qexp,Qtype='S') else: #Use ray tracing Q_S=hfsims.get_attenuation(f,structure,directS,Qexp,scattering=scattering, Qc_exp=Qc_exp,baseline_Qc=baseline_Qc) #get quarter wavelength amplificationf actors # pass rho in kg/m^3 (this units nightmare is what I get for following Graves' code) I_S=hfsims.get_amplification_factors(f,structure,zs,beta,rho*1000) #Build the entire path term G_S=(I_S*Q_S)/path_length_S # G_S=(1*Q_S)/path_length_S #Get conically averaged radiation pattern terms if component=='Z': RP_vert=hfsims.conically_avg_vert_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_S) #And finally multiply everything together to get the subfault amplitude spectrum AS=CS*S*G_S*P*RP_vert # print('... RP_vert = '+str(RP_vert)) else: RP=hfsims.conically_avg_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_S,component_angle) RP=abs(RP) # print('... RP_horiz = '+str(RP)) #And finally multiply everything together to get the subfault amplitude spectrum AS=CS*S*G_S*P*RP #Generate windowed time series duration=1./fc_subfault+0.063*(dist/1000) w=hfsims.windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) #Go to frequency domain, apply amplitude spectrum and ifft for final time series hf_seis_S=hfsims.apply_spectrum(w,AS,f,hf_dt) #save thigns to check # if sta=='AL2H': # path_out = '/Users/dmelgarm/FakeQuakes/ONC_debug/analysis/frequency/Swave/' # path_out = path_out+str(kfault) # # savetxt(path_out+'.soverp',c_[f,(CS*S)/(CP*S)]) # savetxt(path_out+'.all',c_[f,AS]) # savetxt(path_out+'.source',c_[f,CS*S]) # savetxt(path_out+'.path',c_[f,G_S]) # savetxt(path_out+'.site',c_[f,P]) #What time after OT should this time series start at? time_insert=directS.path['time'][-1]+onset_times[kfault] #print 'ts = '+str(time_insert)+' , Td = '+str(duration) #time_insert=Ppaths[0].path['time'][-1] i=argmin(abs(t-time_insert)) j=i+len(hf_seis_S) #Check seismogram doesn't go past last sample if i<len(hf)-1: #if i (the beginning of the seimogram) is less than the length if j>len(hf): #seismogram goes past total_duration length, trim it len_paste=len(hf)-i j=len(hf) #Add seismogram hf[i:j]=hf[i:j]+real(hf_seis_S[0:len_paste]) else: #Lengths are fine hf[i:j]=hf[i:j]+real(hf_seis_S) else: #Beginning of seismogram is past end of available space pass ####### Build Moho reflected S ray ###### # if mohoS==None: # pass # else: # if kfault%100==0: # print '... ... building Moho reflected S wave' # take_off_angle_mS=mohoS.takeoff_angle # # #Get attenuation due to geometrical spreading (from the path length) # path_length_mS=get_path_length(mohoS,zs,dist_in_degs) # path_length_mS=path_length_mS*100 #to cm # # #Get effect of intrinsic aptimeenuation for that ray (path integrated) # Q_mS=get_attenuation(f,structure,mohoS,Qexp) # # #Build the entire path term # G_mS=(I*Q_mS)/path_length_mS # # #Get conically averaged radiation pattern terms # if component=='Z': # RP_vert=conically_avg_vert_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP_vert # else: # RP=conically_avg_radiation_pattern(strike,dip,rake,azimuth,take_off_angle_mS,component_angle) # RP=abs(RP) # #And finally multiply everything together to get the subfault amplitude spectrum # A=C*S*G_mS*P*RP # # #Generate windowed time series # duration=1./fc_subfault+0.063*(dist/1000) # w=windowed_gaussian(duration,hf_dt,window_type='saragoni_hart') # #w=windowed_gaussian(3*duration,hf_dt,window_type='cua',ptime=Ppaths[0].path['time'][-1],stime=Spaths[0].path['time'][-1]) # # #Go to frequency domain, apply amplitude spectrum and ifft for final time series # hf_seis=apply_spectrum(w,A,f,hf_dt) # # #What time after OT should this time series start at? # time_insert=mohoS.path['time'][-1]+onset_times[kfault] # #print 'ts = '+str(time_insert)+' , Td = '+str(duration) # #time_insert=Ppaths[0].path['time'][-1] # i=argmin(abs(t-time_insert)) # j=i+len(hf_seis) # # #Add seismogram # hf[i:j]=hf[i:j]+hf_seis # # #Done, reset # mohoS=None #Done tr.data=hf/100 #convert to m/s**2 #Add station location, event location, and first P-wave arrival time to SAC header tr.stats.update({'sac':{'stlo':sta_lon,'stla':sta_lat,'evlo':epicenter[0],'evla':epicenter[1],'evdp':epicenter[2],'dist':dist_in_km,'az':az,'baz':backaz,'mag':Mw}}) #,'idep':"ACC (m/s^2)" not sure why idep won't work #Write out to file #old rupture=rupture_name.split('.')[0]+'.'+rupture_name.split('.')[1] #new rupture=rupture_name.rsplit('.',1)[0] if not path.exists(home+project_name+'/output/waveforms/'+rupture+'/'): makedirs(home+project_name+'/output/waveforms/'+rupture+'/') if rank < 10: tr.write(home+project_name+'/output/waveforms/'+rupture+'/'+sta+'.HN'+component+'.00'+str(rank)+'.sac',format='SAC') elif rank < 100: tr.write(home+project_name+'/output/waveforms/'+rupture+'/'+sta+'.HN'+component+'.0'+str(rank)+'.sac',format='SAC') else: tr.write(home+project_name+'/output/waveforms/'+rupture+'/'+sta+'.HN'+component+'.'+str(rank)+'.sac',format='SAC')
class TauPyPlottingTestCase(unittest.TestCase): """ TauPy plotting tests. """ def setUp(self): self.image_dir = os.path.join(os.path.dirname(__file__), 'images') self.model = TauPyModel(model="iasp91") def test_spherical_many_phases(self): """ Spherical plot of the ray paths for many phases for a single epicentral distance, but both ways around the globe. """ with ImageComparison(self.image_dir, "spherical_many_phases.png") as ic: self.model.get_ray_paths(500, 140).plot_rays(plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_spherical_many_phases_buried_station(self): """ Same as test_spherical_many_phases, but this time the receiver is buried. """ with ImageComparison(self.image_dir, "spherical_many_phases_buried_station.png") as ic: arrivals = self.model.get_ray_paths(500, 140, receiver_depth_in_km=1000) arrivals.plot_rays(plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_spherical_many_phases_one_way(self): """ Same as test_spherical_many_phases, but this time no phases travelling the other way around the globe are plotted. """ with ImageComparison(self.image_dir, "spherical_many_phases_one_way.png") as ic: self.model.get_ray_paths(500, 140).plot_rays(plot_type="spherical", plot_all=False, show=False) plt.savefig(ic.name) def test_spherical_more_then_360_degrees(self): """ Spherical plot with rays traveling more than 360.0 degrees. """ with ImageComparison(self.image_dir, "spherical_more_then_360.png") as ic: self.model.get_ray_paths(0, 10, phase_list=["PPPPPP"]).plot_rays( plot_type="spherical", plot_all=True, show=False, phase_list=['PPPPPP']) plt.savefig(ic.name) def test_spherical_diff_phases(self): """ Spherical plot of ``diff`` phases. """ with ImageComparison(self.image_dir, "spherical_diff_phases.png") as ic: self.model.get_ray_paths( 700, 140, phase_list=["Pdiff", "Sdiff", "pSdiff", "sSdiff", "pPdiff", "sPdiff"]).plot_rays( phase_list=["Pdiff", "Sdiff", "pSdiff", "sSdiff", "pPdiff", "sPdiff"], plot_type="spherical", legend=True, plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases(self): """ Cartesian plot of the ray paths for many phases for a single epicentral distance, but both ways around the globe. """ with ImageComparison(self.image_dir, "cartesian_many_phases.png") as ic: self.model.get_ray_paths(500, 140).plot_rays(plot_type="cartesian", plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases_buried_station(self): """ Same as test_cartesian_many_phases but this time the receiver is buried. """ with ImageComparison(self.image_dir, "cartesian_many_phases_buried_station.png") as ic: arrivals = self.model.get_ray_paths(500, 140, receiver_depth_in_km=1000) arrivals.plot_rays(plot_type="cartesian", plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases_one_way(self): """ Same as test_cartesian_many_phases but this time no phases travelling the other way around the globe are plotted. """ arrivals = self.model.get_ray_paths(500, 140) with ImageComparison(self.image_dir, "cartesian_many_phases_one_way.png") as ic: arrivals.plot_rays(plot_type="cartesian", plot_all=False, show=False) plt.savefig(ic.name) # check warning message on deprecated routine with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") with ImageComparison(self.image_dir, "cartesian_many_phases_one_way.png") as ic: # default for legend was True in legacy method arrivals.plot(plot_type="cartesian", plot_all=False, show=False, legend=False) plt.savefig(ic.name) self.assertGreaterEqual(len(w), 1) for w_ in w: try: self.assertEqual( str(w_.message), 'The plot() function is ' 'deprecated. Please use arrivals.plot_rays()') self.assertEqual(w_.category, ObsPyDeprecationWarning) except AssertionError: continue break else: raise def test_plot_travel_times(self): """ Travel time plot for many phases at a single epicentral distance. """ with ImageComparison(self.image_dir, "traveltimes_many_phases.png") as ic: self.model.get_ray_paths(10, 100, phase_list=("ttbasic",)).plot_times( show=False, legend=True) plt.savefig(ic.name) def test_plot_travel_times_convenience(self): """ Travel time plot for many phases at multiple epicentral distances, convenience function """ with ImageComparison( self.image_dir, "traveltimes_many_phases_multiple_degrees.png") as ic: # base line image looks awkward with points at the left/right end # of the plot but that's only due to the "classic" style sheet used # in tests. default mpl2 style makes room around plotted artists # larger point size to ensure plot can fail properly if points # should move mpl.rcParams['lines.markersize'] = 20 plot_travel_times(10, phase_list=("P", "S", "SKS", "PP"), min_degrees=40, max_degrees=60, show=False, legend=True, npoints=4) plt.savefig(ic.name) def _test_plot_all(plot_all): mpl.rcParams['lines.markersize'] = 200 plot_travel_times(10, phase_list=("SSS",), min_degrees=150, max_degrees=200, npoints=4, legend=False, plot_all=plot_all) # now test option plot_all=False with ImageComparison( self.image_dir, "traveltimes_plot_all_False.png") as ic: _test_plot_all(plot_all=False) plt.savefig(ic.name) # Now with option plot_all=True with ImageComparison( self.image_dir, "traveltimes_plot_all_True.png") as ic: _test_plot_all(plot_all=True) plt.savefig(ic.name) def test_ray_plot_mismatching_axes_type_warnings(self): """ Test warnings when attempting ray path plots in spherical/cartesian with bad axes type (polar/not polar). """ arrivals = self.model.get_ray_paths(500, 20, phase_list=['P']) # polar pot attempted in cartesian axes fig, ax = plt.subplots() expected_message = ("Axes instance provided for plotting with " "`plot_type='spherical'` but it seems the axes is " "not a polar axes.") try: with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") # this raises an exception as well: # "AttributeError: 'AxesSubplot' object has no attribute " # "'set_theta_zero_location'" with self.assertRaises(AttributeError): arrivals.plot_rays(plot_type="spherical", ax=ax, show=False) self.assertEqual(len(w), 1) self.assertEqual(str(w[0].message), expected_message) self.assertEqual(w[0].category, UserWarning) finally: plt.close(fig) # cartesian pot attempted in polar axes fig, ax = plt.subplots(subplot_kw=dict(projection='polar')) expected_message = ("Axes instance provided for plotting with " "`plot_type='cartesian'` but it seems the axes is " "a polar axes.") try: with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") arrivals.plot_rays(plot_type="cartesian", ax=ax, show=False) self.assertEqual(len(w), 1) self.assertEqual(str(w[0].message), expected_message) self.assertEqual(w[0].category, UserWarning) finally: plt.close(fig) def test_invalid_plot_option(self): """ Test error message when attempting ray path plots with invalid plot type """ arrivals = self.model.get_ray_paths(500, 20, phase_list=['P']) # polar plot attempted in cartesian axes expected_msg = "Plot type 'spam' is not a valid option." with self.assertRaisesRegexp(ValueError, expected_msg): arrivals.plot_rays(plot_type="spam")
def test_deep_source(self): # Regression test -- check if deep sources are ok model = TauPyModel("ak135") arrivals = model.get_ray_paths(2000.0, 60.0, ["P"]) assert abs(arrivals[0].time - 480.32) < 1e-2
label='twin', frameon=False) ax_left.set_theta_zero_location('N') ax_left.set_theta_direction(+1) ax_left.xaxis.set_visible(False) ax_left.yaxis.set_visible(False) # Plot all pre-determined phases for phase, distance in PHASES: if distance < 0: realdist = -distance ax = ax_left else: realdist = distance ax = ax_right arrivals = model.get_ray_paths(700, realdist, phase_list=[phase]) if not len(arrivals): print('FAIL', phase, distance) continue arrivals.plot(plot_type='spherical', plot_all=phase in PLOT_ALL, legend=False, label_arrivals=True, show=False, ax=ax) # Annotate regions ax_right.text(0, 0, 'Solid\ninner\ncore', horizontalalignment='center', verticalalignment='center', bbox=dict(facecolor='white', edgecolor='none', alpha=0.7)) ocr = (model.model.radiusOfEarth - (model.model.sMod.vMod.iocbDepth + model.model.sMod.vMod.cmbDepth) / 2) ax_right.text(np.deg2rad(180), ocr, 'Fluid outer core', horizontalalignment='center',
ax_left = fig.add_axes(ax_right.get_position(), projection="polar", label="twin", frameon=False) ax_left.set_theta_zero_location("N") ax_left.set_theta_direction(+1) ax_left.xaxis.set_visible(False) ax_left.yaxis.set_visible(False) # Plot all ray paths: for distance in DISTANCES: if distance < 0: realdist = -distance ax = ax_left else: realdist = distance ax = ax_right arrivals = model.get_ray_paths(sourcedepth, realdist, phase_list=PHASES) if not len(arrivals): # print('FAIL', PHASES, distance) continue arrivals.plot(plot_type="spherical", legend=False, label_arrivals=True, show=False, ax=ax) # Annotate regions: ax_right.text( 0, 0, "Solid\ninner\ncore", horizontalalignment="center", verticalalignment="center", bbox=dict(facecolor="white", edgecolor="none", alpha=0.7), ) ocr = model.model.radiusOfEarth - (model.model.sMod.vMod.iocbDepth + model.model.sMod.vMod.cmbDepth) / 2
Phase1arrivals = [] Phase2arrivals = [] Phase1_IA = [] Phase2_IA = [] for dist_deg in dists[:]: temparr = model.get_travel_times(source_depth_in_km=sourcedepth, distance_in_degree=dist_deg, phase_list=[phases[0]]) temparr2 = model.get_travel_times(source_depth_in_km=sourcedepth, distance_in_degree=dist_deg, phase_list=[phases2[0]]) # there may be something wrong with obpsy and plotting since the error is that the arrivals does not have the attribute for plot_rays(), see Vipul's email for another way to plot. try: somearray = model.get_ray_paths(source_depth_in_km=sourcedepth, distance_in_degree=dist_deg, phase_list=[phases[0]]) except: print('no somearray!') if len(temparr) == 0: Phase1arrivals.append(math.nan) Phase1_IA.append(math.nan) else: Phase1arrivals.append(temparr[0].time) Phase1_IA.append(temparr[0].incident_angle) if len(temparr2) == 0: Phase2arrivals.append(math.nan) Phase2_IA.append(math.nan) else:
class TauPyPlottingTestCase(unittest.TestCase): """ TauPy plotting tests. """ def setUp(self): self.image_dir = os.path.join(os.path.dirname(__file__), 'images') self.model = TauPyModel(model="iasp91") def test_spherical_many_phases(self): """ Spherical plot of the ray paths for many phases for a single epicentral distance, but both ways around the globe. """ with ImageComparison(self.image_dir, "spherical_many_phases.png") as ic: self.model.get_ray_paths(500, 140).plot_rays(plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_spherical_many_phases_buried_station(self): """ Same as test_spherical_many_phases, but this time the receiver is buried. """ with ImageComparison(self.image_dir, "spherical_many_phases_buried_station.png") as ic: arrivals = self.model.get_ray_paths(500, 140, receiver_depth_in_km=1000) arrivals.plot_rays(plot_type="spherical", plot_all=True, show=False) plt.savefig(ic.name) def test_spherical_many_phases_one_way(self): """ Same as test_spherical_many_phases, but this time no phases travelling the other way around the globe are plotted. """ with ImageComparison(self.image_dir, "spherical_many_phases_one_way.png") as ic: self.model.get_ray_paths(500, 140).plot_rays(plot_type="spherical", plot_all=False, show=False) plt.savefig(ic.name) def test_spherical_more_then_360_degrees(self): """ Spherical plot with rays traveling more than 360.0 degrees. """ with ImageComparison(self.image_dir, "spherical_more_then_360.png") as ic: self.model.get_ray_paths(0, 10, phase_list=["PPPPPP"]).plot_rays( plot_type="spherical", plot_all=True, show=False, phase_list=['PPPPPP']) plt.savefig(ic.name) def test_spherical_diff_phases(self): """ Spherical plot of ``diff`` phases. """ with ImageComparison(self.image_dir, "spherical_diff_phases.png") as ic: self.model.get_ray_paths(700, 140, phase_list=[ "Pdiff", "Sdiff", "pSdiff", "sSdiff", "pPdiff", "sPdiff" ]).plot_rays(phase_list=[ "Pdiff", "Sdiff", "pSdiff", "sSdiff", "pPdiff", "sPdiff" ], plot_type="spherical", legend=True, plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases(self): """ Cartesian plot of the ray paths for many phases for a single epicentral distance, but both ways around the globe. """ with ImageComparison(self.image_dir, "cartesian_many_phases.png") as ic: self.model.get_ray_paths(500, 140).plot_rays(plot_type="cartesian", plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases_buried_station(self): """ Same as test_cartesian_many_phases but this time the receiver is buried. """ with ImageComparison(self.image_dir, "cartesian_many_phases_buried_station.png") as ic: arrivals = self.model.get_ray_paths(500, 140, receiver_depth_in_km=1000) arrivals.plot_rays(plot_type="cartesian", plot_all=True, show=False) plt.savefig(ic.name) def test_cartesian_many_phases_one_way(self): """ Same as test_cartesian_many_phases but this time no phases travelling the other way around the globe are plotted. """ arrivals = self.model.get_ray_paths(500, 140) with ImageComparison(self.image_dir, "cartesian_many_phases_one_way.png") as ic: arrivals.plot_rays(plot_type="cartesian", plot_all=False, show=False) plt.savefig(ic.name) # check warning message on deprecated routine with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") with ImageComparison(self.image_dir, "cartesian_many_phases_one_way.png") as ic: # default for legend was True in legacy method arrivals.plot(plot_type="cartesian", plot_all=False, show=False, legend=False) plt.savefig(ic.name) self.assertGreaterEqual(len(w), 1) for w_ in w: try: self.assertEqual( str(w[0].message), 'The plot() function is ' 'deprecated. Please use arrivals.plot_rays()') except: continue break else: raise self.assertEqual(w[0].category, ObsPyDeprecationWarning) def test_plot_travel_times(self): """ Travel time plot for many phases at a single epicentral distance. """ with ImageComparison(self.image_dir, "traveltimes_many_phases.png") as ic: self.model.get_ray_paths( 10, 100, phase_list=("ttbasic", )).plot_times(show=False, legend=True) plt.savefig(ic.name) def test_plot_travel_times_convenience(self): """ Travel time plot for many phases at multiple epicentral distances, convenience function """ with ImageComparison( self.image_dir, "traveltimes_many_phases_multiple_degrees.png") as ic: # base line image looks awkward with points at the left/right end # of the plot but that's only due to the "classic" style sheet used # in tests. default mpl2 style makes room around plotted artists # larger point size to ensure plot can fail properly if points # should move mpl.rcParams['lines.markersize'] = 20 plot_travel_times(10, phase_list=("P", "S", "SKS", "PP"), min_degrees=40, max_degrees=60, show=False, legend=True, npoints=4) plt.savefig(ic.name) def _test_plot_all(plot_all): mpl.rcParams['lines.markersize'] = 200 plot_travel_times(10, phase_list=("SSS", ), min_degrees=150, max_degrees=200, npoints=4, legend=False, plot_all=plot_all) # now test option plot_all=False with ImageComparison(self.image_dir, "traveltimes_plot_all_False.png") as ic: _test_plot_all(plot_all=False) plt.savefig(ic.name) # same test should fail if plot_all=True tol = {} # adjust tolerance on Travis minimum dependency build, tolerance is set # so high for that build that image comparison can virtually never # fail.. (also adjust for matplotlib 1.2.0 on centos) if MATPLOTLIB_VERSION <= [1, 2]: tol['reltol'] = 5 tol['adjust_tolerance'] = False with self.assertRaises(ImageComparisonException): with ImageComparison(self.image_dir, "traveltimes_plot_all_False.png", no_uploads=True, **tol) as ic: _test_plot_all(plot_all=True) plt.savefig(ic.name) def test_ray_plot_mismatching_axes_type_warnings(self): """ Test warnings when attempting ray path plots in spherical/cartesian with bad axes type (polar/not polar). """ arrivals = self.model.get_ray_paths(500, 20, phase_list=['P']) # polar pot attempted in cartesian axes fig, ax = plt.subplots() expected_message = ("Axes instance provided for plotting with " "`plot_type='spherical'` but it seems the axes is " "not a polar axes.") try: with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") # this raises an exception as well: # "AttributeError: 'AxesSubplot' object has no attribute " # "'set_theta_zero_location'" with self.assertRaises(AttributeError): arrivals.plot_rays(plot_type="spherical", ax=ax, show=False) self.assertEqual(len(w), 1) self.assertEqual(str(w[0].message), expected_message) self.assertEqual(w[0].category, UserWarning) finally: plt.close(fig) # cartesian pot attempted in polar axes fig, ax = plt.subplots(subplot_kw=dict(projection='polar')) expected_message = ("Axes instance provided for plotting with " "`plot_type='cartesian'` but it seems the axes is " "a polar axes.") try: with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") arrivals.plot_rays(plot_type="cartesian", ax=ax, show=False) self.assertEqual(len(w), 1) self.assertEqual(str(w[0].message), expected_message) self.assertEqual(w[0].category, UserWarning) finally: plt.close(fig) def test_invalid_plot_option(self): """ Test error message when attempting ray path plots with invalid plot type """ arrivals = self.model.get_ray_paths(500, 20, phase_list=['P']) # polar plot attempted in cartesian axes expected_msg = "Plot type 'spam' is not a valid option." with self.assertRaisesRegexp(ValueError, expected_msg): arrivals.plot_rays(plot_type="spam")
from obspy.taup import taup_create, TauPyModel tvel = u'/Users/dmelgar/FakeQuakes/M6_validation/structure/test.tvel' out = '/Users/dmelgar/FakeQuakes/M6_validation/structure/' print 'Building model' taup_create.build_taup_model(tvel, output_folder=out) print 'Loading model' velmod = TauPyModel( model='/Users/dmelgar/FakeQuakes/M6_validation/structure/test.npz', verbose=True) print 'Getting phases' #paths=velmod.get_ray_paths(10.1,1.0,phase_list=['S','s','Sn']) #paths2=velmod.get_ray_paths(10.1,3.0,phase_list=['S','s','Sn']) paths3 = velmod.get_ray_paths(18, 0.4, phase_list=['S', 's', 'Sn', 'SmS', 'Sm']) paths3.plot(plot_type='cartesian') #paths.plot(plot_type='cartesian') #paths2.plot(plot_type='cartesian') #from obspy.taup import TauPyModel # #velmod=TauPyModel(model='iasp91') #paths=velmod.get_ray_paths(10.1,3.0,phase_list=['p','P','Pn','S','s','Sn']) #paths.plot(plot_type='cartesian')
ASH = -qL * np.cos(jS) - pL * np.sin(jS) return AP, ASV, ASH # Earth testing earth = TauPyModel(model="iasp91") etimes = earth.get_travel_times(source_depth_in_km=55, distance_in_degree=40, phase_list=["P", "S"]) print('EARTH') print(etimes) print(etimes[0].time, etimes[0].ray_param, etimes[0].incident_angle) erays = earth.get_ray_paths(source_depth_in_km=55, distance_in_degree=40, phase_list=["P", "S"]) erays.plot_rays() # move on to Mars: radius = 3389.5 mars = TauPyModel(model="TAYAK") mtimes = mars.get_travel_times(source_depth_in_km=55, distance_in_degree=40, phase_list=["P", "S"]) print('MARS') print(mtimes) print(mtimes[0].time, mtimes[0].ray_param, mtimes[0].incident_angle) # testing... #incident angle at the station
["blue"] * len(Conversion_rec) + ["green"] * len(Underside_refl_src) + ["purple"] * len(Reflection_phases)) phase_labels = { "grey": "Direct/Double/Depth phase", "red": "source side", "blue": "receiver side", "green": "underside reflection", } """ Vizualize the reflection phases """ if not os.path.exists(os.path.join(save_path, "ray_paths")): os.mkdir(os.path.join(save_path, "ray_paths")) for depth in depths: for phase in extra_phases: arrivals = model.get_ray_paths(source_depth_in_km=depth, distance_in_degree=epi, phase_list=[phase]) if not arrivals: continue ax = arrivals.plot_rays(plot_type="cartesian", show=False, legend=True) plt.savefig( os.path.join(save_path, "ray_paths", f"d_{depth}_{phase}")) plt.close() """ Define forward solver """ fwd = SS_MTI.Forward.Instaseis( instaseis_db=db, taup_model=npz_file, or_time=or_time,