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 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')
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