def get_mean_slip(target_Mw,fault_array,vel_mod): ''' Depending on the target magnitude calculate the necessary uniform slip on the fault given the 1D layered Earth velocity model ''' from numpy import genfromtxt,zeros,ones from mudpy.forward import get_mu vel=genfromtxt(vel_mod) areas=fault_array[:,8]*fault_array[:,9] mu=zeros(len(fault_array)) for k in range(len(mu)): mu[k]=get_mu(vel,fault_array[k,3]) target_moment=10**(1.5*target_Mw+9.1) mean_slip=ones(len(fault_array))*target_moment/sum(areas*mu) return mean_slip,mu
def run_syn(home, project_name, source, station_file, green_path, model_name, integrate, static, tsunami, subfault, time_epi, beta, impulse=False, okada=False, okada_mu=45e9, insar=False): ''' Use green functions and compute synthetics at stations for a single source and multiple stations. This code makes an external system call to syn.c first it will make the external call for the strike-slip component then a second externall call will be made for the dip-slip component. The unit amount of moment is 1e15 which corresponds to Mw=3.9333... IN: source: 1-row numpy array containig informaiton aboutt he source, lat, lon, depth, etc... station_file: File name with the station coordinates green_path: Directopry where GFs are stored model_file: File containing the Earth velocity structure integrate: =0 if youw ant velocity waveforms, =1 if you want displacements static: =0 if computing full waveforms, =1 if computing only the static field subfault: String indicating the subfault being worked on coord_type: =0 if problem is in cartesian coordinates, =1 if problem is in lat/lon OUT: log: Sysytem standard output and standard error for log ''' import os import subprocess from mudpy.forward import get_mu from string import rjust from numpy import array, genfromtxt, loadtxt, savetxt, log10, argmin from obspy import read from shlex import split #Constant parameters rakeDS = 90 + beta #90 is thrust, -90 is normal rakeSS = 0 + beta #0 is left lateral, 180 is right lateral tb = 50 #Number of samples before first arrival #Load structure model_file = home + project_name + '/structure/' + model_name structure = loadtxt(model_file, ndmin=2) #Parse the soruce information num = rjust(str(int(source[0])), 4, '0') xs = source[1] ys = source[2] zs = source[3] strike = source[4] dip = source[5] rise = source[6] if impulse == True: #Impulse GFs or apply rise time duration = 0 else: duration = source[7] ss_length = source[8] ds_length = source[9] ss_length_in_km = ss_length / 1000. ds_length_in_km = ds_length / 1000. strdepth = '%.4f' % zs if static == 0 and tsunami == 0: #Where to save dynamic waveforms green_path = green_path + 'dynamic/' + model_name + "_" + strdepth + ".sub" + subfault + "/" if static == 0 and tsunami == 1: #Where to save dynamic waveforms green_path = green_path + 'tsunami/' + model_name + "_" + strdepth + ".sub" + subfault + "/" print("--> Computing synthetics at stations for the source at (" + str(xs) + " , " + str(ys) + ")") staname = genfromtxt(station_file, dtype="S6", usecols=0) if staname.shape == (): #Single staiton file staname = array([staname]) #Compute distances and azimuths d, az, lon_sta, lat_sta = src2sta(station_file, source, output_coordinates=True) #Get moment corresponding to 1 meter of slip on subfault mu = get_mu(structure, zs) Mo = mu * ss_length * ds_length * 1 Mw = (2. / 3) * (log10(Mo) - 9.1) #Move to output folder log = '' #Initalize log os.chdir(green_path) for k in range(len(d)): if static == 0: #Compute full waveforms diststr = '%.3f' % d[ k] #Need current distance in string form for external call #Form the strings to be used for the system calls according to suer desired options if integrate == 1: #Make displ. #First Stike-Slip GFs commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" print commandSS #Output to screen so I know we're underway log = log + commandSS + '\n' #Append to log commandSS = split( commandSS ) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" print commandDS log = log + commandDS + '\n' commandDS = split(commandDS) else: #Make vel. #First Stike-Slip GFs commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" print commandSS log = log + commandSS + '\n' commandSS = split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" print commandDS log = log + commandDS + '\n' commandDS = split(commandDS) #Run the strike- and dip-slip commands (make system calls) p = subprocess.Popen(commandSS, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() p = subprocess.Popen(commandDS, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = p.communicate() #Result is in RTZ system (+Z is down) rotate to NEZ with +Z up and scale to m or m/s if integrate == 1: #'tis displacememnt #Strike slip if duration > 0: #Is there a source time fucntion? Yes! r = read(staname[k] + ".subfault" + num + '.SS.disp.r') t = read(staname[k] + ".subfault" + num + '.SS.disp.t') z = read(staname[k] + ".subfault" + num + '.SS.disp.z') else: #No! This is the impulse response! r = read(staname[k] + ".subfault" + num + '.SS.disp.ri') t = read(staname[k] + ".subfault" + num + '.SS.disp.ti') z = read(staname[k] + ".subfault" + num + '.SS.disp.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) #Scale to m and overwrite with rotated waveforms n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.SS.disp.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.SS.disp.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.SS.disp.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.SS.disp.r') silentremove(staname[k] + ".subfault" + num + '.SS.disp.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.SS.disp.ri') silentremove(staname[k] + ".subfault" + num + '.SS.disp.ti') silentremove(staname[k] + ".subfault" + num + '.SS.disp.zi') #Dip Slip if duration > 0: r = read(staname[k] + ".subfault" + num + '.DS.disp.r') t = read(staname[k] + ".subfault" + num + '.DS.disp.t') z = read(staname[k] + ".subfault" + num + '.DS.disp.z') else: r = read(staname[k] + ".subfault" + num + '.DS.disp.ri') t = read(staname[k] + ".subfault" + num + '.DS.disp.ti') z = read(staname[k] + ".subfault" + num + '.DS.disp.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.DS.disp.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.DS.disp.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.DS.disp.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.DS.disp.r') silentremove(staname[k] + ".subfault" + num + '.DS.disp.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.DS.disp.ri') silentremove(staname[k] + ".subfault" + num + '.DS.disp.ti') silentremove(staname[k] + ".subfault" + num + '.DS.disp.zi') else: #Waveforms are velocity, as before, rotate from RT-Z to NE+Z and scale to m/s #Strike slip if duration > 0: #Is there a source time fucntion? Yes! r = read(staname[k] + ".subfault" + num + '.SS.vel.r') t = read(staname[k] + ".subfault" + num + '.SS.vel.t') z = read(staname[k] + ".subfault" + num + '.SS.vel.z') else: #No! This is the impulse response! r = read(staname[k] + ".subfault" + num + '.SS.vel.ri') t = read(staname[k] + ".subfault" + num + '.SS.vel.ti') z = read(staname[k] + ".subfault" + num + '.SS.vel.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.SS.vel.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.SS.vel.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.SS.vel.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.SS.vel.r') silentremove(staname[k] + ".subfault" + num + '.SS.vel.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.SS.vel.ri') silentremove(staname[k] + ".subfault" + num + '.SS.vel.ti') silentremove(staname[k] + ".subfault" + num + '.SS.vel.zi') #Dip Slip if duration > 0: r = read(staname[k] + ".subfault" + num + '.DS.vel.r') t = read(staname[k] + ".subfault" + num + '.DS.vel.t') z = read(staname[k] + ".subfault" + num + '.DS.vel.z') else: r = read(staname[k] + ".subfault" + num + '.DS.vel.ri') t = read(staname[k] + ".subfault" + num + '.DS.vel.ti') z = read(staname[k] + ".subfault" + num + '.DS.vel.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.DS.vel.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.DS.vel.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.DS.vel.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.DS.vel.r') silentremove(staname[k] + ".subfault" + num + '.DS.vel.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.DS.vel.ri') silentremove(staname[k] + ".subfault" + num + '.DS.vel.ti') silentremove(staname[k] + ".subfault" + num + '.DS.vel.zi') else: #Compute static synthetics os.chdir(green_path + 'static/') #Move to appropriate dir if okada == False: diststr = '%.1f' % d[ k] #Need current distance in string form for external call if insar == True: green_file = model_name + ".static." + strdepth + ".sub" + subfault + '.insar' #Output dir else: #GPS green_file = model_name + ".static." + strdepth + ".sub" + subfault + '.gps' #Output dir print green_file log = log + green_file + '\n' #Append to log statics = loadtxt(green_file) #Load GFs #Print static GFs into a pipe and pass into synthetics command station_index = argmin(abs(statics[:, 0] - d[k])) #Look up by distance try: temp_pipe = statics[station_index, :] except: temp_pipe = statics inpipe = '' for j in range(len(temp_pipe)): inpipe = inpipe + ' %.6e' % temp_pipe[j] #Form command for external call commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+\ " -A"+str(az[k])+" -P" commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+\ " -A"+str(az[k])+" -P" print staname[k] print commandSS print commandDS log = log + staname[ k] + '\n' + commandSS + '\n' + commandDS + '\n' #Append to log commandSS = split(commandSS) #Lexical split commandDS = split(commandDS) #Make system calls, one for DS, one for SS, and save log ps = subprocess.Popen( ['printf', inpipe], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) #This is the statics pipe, pint stdout to syn's stdin p = subprocess.Popen(commandSS, stdin=ps.stdout, stdout=open( staname[k] + '.subfault' + num + '.SS.static.rtz', 'w'), stderr=subprocess.PIPE) out, err = p.communicate() log = log + str(out) + str(err) ps = subprocess.Popen( ['printf', inpipe], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) #This is the statics pipe, pint stdout to syn's stdin p = subprocess.Popen(commandDS, stdin=ps.stdout, stdout=open( staname[k] + '.subfault' + num + '.DS.static.rtz', 'w'), stderr=subprocess.PIPE) out, err = p.communicate() log = log + str(out) + str(err) #Rotate radial/transverse to East/North, correct vertical and scale to m statics = loadtxt(staname[k] + '.subfault' + num + '.SS.static.rtz') u = statics[2] / 100 r = statics[3] / 100 t = statics[4] / 100 ntemp, etemp = rt2ne(array([r, r]), array([t, t]), az[k]) n = ntemp[0] e = etemp[0] savetxt(staname[k] + '.subfault' + num + '.SS.static.neu', (n, e, u, beta), header='north(m),east(m),up(m),beta(degs)') statics = loadtxt(staname[k] + '.subfault' + num + '.DS.static.rtz') u = statics[2] / 100 r = statics[3] / 100 t = statics[4] / 100 ntemp, etemp = rt2ne(array([r, r]), array([t, t]), az[k]) n = ntemp[0] e = etemp[0] savetxt(staname[k] + '.subfault' + num + '.DS.static.neu', (n, e, u, beta), header='north(m),east(m),up(m),beta(degs)') else: #SS n, e, u = okada_synthetics(strike, dip, rakeSS, ss_length_in_km, ds_length_in_km, xs, ys, zs, lon_sta[k], lat_sta[k], okada_mu) savetxt(staname[k] + '.subfault' + num + '.SS.static.neu', (n, e, u, beta), header='north(m),east(m),up(m),beta(degs)') #DS n, e, u = okada_synthetics(strike, dip, rakeDS, ss_length_in_km, ds_length_in_km, xs, ys, zs, lon_sta[k], lat_sta[k], okada_mu) savetxt(staname[k] + '.subfault' + num + '.DS.static.neu', (n, e, u, beta), header='north(m),east(m),up(m),beta(degs)') return log
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')
def run_syn(home,project_name,source,station_file,green_path,model_name,integrate,static,tsunami, subfault,time_epi,beta,impulse=False,okada=False,okada_mu=45e9,insar=False): ''' Use green functions and compute synthetics at stations for a single source and multiple stations. This code makes an external system call to syn.c first it will make the external call for the strike-slip component then a second externall call will be made for the dip-slip component. The unit amount of moment is 1e15 which corresponds to Mw=3.9333... IN: source: 1-row numpy array containig informaiton aboutt he source, lat, lon, depth, etc... station_file: File name with the station coordinates green_path: Directopry where GFs are stored model_file: File containing the Earth velocity structure integrate: =0 if youw ant velocity waveforms, =1 if you want displacements static: =0 if computing full waveforms, =1 if computing only the static field subfault: String indicating the subfault being worked on coord_type: =0 if problem is in cartesian coordinates, =1 if problem is in lat/lon OUT: log: Sysytem standard output and standard error for log ''' import os import subprocess from mudpy.forward import get_mu from string import rjust from numpy import array,genfromtxt,loadtxt,savetxt,log10,argmin from obspy import read from shlex import split #Constant parameters rakeDS=90+beta #90 is thrust, -90 is normal rakeSS=0+beta #0 is left lateral, 180 is right lateral tb=50 #Number of samples before first arrival #Load structure model_file=home+project_name+'/structure/'+model_name structure=loadtxt(model_file,ndmin=2) #Parse the soruce information num=rjust(str(int(source[0])),4,'0') xs=source[1] ys=source[2] zs=source[3] strike=source[4] dip=source[5] rise=source[6] if impulse==True: #Impulse GFs or apply rise time duration=0 else: duration=source[7] ss_length=source[8] ds_length=source[9] ss_length_in_km=ss_length/1000. ds_length_in_km=ds_length/1000. strdepth='%.4f' % zs if static==0 and tsunami==0: #Where to save dynamic waveforms green_path=green_path+'dynamic/'+model_name+"_"+strdepth+".sub"+subfault+"/" if static==0 and tsunami==1: #Where to save dynamic waveforms green_path=green_path+'tsunami/'+model_name+"_"+strdepth+".sub"+subfault+"/" print("--> Computing synthetics at stations for the source at ("+str(xs)+" , "+str(ys)+")") staname=genfromtxt(station_file,dtype="S6",usecols=0) if staname.shape==(): #Single staiton file staname=array([staname]) #Compute distances and azimuths d,az,lon_sta,lat_sta=src2sta(station_file,source,output_coordinates=True) #Get moment corresponding to 1 meter of slip on subfault mu=get_mu(structure,zs) Mo=mu*ss_length*ds_length*1 Mw=(2./3)*(log10(Mo)-9.1) #Move to output folder log='' #Initalize log os.chdir(green_path) for k in range(len(d)): if static==0: #Compute full waveforms diststr='%.3f' % d[k] #Need current distance in string form for external call #Form the strings to be used for the system calls according to suer desired options if integrate==1: #Make displ. #First Stike-Slip GFs commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" print commandSS #Output to screen so I know we're underway log=log+commandSS+'\n' #Append to log commandSS=split(commandSS) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" print commandDS log=log+commandDS+'\n' commandDS=split(commandDS) else: #Make vel. #First Stike-Slip GFs commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" print commandSS log=log+commandSS+'\n' commandSS=split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" print commandDS log=log+commandDS+'\n' commandDS=split(commandDS) #Run the strike- and dip-slip commands (make system calls) p=subprocess.Popen(commandSS,stdout=subprocess.PIPE,stderr=subprocess.PIPE) out,err=p.communicate() p=subprocess.Popen(commandDS,stdout=subprocess.PIPE,stderr=subprocess.PIPE) out,err=p.communicate() #Result is in RTZ system (+Z is down) rotate to NEZ with +Z up and scale to m or m/s if integrate==1: #'tis displacememnt #Strike slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.SS.disp.r') t=read(staname[k]+".subfault"+num+'.SS.disp.t') z=read(staname[k]+".subfault"+num+'.SS.disp.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.SS.disp.ri') t=read(staname[k]+".subfault"+num+'.SS.disp.ti') z=read(staname[k]+".subfault"+num+'.SS.disp.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) #Scale to m and overwrite with rotated waveforms n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.SS.disp.n',format='SAC') e.write(staname[k]+".subfault"+num+'.SS.disp.e',format='SAC') z.write(staname[k]+".subfault"+num+'.SS.disp.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.SS.disp.r') silentremove(staname[k]+".subfault"+num+'.SS.disp.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.SS.disp.ri') silentremove(staname[k]+".subfault"+num+'.SS.disp.ti') silentremove(staname[k]+".subfault"+num+'.SS.disp.zi') #Dip Slip if duration>0: r=read(staname[k]+".subfault"+num+'.DS.disp.r') t=read(staname[k]+".subfault"+num+'.DS.disp.t') z=read(staname[k]+".subfault"+num+'.DS.disp.z') else: r=read(staname[k]+".subfault"+num+'.DS.disp.ri') t=read(staname[k]+".subfault"+num+'.DS.disp.ti') z=read(staname[k]+".subfault"+num+'.DS.disp.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.DS.disp.n',format='SAC') e.write(staname[k]+".subfault"+num+'.DS.disp.e',format='SAC') z.write(staname[k]+".subfault"+num+'.DS.disp.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.DS.disp.r') silentremove(staname[k]+".subfault"+num+'.DS.disp.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.DS.disp.ri') silentremove(staname[k]+".subfault"+num+'.DS.disp.ti') silentremove(staname[k]+".subfault"+num+'.DS.disp.zi') else: #Waveforms are velocity, as before, rotate from RT-Z to NE+Z and scale to m/s #Strike slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.SS.vel.r') t=read(staname[k]+".subfault"+num+'.SS.vel.t') z=read(staname[k]+".subfault"+num+'.SS.vel.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.SS.vel.ri') t=read(staname[k]+".subfault"+num+'.SS.vel.ti') z=read(staname[k]+".subfault"+num+'.SS.vel.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.SS.vel.n',format='SAC') e.write(staname[k]+".subfault"+num+'.SS.vel.e',format='SAC') z.write(staname[k]+".subfault"+num+'.SS.vel.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.SS.vel.r') silentremove(staname[k]+".subfault"+num+'.SS.vel.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.SS.vel.ri') silentremove(staname[k]+".subfault"+num+'.SS.vel.ti') silentremove(staname[k]+".subfault"+num+'.SS.vel.zi') #Dip Slip if duration>0: r=read(staname[k]+".subfault"+num+'.DS.vel.r') t=read(staname[k]+".subfault"+num+'.DS.vel.t') z=read(staname[k]+".subfault"+num+'.DS.vel.z') else: r=read(staname[k]+".subfault"+num+'.DS.vel.ri') t=read(staname[k]+".subfault"+num+'.DS.vel.ti') z=read(staname[k]+".subfault"+num+'.DS.vel.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.DS.vel.n',format='SAC') e.write(staname[k]+".subfault"+num+'.DS.vel.e',format='SAC') z.write(staname[k]+".subfault"+num+'.DS.vel.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.DS.vel.r') silentremove(staname[k]+".subfault"+num+'.DS.vel.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.DS.vel.ri') silentremove(staname[k]+".subfault"+num+'.DS.vel.ti') silentremove(staname[k]+".subfault"+num+'.DS.vel.zi') else: #Compute static synthetics os.chdir(green_path+'static/') #Move to appropriate dir if okada==False: diststr='%.1f' % d[k] #Need current distance in string form for external call if insar==True: green_file=model_name+".static."+strdepth+".sub"+subfault+'.insar' #Output dir else: #GPS green_file=model_name+".static."+strdepth+".sub"+subfault+'.gps' #Output dir print green_file log=log+green_file+'\n' #Append to log statics=loadtxt(green_file) #Load GFs #Print static GFs into a pipe and pass into synthetics command station_index=argmin(abs(statics[:,0]-d[k])) #Look up by distance try: temp_pipe=statics[station_index,:] except: temp_pipe=statics inpipe='' for j in range(len(temp_pipe)): inpipe=inpipe+' %.6e' % temp_pipe[j] #Form command for external call commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+\ " -A"+str(az[k])+" -P" commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+\ " -A"+str(az[k])+" -P" print staname[k] print commandSS print commandDS log=log+staname[k]+'\n'+commandSS+'\n'+commandDS+'\n' #Append to log commandSS=split(commandSS) #Lexical split commandDS=split(commandDS) #Make system calls, one for DS, one for SS, and save log ps=subprocess.Popen(['printf',inpipe],stdout=subprocess.PIPE,stderr=subprocess.PIPE) #This is the statics pipe, pint stdout to syn's stdin p=subprocess.Popen(commandSS,stdin=ps.stdout,stdout=open(staname[k]+'.subfault'+num+'.SS.static.rtz','w'),stderr=subprocess.PIPE) out,err=p.communicate() log=log+str(out)+str(err) ps=subprocess.Popen(['printf',inpipe],stdout=subprocess.PIPE,stderr=subprocess.PIPE) #This is the statics pipe, pint stdout to syn's stdin p=subprocess.Popen(commandDS,stdin=ps.stdout,stdout=open(staname[k]+'.subfault'+num+'.DS.static.rtz','w'),stderr=subprocess.PIPE) out,err=p.communicate() log=log+str(out)+str(err) #Rotate radial/transverse to East/North, correct vertical and scale to m statics=loadtxt(staname[k]+'.subfault'+num+'.SS.static.rtz') u=statics[2]/100 r=statics[3]/100 t=statics[4]/100 ntemp,etemp=rt2ne(array([r,r]),array([t,t]),az[k]) n=ntemp[0] e=etemp[0] savetxt(staname[k]+'.subfault'+num+'.SS.static.neu',(n,e,u,beta),header='north(m),east(m),up(m),beta(degs)') statics=loadtxt(staname[k]+'.subfault'+num+'.DS.static.rtz') u=statics[2]/100 r=statics[3]/100 t=statics[4]/100 ntemp,etemp=rt2ne(array([r,r]),array([t,t]),az[k]) n=ntemp[0] e=etemp[0] savetxt(staname[k]+'.subfault'+num+'.DS.static.neu',(n,e,u,beta),header='north(m),east(m),up(m),beta(degs)') else: #SS n,e,u=okada_synthetics(strike,dip,rakeSS,ss_length_in_km,ds_length_in_km,xs,ys, zs,lon_sta[k],lat_sta[k],okada_mu) savetxt(staname[k]+'.subfault'+num+'.SS.static.neu',(n,e,u,beta),header='north(m),east(m),up(m),beta(degs)') #DS n,e,u=okada_synthetics(strike,dip,rakeDS,ss_length_in_km,ds_length_in_km,xs,ys, zs,lon_sta[k],lat_sta[k],okada_mu) savetxt(staname[k]+'.subfault'+num+'.DS.static.neu',(n,e,u,beta),header='north(m),east(m),up(m),beta(degs)') return log
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
def run_parallel_synthetics(home, project_name, station_file, model_name, integrate, static, tsunami, time_epi, beta, custom_stf, impulse, rank, size, insar=False, okada=False, mu_okada=45e9): ''' Use green functions and compute synthetics at stations for a single source and multiple stations. This code makes an external system call to syn.c first it will make the external call for the strike-slip component then a second externall call will be made for the dip-slip component. The unit amount of moment is 1e15 which corresponds to Mw=3.9333... IN: source: 1-row numpy array containig informaiton aboutt he source, lat, lon, depth, etc... station_file: File name with the station coordinates green_path: Directopry where GFs are stored model_file: File containing the Earth velocity structure integrate: =0 if youw ant velocity waveforms, =1 if you want displacements static: =0 if computing full waveforms, =1 if computing only the static field subfault: String indicating the subfault being worked on coord_type: =0 if problem is in cartesian coordinates, =1 if problem is in lat/lon OUT: log: Sysytem standard output and standard error for log ''' import os import subprocess from mudpy.forward import get_mu from numpy import array, genfromtxt, loadtxt, savetxt, log10 from obspy import read from shlex import split from mudpy.green import src2sta, rt2ne, origin_time, okada_synthetics from glob import glob from mudpy.green import silentremove from os import remove #What parameters are we using? if rank == 0: out = '''Running all processes with: home = %s project_name = %s station_file = %s model_name = %s integrate = %s static = %s tsunami = %s time_epi = %s beta = %d custom_stf = %s impulse = %s insar = %s okada = %s mu = %.2e ''' % (home, project_name, station_file, model_name, str(integrate), str(static), str(tsunami), str(time_epi), beta, custom_stf, impulse, insar, okada, mu_okada) print(out) #Read your corresponding source file mpi_source = genfromtxt(home + project_name + '/data/model_info/mpi_source.' + str(rank) + '.fault') #Constant parameters rakeDS = 90 + beta #90 is thrust, -90 is normal rakeSS = 0 + beta #0 is left lateral, 180 is right lateral tb = 50 #Number of samples before first arrival (should be 50, NEVER CHANGE, if you do then adjust in fk.pl) #Figure out custom STF if custom_stf.lower() != 'none': custom_stf = home + project_name + '/GFs/STFs/' + custom_stf else: custom_stf = None #Load structure model_file = home + project_name + '/structure/' + model_name structure = loadtxt(model_file, ndmin=2) for ksource in range(len(mpi_source)): source = mpi_source[ksource, :] #Parse the soruce information num = str(int(source[0])).rjust(4, '0') xs = source[1] ys = source[2] zs = source[3] strike = source[4] dip = source[5] rise = source[6] if impulse == True: duration = 0 else: duration = source[7] ss_length = source[8] ds_length = source[9] ss_length_in_km = ss_length / 1000. ds_length_in_km = ds_length / 1000. strdepth = '%.4f' % zs subfault = str(int(source[0])).rjust(4, '0') if static == 0 and tsunami == 0: #Where to save dynamic waveforms green_path = home + project_name + '/GFs/dynamic/' + model_name + "_" + strdepth + ".sub" + subfault + "/" if static == 1 and tsunami == 1: #Where to save dynamic waveforms green_path = home + project_name + '/GFs/tsunami/' + model_name + "_" + strdepth + ".sub" + subfault + "/" if static == 1 and tsunami == 0: #Where to save statics green_path = home + project_name + '/GFs/static/' + model_name + "_" + strdepth + ".sub" + subfault + "/" staname = genfromtxt(station_file, dtype="U", usecols=0) if staname.shape == (): #Single staiton file staname = array([staname]) #Compute distances and azimuths d, az, lon_sta, lat_sta = src2sta(station_file, source, output_coordinates=True) #Get moment corresponding to 1 meter of slip on subfault mu = get_mu(structure, zs) Mo = mu * ss_length * ds_length * 1.0 Mw = (2. / 3) * (log10(Mo) - 9.1) #Move to output folder os.chdir(green_path) print('Processor ' + str(rank) + ' is working on subfault ' + str(int(source[0])) + ' and ' + str(len(d)) + ' stations ') for k in range(len(d)): if static == 0: #Compute full waveforms diststr = '%.6f' % d[ k] #Need current distance in string form for external call #Form the strings to be used for the system calls according to user desired options if integrate == 1: #Make displ. #First Stike-Slip GFs if custom_stf == None: commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" commandSS = split( commandSS ) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" commandDS = split(commandDS) else: commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" commandSS = split( commandSS ) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" commandDS = split(commandDS) else: #Make vel. #First Stike-Slip GFs if custom_stf == None: commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" commandSS = split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" commandDS = split(commandDS) else: commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" commandSS = split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" commandDS = split(commandDS) #Run the strike- and dip-slip commands (make system calls) p = subprocess.Popen(commandSS) p.communicate() p = subprocess.Popen(commandDS) p.communicate() #Result is in RTZ system (+Z is down) rotate to NEZ with +Z up and scale to m or m/s if integrate == 1: #'tis displacememnt #Strike slip if duration > 0: #Is there a source time fucntion? Yes! r = read(staname[k] + ".subfault" + num + '.SS.disp.r') t = read(staname[k] + ".subfault" + num + '.SS.disp.t') z = read(staname[k] + ".subfault" + num + '.SS.disp.z') else: #No! This is the impulse response! r = read(staname[k] + ".subfault" + num + '.SS.disp.ri') t = read(staname[k] + ".subfault" + num + '.SS.disp.ti') z = read(staname[k] + ".subfault" + num + '.SS.disp.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) #Scale to m and overwrite with rotated waveforms n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.SS.disp.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.SS.disp.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.SS.disp.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.SS.disp.r') silentremove(staname[k] + ".subfault" + num + '.SS.disp.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.SS.disp.ri') silentremove(staname[k] + ".subfault" + num + '.SS.disp.ti') silentremove(staname[k] + ".subfault" + num + '.SS.disp.zi') #Dip Slip if duration > 0: #Is there a source time fucntion? Yes! r = read(staname[k] + ".subfault" + num + '.DS.disp.r') t = read(staname[k] + ".subfault" + num + '.DS.disp.t') z = read(staname[k] + ".subfault" + num + '.DS.disp.z') else: #No! This is the impulse response! r = read(staname[k] + ".subfault" + num + '.DS.disp.ri') t = read(staname[k] + ".subfault" + num + '.DS.disp.ti') z = read(staname[k] + ".subfault" + num + '.DS.disp.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.DS.disp.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.DS.disp.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.DS.disp.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.DS.disp.r') silentremove(staname[k] + ".subfault" + num + '.DS.disp.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.DS.disp.ri') silentremove(staname[k] + ".subfault" + num + '.DS.disp.ti') silentremove(staname[k] + ".subfault" + num + '.DS.disp.zi') else: #Waveforms are velocity, as before, rotate from RT-Z to NE+Z and scale to m/s #Strike slip if duration > 0: #Is there a source time fucntion? Yes! r = read(staname[k] + ".subfault" + num + '.SS.vel.r') t = read(staname[k] + ".subfault" + num + '.SS.vel.t') z = read(staname[k] + ".subfault" + num + '.SS.vel.z') else: #No! This is the impulse response! r = read(staname[k] + ".subfault" + num + '.SS.vel.ri') t = read(staname[k] + ".subfault" + num + '.SS.vel.ti') z = read(staname[k] + ".subfault" + num + '.SS.vel.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.SS.vel.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.SS.vel.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.SS.vel.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.SS.vel.r') silentremove(staname[k] + ".subfault" + num + '.SS.vel.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.SS.vel.ri') silentremove(staname[k] + ".subfault" + num + '.SS.vel.ti') silentremove(staname[k] + ".subfault" + num + '.SS.vel.zi') #Dip Slip if duration > 0: #Is there a source time fucntion? Yes! r = read(staname[k] + ".subfault" + num + '.DS.vel.r') t = read(staname[k] + ".subfault" + num + '.DS.vel.t') z = read(staname[k] + ".subfault" + num + '.DS.vel.z') else: #No! This is the impulse response! r = read(staname[k] + ".subfault" + num + '.DS.vel.ri') t = read(staname[k] + ".subfault" + num + '.DS.vel.ti') z = read(staname[k] + ".subfault" + num + '.DS.vel.zi') ntemp, etemp = rt2ne(r[0].data, t[0].data, az[k]) n = r.copy() n[0].data = ntemp / 100 e = t.copy() e[0].data = etemp / 100 z[0].data = z[0].data / 100 n = origin_time(n, time_epi, tb) e = origin_time(e, time_epi, tb) z = origin_time(z, time_epi, tb) n.write(staname[k] + ".subfault" + num + '.DS.vel.n', format='SAC') e.write(staname[k] + ".subfault" + num + '.DS.vel.e', format='SAC') z.write(staname[k] + ".subfault" + num + '.DS.vel.z', format='SAC') silentremove(staname[k] + ".subfault" + num + '.DS.vel.r') silentremove(staname[k] + ".subfault" + num + '.DS.vel.t') if impulse == True: silentremove(staname[k] + ".subfault" + num + '.DS.vel.ri') silentremove(staname[k] + ".subfault" + num + '.DS.vel.ti') silentremove(staname[k] + ".subfault" + num + '.DS.vel.zi') else: #Compute static synthetics if okada == False: #Layered earth model temp_pipe = [] diststr = '%.1f' % d[ k] #Need current distance in string form for external call if insar == True: green_file = green_path + model_name + ".static." + strdepth + ".sub" + subfault + '.insar' #Output dir else: #GPS green_file = green_path + model_name + ".static." + strdepth + ".sub" + subfault + '.gps' #Output dir statics = loadtxt(green_file) #Load GFs if len(statics) < 1: print('ERROR: Empty GF file') break #Print static GFs into a pipe and pass into synthetics command try: temp_pipe = statics[k, :] except: temp_pipe = statics inpipe = '' for j in range(len(temp_pipe)): inpipe = inpipe + ' %.6e' % temp_pipe[j] #Form command for external call commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+\ " -A"+str(az[k])+" -P" commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+\ " -A"+str(az[k])+" -P" commandSS = split(commandSS) #Lexical split commandDS = split(commandDS) #Make system calls, one for DS, one for SS ps = subprocess.Popen( ['printf', inpipe], stdout=subprocess.PIPE ) #This is the statics pipe, pint stdout to syn's stdin p = subprocess.Popen( commandSS, stdin=ps.stdout, stdout=open( green_path + staname[k] + '.subfault' + num + '.SS.static.rtz', 'w')) p.communicate() ps = subprocess.Popen( ['printf', inpipe], stdout=subprocess.PIPE ) #This is the statics pipe, pint stdout to syn's stdin p = subprocess.Popen( commandDS, stdin=ps.stdout, stdout=open( green_path + staname[k] + '.subfault' + num + '.DS.static.rtz', 'w')) p.communicate() #Rotate radial/transverse to East/North, correct vertical and scale to m statics = loadtxt(green_path + staname[k] + '.subfault' + num + '.SS.static.rtz') u = statics[2] / 100 r = statics[3] / 100 t = statics[4] / 100 ntemp, etemp = rt2ne(array([r, r]), array([t, t]), az[k]) n = ntemp[0] e = etemp[0] savetxt( green_path + staname[k] + '.subfault' + num + '.SS.static.neu', (n, e, u, beta)) statics = loadtxt(green_path + staname[k] + '.subfault' + num + '.DS.static.rtz') u = statics[2] / 100 r = statics[3] / 100 t = statics[4] / 100 ntemp, etemp = rt2ne(array([r, r]), array([t, t]), az[k]) n = ntemp[0] e = etemp[0] savetxt(green_path + staname[k] + '.subfault' + num + '.DS.static.neu', (n, e, u, beta), header='north(m),east(m),up(m),beta(degs)') else: #Okada half space solutions #SS n, e, u = okada_synthetics(strike, dip, rakeSS, ss_length_in_km, ds_length_in_km, xs, ys, zs, lon_sta[k], lat_sta[k], mu_okada) savetxt(staname[k] + '.subfault' + num + '.SS.static.neu', (n, e, u, beta), header='north(m),east(m),up(m),beta(degs)') #DS n, e, u = okada_synthetics(strike, dip, rakeDS, ss_length_in_km, ds_length_in_km, xs, ys, zs, lon_sta[k], lat_sta[k], mu_okada) savetxt(staname[k] + '.subfault' + num + '.DS.static.neu', (n, e, u, beta), header='north(m),east(m),up(m),beta(degs)')
#means mux = Dstrike.max() / 2 muy = Ddip.max() / 2 #Make slip slip = exp(-((Dstrike - mux)**2 / sigmax + (Ddip - muy)**2 / sigmay)) #Get moment of the thing GLOBALS ######## home = '/Users/dmelgar/Slip_inv/' project_name = 'Amatrice_3Dfitsgeol_final1' fault_name = 'norcia_east.fault' model_name = 'aci.mod' mod = loadtxt(home + project_name + '/structure/' + model_name, ndmin=2) mu = zeros(len(slip)) for k in range(len(slip)): mu[k] = forward.get_mu(mod, f[k, 3]) A = f[:, -1]**2 #Compute moments try: M0 = mu * A * slip[:, 0] except: M0 = mu * A * slip #Total up and copute magnitude M0 = M0.sum() Mw = (2. / 3) * (log10(M0) - 9.1) print 'Moment before scaling is ' + str(M0) #Scale scale = M0 / (7.32 * 10**17)
def run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,tsunami,time_epi, beta,custom_stf,impulse,rank,size,insar=False,okada=False,mu_okada=45e9): ''' Use green functions and compute synthetics at stations for a single source and multiple stations. This code makes an external system call to syn.c first it will make the external call for the strike-slip component then a second externall call will be made for the dip-slip component. The unit amount of moment is 1e15 which corresponds to Mw=3.9333... IN: source: 1-row numpy array containig informaiton aboutt he source, lat, lon, depth, etc... station_file: File name with the station coordinates green_path: Directopry where GFs are stored model_file: File containing the Earth velocity structure integrate: =0 if youw ant velocity waveforms, =1 if you want displacements static: =0 if computing full waveforms, =1 if computing only the static field subfault: String indicating the subfault being worked on coord_type: =0 if problem is in cartesian coordinates, =1 if problem is in lat/lon OUT: log: Sysytem standard output and standard error for log ''' import os import subprocess from pandas import DataFrame as df from mudpy.forward import get_mu from numpy import array,genfromtxt,loadtxt,savetxt,log10,zeros,sin,cos,ones,deg2rad from obspy import read from shlex import split from mudpy.green import src2sta,rt2ne,origin_time,okada_synthetics from glob import glob from mudpy.green import silentremove from os import remove #What parameters are we using? if rank==0: out='''Running all processes with: home = %s project_name = %s station_file = %s model_name = %s integrate = %s static = %s tsunami = %s time_epi = %s beta = %d custom_stf = %s impulse = %s insar = %s okada = %s mu = %.2e ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(time_epi),beta,custom_stf,impulse,insar,okada,mu_okada) print(out) #Read your corresponding source file mpi_source=genfromtxt(home+project_name+'/data/model_info/mpi_source.'+str(rank)+'.fault') #Constant parameters rakeDS=90+beta #90 is thrust, -90 is normal rakeSS=0+beta #0 is left lateral, 180 is right lateral tb=50 #Number of samples before first arrival (should be 50, NEVER CHANGE, if you do then adjust in fk.pl) #Figure out custom STF if custom_stf.lower()!='none': custom_stf=home+project_name+'/GFs/STFs/'+custom_stf else: custom_stf=None #Load structure model_file=home+project_name+'/structure/'+model_name structure=loadtxt(model_file,ndmin=2) #this keeps track of statics dataframe write_df=False for ksource in range(len(mpi_source)): source=mpi_source[ksource,:] #Parse the soruce information num=str(int(source[0])).rjust(4,'0') xs=source[1] ys=source[2] zs=source[3] strike=source[4] dip=source[5] rise=source[6] if impulse==True: duration=0 else: duration=source[7] ss_length=source[8] ds_length=source[9] ss_length_in_km=ss_length/1000. ds_length_in_km=ds_length/1000. strdepth='%.4f' % zs subfault=str(int(source[0])).rjust(4,'0') if static==0 and tsunami==0: #Where to save dynamic waveforms green_path=home+project_name+'/GFs/dynamic/'+model_name+"_"+strdepth+".sub"+subfault+"/" if static==1 and tsunami==1: #Where to save dynamic waveforms green_path=home+project_name+'/GFs/tsunami/'+model_name+"_"+strdepth+".sub"+subfault+"/" if static==1 and tsunami==0: #Where to save statics green_path=home+project_name+'/GFs/static/'+model_name+"_"+strdepth+".sub"+subfault+"/" staname=genfromtxt(station_file,dtype="U",usecols=0) if staname.shape==(): #Single staiton file staname=array([staname]) #Compute distances and azimuths d,az,lon_sta,lat_sta=src2sta(station_file,source,output_coordinates=True) #Get moment corresponding to 1 meter of slip on subfault mu=get_mu(structure,zs) Mo=mu*ss_length*ds_length*1.0 Mw=(2./3)*(log10(Mo)-9.1) #Move to output folder os.chdir(green_path) print('Processor '+str(rank)+' is working on subfault '+str(int(source[0]))+' and '+str(len(d))+' stations ') #This is looping over "sites" for k in range(len(d)): if static==0: #Compute full waveforms diststr='%.6f' % d[k] #Need current distance in string form for external call #Form the strings to be used for the system calls according to user desired options if integrate==1: #Make displ. #First Stike-Slip GFs if custom_stf==None: commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) else: commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) else: #Make vel. #First Stike-Slip GFs if custom_stf==None: commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) else: commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) #Run the strike- and dip-slip commands (make system calls) p=subprocess.Popen(commandSS) p.communicate() p=subprocess.Popen(commandDS) p.communicate() #Result is in RTZ system (+Z is down) rotate to NEZ with +Z up and scale to m or m/s if integrate==1: #'tis displacememnt #Strike slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.SS.disp.r') t=read(staname[k]+".subfault"+num+'.SS.disp.t') z=read(staname[k]+".subfault"+num+'.SS.disp.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.SS.disp.ri') t=read(staname[k]+".subfault"+num+'.SS.disp.ti') z=read(staname[k]+".subfault"+num+'.SS.disp.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) #Scale to m and overwrite with rotated waveforms n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 # get rid of numerical "noise" in the first tb samples n[0].data[0:tb]=0 e[0].data[0:tb]=0 z[0].data[0:tb]=0 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.SS.disp.n',format='SAC') e.write(staname[k]+".subfault"+num+'.SS.disp.e',format='SAC') z.write(staname[k]+".subfault"+num+'.SS.disp.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.SS.disp.r') silentremove(staname[k]+".subfault"+num+'.SS.disp.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.SS.disp.ri') silentremove(staname[k]+".subfault"+num+'.SS.disp.ti') silentremove(staname[k]+".subfault"+num+'.SS.disp.zi') #Dip Slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.DS.disp.r') t=read(staname[k]+".subfault"+num+'.DS.disp.t') z=read(staname[k]+".subfault"+num+'.DS.disp.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.DS.disp.ri') t=read(staname[k]+".subfault"+num+'.DS.disp.ti') z=read(staname[k]+".subfault"+num+'.DS.disp.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.DS.disp.n',format='SAC') e.write(staname[k]+".subfault"+num+'.DS.disp.e',format='SAC') z.write(staname[k]+".subfault"+num+'.DS.disp.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.DS.disp.r') silentremove(staname[k]+".subfault"+num+'.DS.disp.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.DS.disp.ri') silentremove(staname[k]+".subfault"+num+'.DS.disp.ti') silentremove(staname[k]+".subfault"+num+'.DS.disp.zi') else: #Waveforms are velocity, as before, rotate from RT-Z to NE+Z and scale to m/s #Strike slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.SS.vel.r') t=read(staname[k]+".subfault"+num+'.SS.vel.t') z=read(staname[k]+".subfault"+num+'.SS.vel.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.SS.vel.ri') t=read(staname[k]+".subfault"+num+'.SS.vel.ti') z=read(staname[k]+".subfault"+num+'.SS.vel.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.SS.vel.n',format='SAC') e.write(staname[k]+".subfault"+num+'.SS.vel.e',format='SAC') z.write(staname[k]+".subfault"+num+'.SS.vel.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.SS.vel.r') silentremove(staname[k]+".subfault"+num+'.SS.vel.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.SS.vel.ri') silentremove(staname[k]+".subfault"+num+'.SS.vel.ti') silentremove(staname[k]+".subfault"+num+'.SS.vel.zi') #Dip Slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.DS.vel.r') t=read(staname[k]+".subfault"+num+'.DS.vel.t') z=read(staname[k]+".subfault"+num+'.DS.vel.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.DS.vel.ri') t=read(staname[k]+".subfault"+num+'.DS.vel.ti') z=read(staname[k]+".subfault"+num+'.DS.vel.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.DS.vel.n',format='SAC') e.write(staname[k]+".subfault"+num+'.DS.vel.e',format='SAC') z.write(staname[k]+".subfault"+num+'.DS.vel.z',format='SAC') silentremove(staname[k]+".subfault"+num+'.DS.vel.r') silentremove(staname[k]+".subfault"+num+'.DS.vel.t') if impulse==True: silentremove(staname[k]+".subfault"+num+'.DS.vel.ri') silentremove(staname[k]+".subfault"+num+'.DS.vel.ti') silentremove(staname[k]+".subfault"+num+'.DS.vel.zi') else: #Compute static synthetics if okada==False: #Layered earth model #this is because when I first wrote this code it processed each #source/station pair independently but now that it's vectorized #it's does ALL stations in one fell swoop, given the logic it's #easier to just keep this inside the for loop and use the if to #run it jsut the first time for all sites if k==0: #initalize output variables staticsSS = zeros((len(d),4)) staticsDS = zeros((len(d),4)) write_df=True #read GFs file if insar==True: green_file=green_path+model_name+".static."+strdepth+".sub"+subfault+'.insar' #Output dir else: #GPS green_file=green_path+model_name+".static."+strdepth+".sub"+subfault+'.gps' #Output statics=loadtxt(green_file) #Load GFs Nsites=len(statics) if len(statics)<1: print('ERROR: Empty GF file') break #Now get radiation pattern terms, there will be 3 terms #for each direction so 9 terms total. THis comes from funtion #dc_radiat() in radiats.c from fk radiation_pattern_ss = zeros((Nsites,9)) radiation_pattern_ds = zeros((Nsites,9)) rakeSSrad = deg2rad(rakeSS) rakeDSrad = deg2rad(rakeDS) dip_rad = deg2rad(dip) pseudo_strike = deg2rad(az-strike) #Let's do SS first r = rakeSSrad #trigonometric terms following nomenclature used in radiats.c sstk=sin(pseudo_strike) ; cstk=cos(pseudo_strike) sdip=sin(dip_rad) ; cdip=cos(dip_rad) srak=sin(r) ; crak=cos(r) sstk2=2*sstk*cstk ; cstk2=cstk*cstk-sstk*sstk sdip2=2*sdip*cdip ; cdip2=cdip*cdip-sdip*sdip # terms for up component u_dd = 0.5*srak*sdip2*ones(Nsites) u_ds = -sstk*srak*cdip2+cstk*crak*cdip u_ss = -sstk2*crak*sdip-0.5*cstk2*srak*sdip2 #terms for r component r_dd = u_dd.copy() r_ds = u_ds.copy() r_ss = u_ss.copy() #terms for t component t_dd = zeros(Nsites) t_ds = cstk*srak*cdip2+sstk*crak*cdip t_ss = cstk2*crak*sdip-0.5*sstk2*srak*sdip2 #assemble in one variable radiation_pattern_ss[:,0] = u_dd radiation_pattern_ss[:,1] = u_ds radiation_pattern_ss[:,2] = u_ss radiation_pattern_ss[:,3] = r_dd radiation_pattern_ss[:,4] = r_ds radiation_pattern_ss[:,5] = r_ss radiation_pattern_ss[:,6] = t_dd radiation_pattern_ss[:,7] = t_ds radiation_pattern_ss[:,8] = t_ss #Now radiation pattern for DS r = rakeDSrad #trigonometric terms following nomenclature used in radiats.c sstk=sin(pseudo_strike) ; cstk=cos(pseudo_strike) sdip=sin(dip_rad) ; cdip=cos(dip_rad) srak=sin(r) ; crak=cos(r) sstk2=2*sstk*cstk ; cstk2=cstk*cstk-sstk*sstk sdip2=2*sdip*cdip ; cdip2=cdip*cdip-sdip*sdip # terms for up component u_dd = 0.5*srak*sdip2*ones(Nsites) u_ds = -sstk*srak*cdip2+cstk*crak*cdip u_ss = -sstk2*crak*sdip-0.5*cstk2*srak*sdip2 #terms for r component r_dd = u_dd.copy() r_ds = u_ds.copy() r_ss = u_ss.copy() #terms for t component t_dd = zeros(Nsites) t_ds = cstk*srak*cdip2+sstk*crak*cdip t_ss = cstk2*crak*sdip-0.5*sstk2*srak*sdip2 #assemble in one variable radiation_pattern_ds[:,0] = u_dd radiation_pattern_ds[:,1] = u_ds radiation_pattern_ds[:,2] = u_ss radiation_pattern_ds[:,3] = r_dd radiation_pattern_ds[:,4] = r_ds radiation_pattern_ds[:,5] = r_ss radiation_pattern_ds[:,6] = t_dd radiation_pattern_ds[:,7] = t_ds radiation_pattern_ds[:,8] = t_ss #Now define the scalng based on magnitude this is variable #"coef" in the syn.c original source code scale = 10**(1.5*Mw+16.1-20) #definition used in syn.c #Scale radiation patterns accordingly radiation_pattern_ss *= scale radiation_pattern_ds *= scale #Now multiply each GF component by the appropriate SCALED #radiation pattern term and add em up to get the displacements # also /100 to convert to meters up_ss = radiation_pattern_ss[:,0:3]*statics[:,[1,4,7]] up_ss = up_ss.sum(axis=1) / 100 up_ds = radiation_pattern_ds[:,0:3]*statics[:,[1,4,7]] up_ds = up_ds.sum(axis=1) / 100 radial_ss = radiation_pattern_ss[:,3:6]*statics[:,[2,5,8]] radial_ss = radial_ss.sum(axis=1) / 100 radial_ds = radiation_pattern_ds[:,3:6]*statics[:,[2,5,8]] radial_ds = radial_ds.sum(axis=1) / 100 tangential_ss = radiation_pattern_ss[:,6:9]*statics[:,[3,6,9]] tangential_ss = tangential_ss.sum(axis=1) / 100 tangential_ds = radiation_pattern_ds[:,6:9]*statics[:,[3,6,9]] tangential_ds = tangential_ds.sum(axis=1) / 100 #rotate to neu n_ss,e_ss=rt2ne(radial_ss,tangential_ss,az) n_ds,e_ds=rt2ne(radial_ds,tangential_ds,az) #put in output variables staticsSS[:,0]=n_ss staticsSS[:,1]=e_ss staticsSS[:,2]=up_ss staticsSS[:,3]=beta*ones(Nsites) staticsDS[:,0]=n_ds staticsDS[:,1]=e_ds staticsDS[:,2]=up_ds staticsDS[:,3]=beta*ones(Nsites) else: pass else: #Okada half space solutions #SS n,e,u=okada_synthetics(strike,dip,rakeSS,ss_length_in_km,ds_length_in_km,xs,ys, zs,lon_sta[k],lat_sta[k],mu_okada) savetxt(staname[k]+'.subfault'+num+'.SS.static.neu',(n,e,u,beta),header='north(m),east(m),up(m),beta(degs)') #DS n,e,u=okada_synthetics(strike,dip,rakeDS,ss_length_in_km,ds_length_in_km,xs,ys, zs,lon_sta[k],lat_sta[k],mu_okada) savetxt(staname[k]+'.subfault'+num+'.DS.static.neu',(n,e,u,beta),header='north(m),east(m),up(m),beta(degs)') if write_df==True and static ==1: #Note to self: stop using 0,1 and swithc to True/False #Strike slip SSdf = df(data=None, index=None, columns=['staname','n','e','u','beta']) SSdf.staname=staname SSdf.n=staticsSS[:,0] SSdf.e=staticsSS[:,1] SSdf.u=staticsSS[:,2] SSdf.beta=staticsSS[:,3] SSdf.to_csv(green_path+'subfault'+num+'.SS.static.neu',sep='\t',index=False,header=False) DSdf = df(data=None, index=None, columns=['staname','n','e','u','beta']) DSdf.staname=staname DSdf.n=staticsDS[:,0] DSdf.e=staticsDS[:,1] DSdf.u=staticsDS[:,2] DSdf.beta=staticsDS[:,3] DSdf.to_csv(green_path+'subfault'+num+'.DS.static.neu',sep='\t',index=False,header=False)
def run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,tsunami,time_epi, beta,custom_stf,rank,size): ''' Use green functions and compute synthetics at stations for a single source and multiple stations. This code makes an external system call to syn.c first it will make the external call for the strike-slip component then a second externall call will be made for the dip-slip component. The unit amount of moment is 1e15 which corresponds to Mw=3.9333... IN: source: 1-row numpy array containig informaiton aboutt he source, lat, lon, depth, etc... station_file: File name with the station coordinates green_path: Directopry where GFs are stored model_file: File containing the Earth velocity structure integrate: =0 if youw ant velocity waveforms, =1 if you want displacements static: =0 if computing full waveforms, =1 if computing only the static field subfault: String indicating the subfault being worked on coord_type: =0 if problem is in cartesian coordinates, =1 if problem is in lat/lon OUT: log: Sysytem standard output and standard error for log ''' import os import subprocess from mudpy.forward import get_mu from string import rjust from numpy import array,genfromtxt,loadtxt,savetxt,log10 from obspy import read from shlex import split from mudpy.green import src2sta,rt2ne,origin_time from glob import glob from os import remove #What parameters are we using? if rank==0: out='''Running all processes with: home = %s project_name = %s station_file = %s model_name = %s integrate = %s static = %s tsunami = %s time_epi = %s beta = %d custom_stf = %s ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(time_epi),beta,custom_stf) print out #Read your corresponding source file mpi_source=genfromtxt(home+project_name+'/data/model_info/mpi_source.'+str(rank)+'.fault') #Constant parameters rakeDS=90+beta #90 is thrust, -90 is normal rakeSS=0+beta #0 is left lateral, 180 is right lateral tb=50 #Number of samples before first arrival #Figure out custom STF if custom_stf.lower()!='none': custom_stf=home+project_name+'/GFs/STFs/'+custom_stf else: custom_stf=None #Load structure model_file=home+project_name+'/structure/'+model_name structure=loadtxt(model_file,ndmin=2) for ksource in range(len(mpi_source)): source=mpi_source[ksource,:] #Parse the soruce information num=rjust(str(int(source[0])),4,'0') zs=source[3] strike=source[4] dip=source[5] rise=source[6] duration=source[7] ss_length=source[8] ds_length=source[9] strdepth='%.4f' % zs subfault=rjust(str(int(source[0])),4,'0') if static==0 and tsunami==0: #Where to save dynamic waveforms green_path=home+project_name+'/GFs/dynamic/'+model_name+"_"+strdepth+".sub"+subfault+"/" if static==0 and tsunami==1: #Where to save dynamic waveforms green_path=home+project_name+'/GFs/tsunami/'+model_name+"_"+strdepth+".sub"+subfault+"/" if static==1: #Where to save dynamic waveforms green_path=home+project_name+'/GFs/static/' staname=genfromtxt(station_file,dtype="S6",usecols=0) if staname.shape==(): #Single staiton file staname=array([staname]) #Compute distances and azmuths d,az=src2sta(station_file,source) #Get moment corresponding to 1 meter of slip on subfault mu=get_mu(structure,zs) Mo=mu*ss_length*ds_length*1 Mw=(2./3)*(log10(Mo)-9.1) #Move to output folder os.chdir(green_path) print 'Processor '+str(rank)+' is working on subfault '+str(int(source[0]))+' and '+str(len(d))+' stations ' for k in range(len(d)): if static==0: #Compute full waveforms diststr='%.3f' % d[k] #Need current distance in string form for external call #Form the strings to be used for the system calls according to suer desired options if integrate==1: #Make displ. #First Stike-Slip GFs if custom_stf==None: commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) else: #print "Using custom STF "+custom_stf commandSS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.disp.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Split string into lexical components for system call #Now dip slip commandDS="syn -I -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.disp.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) else: #Make vel. #First Stike-Slip GFs if custom_stf==None: commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -D"+str(duration)+ \ "/"+str(rise)+" -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) else: #print "Using custom STF "+custom_stf commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".SS.vel.x -G"+green_path+diststr+".grn.0" commandSS=split(commandSS) #Now dip slip commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) #Run the strike- and dip-slip commands (make system calls) p=subprocess.Popen(commandSS) p.communicate() p=subprocess.Popen(commandDS) p.communicate() #Result is in RTZ system (+Z is down) rotate to NEZ with +Z up and scale to m or m/s if integrate==1: #'tis displacememnt #Strike slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.SS.disp.r') t=read(staname[k]+".subfault"+num+'.SS.disp.t') z=read(staname[k]+".subfault"+num+'.SS.disp.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.SS.disp.ri') t=read(staname[k]+".subfault"+num+'.SS.disp.ti') z=read(staname[k]+".subfault"+num+'.SS.disp.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) #Scale to m and overwrite with rotated waveforms n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.SS.disp.n',format='SAC') e.write(staname[k]+".subfault"+num+'.SS.disp.e',format='SAC') z.write(staname[k]+".subfault"+num+'.SS.disp.z',format='SAC') #Dip Slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.DS.disp.r') t=read(staname[k]+".subfault"+num+'.DS.disp.t') z=read(staname[k]+".subfault"+num+'.DS.disp.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.DS.disp.ri') t=read(staname[k]+".subfault"+num+'.DS.disp.ti') z=read(staname[k]+".subfault"+num+'.DS.disp.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.DS.disp.n',format='SAC') e.write(staname[k]+".subfault"+num+'.DS.disp.e',format='SAC') z.write(staname[k]+".subfault"+num+'.DS.disp.z',format='SAC') else: #Waveforms are velocity, as before, rotate from RT-Z to NE+Z and scale to m/s #Strike slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.SS.vel.r') t=read(staname[k]+".subfault"+num+'.SS.vel.t') z=read(staname[k]+".subfault"+num+'.SS.vel.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.SS.vel.ri') t=read(staname[k]+".subfault"+num+'.SS.vel.ti') z=read(staname[k]+".subfault"+num+'.SS.vel.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.SS.vel.n',format='SAC') e.write(staname[k]+".subfault"+num+'.SS.vel.e',format='SAC') z.write(staname[k]+".subfault"+num+'.SS.vel.z',format='SAC') #Dip Slip if duration>0: #Is there a source time fucntion? Yes! r=read(staname[k]+".subfault"+num+'.DS.vel.r') t=read(staname[k]+".subfault"+num+'.DS.vel.t') z=read(staname[k]+".subfault"+num+'.DS.vel.z') else: #No! This is the impulse response! r=read(staname[k]+".subfault"+num+'.DS.vel.ri') t=read(staname[k]+".subfault"+num+'.DS.vel.ti') z=read(staname[k]+".subfault"+num+'.DS.vel.zi') ntemp,etemp=rt2ne(r[0].data,t[0].data,az[k]) n=r.copy() n[0].data=ntemp/100 e=t.copy() e[0].data=etemp/100 z[0].data=z[0].data/100 n=origin_time(n,time_epi,tb) e=origin_time(e,time_epi,tb) z=origin_time(z,time_epi,tb) n.write(staname[k]+".subfault"+num+'.DS.vel.n',format='SAC') e.write(staname[k]+".subfault"+num+'.DS.vel.e',format='SAC') z.write(staname[k]+".subfault"+num+'.DS.vel.z',format='SAC') else: #Compute static synthetics temp_pipe=[] diststr='%.1f' % d[k] #Need current distance in string form for external call green_file=model_name+".static."+strdepth+".sub"+subfault #Output dir statics=loadtxt(green_file) #Load GFs if len(statics)<1: print 'ERROR: Empty GF file' break #Print static GFs into a pipe and pass into synthetics command try: temp_pipe=statics[k,:] except: temp_pipe=statics inpipe='' for j in range(len(temp_pipe)): inpipe=inpipe+' %.6e' % temp_pipe[j] #Form command for external call commandDS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeDS)+\ " -A"+str(az[k])+" -P" commandSS="syn -M"+str(Mw)+"/"+str(strike)+"/"+str(dip)+"/"+str(rakeSS)+\ " -A"+str(az[k])+" -P" commandSS=split(commandSS) #Lexical split commandDS=split(commandDS) #Make system calls, one for DS, one for SS ps=subprocess.Popen(['printf',inpipe],stdout=subprocess.PIPE) #This is the statics pipe, pint stdout to syn's stdin p=subprocess.Popen(commandSS,stdin=ps.stdout,stdout=open(staname[k]+'.subfault'+num+'.SS.static.rtz','w')) p.communicate() ps=subprocess.Popen(['printf',inpipe],stdout=subprocess.PIPE) #This is the statics pipe, pint stdout to syn's stdin p=subprocess.Popen(commandDS,stdin=ps.stdout,stdout=open(staname[k]+'.subfault'+num+'.DS.static.rtz','w')) p.communicate() #Rotate radial/transverse to East/North, correct vertical and scale to m statics=loadtxt(staname[k]+'.subfault'+num+'.SS.static.rtz') u=statics[2]/100 r=statics[3]/100 t=statics[4]/100 ntemp,etemp=rt2ne(array([r,r]),array([t,t]),az[k]) n=ntemp[0] e=etemp[0] savetxt(staname[k]+'.subfault'+num+'.SS.static.neu',(n,e,u,beta)) statics=loadtxt(staname[k]+'.subfault'+num+'.DS.static.rtz') u=statics[2]/100 r=statics[3]/100 t=statics[4]/100 ntemp,etemp=rt2ne(array([r,r]),array([t,t]),az[k]) n=ntemp[0] e=etemp[0] savetxt(staname[k]+'.subfault'+num+'.DS.static.neu',(n,e,u,beta),header='north(m),east(m),up(m),beta(degs)')