From dfa5aaf0d84cfed592a5ed0faeb6a0a382e7028f Mon Sep 17 00:00:00 2001 From: Randy LeVeque Date: Wed, 29 Sep 2021 11:37:40 -0700 Subject: [PATCH 01/24] modify waveforms_fakequakes to handle len(all_sources)=1 Turn all_sources into a list if it isn't already. --- src/python/mudpy/forward.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/python/mudpy/forward.py b/src/python/mudpy/forward.py index c0defa8..5c2bfaa 100644 --- a/src/python/mudpy/forward.py +++ b/src/python/mudpy/forward.py @@ -298,6 +298,8 @@ def waveforms_fakequakes(home,project_name,fault_name,rupture_list,GF_list, all_sources=array([rupture_name]) else: all_sources=genfromtxt(home+project_name+'/data/'+rupture_list,dtype='U') + all_sources = array(all_sources, ndmin=1) # in case only 1 entry + #Load all synthetics print('... loading all synthetics into memory') From fab4084f6e02c6cc6f57c51e2d262cf0e8ccb2a1 Mon Sep 17 00:00:00 2001 From: Tara Nye <42422116+taranye96@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:48:07 -0700 Subject: [PATCH 02/24] revised fmt parameter to hace correct number of format options --- src/python/mudpy/forward.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/mudpy/forward.py b/src/python/mudpy/forward.py index 52f756a..ad078bb 100644 --- a/src/python/mudpy/forward.py +++ b/src/python/mudpy/forward.py @@ -802,7 +802,8 @@ def make_parallel_hfsims(home,project_name,rupture_name,ncpus,sta,sta_lon,sta_la for k in range(ncpus): i=arange(k,len(fault),ncpus) mpi_source=fault[i,:] - fmt='%d\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6E' + #fmt='%d\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6f\t%10.6E' #old + fmt='%d\t%10.6f\t%10.6f\t%10.4f\t%10.2f\t%10.2f\t%10.6f\t%10.6E\t%10.6E\t%10.6E\t%10.6f\t%10.6f\t%10.6E\t%10.6E\t%10.6E' #new savetxt(home+project_name+'/output/ruptures/mpi_rupt.'+str(k)+'.'+rupture_name,mpi_source,fmt=fmt) #Make mpi system call print("MPI: Starting Stochastic High Frequency Simulation on ", ncpus, "CPUs") From 543f6d03032c17f44c9a5bae5f23a8dc134901ac Mon Sep 17 00:00:00 2001 From: Tara Nye <42422116+taranye96@users.noreply.github.com> Date: Mon, 19 Sep 2022 16:48:56 -0700 Subject: [PATCH 03/24] changed high_stress_depth from int to float on line 650 --- src/python/mudpy/hfsims_parallel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/mudpy/hfsims_parallel.py b/src/python/mudpy/hfsims_parallel.py index deed876..88edfb8 100644 --- a/src/python/mudpy/hfsims_parallel.py +++ b/src/python/mudpy/hfsims_parallel.py @@ -647,7 +647,7 @@ def run_parallel_hfsims(home,project_name,rupture_name,N,M0,sta,sta_lon,sta_lat, Swave=sys.argv[21] if Swave=='True': Swave=True - high_stress_depth=int(sys.argv[22]) + high_stress_depth=float(sys.argv[22]) Qmethod=sys.argv[23] scattering=sys.argv[24] Qc_exp=float(sys.argv[25]) From 0b9901967db029cf345852878efec38b3c3898c2 Mon Sep 17 00:00:00 2001 From: Tara Nye <42422116+taranye96@users.noreply.github.com> Date: Mon, 8 May 2023 13:35:33 -0700 Subject: [PATCH 04/24] Added modification to account for taupy bug at certain subfault depths --- src/python/mudpy/hfsims_parallel.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/python/mudpy/hfsims_parallel.py b/src/python/mudpy/hfsims_parallel.py index 1a1a897..3a7fbcd 100644 --- a/src/python/mudpy/hfsims_parallel.py +++ b/src/python/mudpy/hfsims_parallel.py @@ -269,7 +269,11 @@ def run_parallel_hfsims(home,project_name,rupture_name,N,M0,sta,sta_lon,sta_lat, 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']) + try: + Ppaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['P','p']) + except: + zs = zs+0.0001 + Ppaths=velmod.get_ray_paths(zs,dist_in_degs,phase_list=['P','p']) #Get ray paths for all direct S arrivals try: From 8da45cff8fcf83af06be4b27bd5e433034b08778 Mon Sep 17 00:00:00 2001 From: taranye96 Date: Wed, 12 Jul 2023 14:38:06 -0700 Subject: [PATCH 05/24] Update fakequakes.py Removed unnecessary print statement --- src/python/mudpy/fakequakes.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/python/mudpy/fakequakes.py b/src/python/mudpy/fakequakes.py index 2df42aa..073c56b 100644 --- a/src/python/mudpy/fakequakes.py +++ b/src/python/mudpy/fakequakes.py @@ -883,7 +883,6 @@ def get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter, # swf_r=randint(1,11) # shear_wave_fraction_shallow=1/60/60/24*swf_r # shear_wave_fraction_deep=1/60/60/24*swf_r - print(shear_wave_fraction_deep*86400) #I don't condone it but this cleans up the warnings warnings.filterwarnings("ignore") @@ -1579,4 +1578,4 @@ def run_generate_ruptures(home,project_name,run_name,fault_name,slab_name,mesh_n realization+=1 - \ No newline at end of file + From a9f581b00ccd73a1da22172f61ba78ff02569c2a Mon Sep 17 00:00:00 2001 From: Tara Nye <42422116+taranye96@users.noreply.github.com> Date: Fri, 4 Aug 2023 09:43:38 -0700 Subject: [PATCH 06/24] modified calc of avg risetime --- src/python/mudpy/generate_ruptures_parallel.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/mudpy/generate_ruptures_parallel.py b/src/python/mudpy/generate_ruptures_parallel.py index 09d2afe..01e3045 100755 --- a/src/python/mudpy/generate_ruptures_parallel.py +++ b/src/python/mudpy/generate_ruptures_parallel.py @@ -258,7 +258,7 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na #Calculate average risetime rise = fault_out[:,7] - avg_rise = np.mean(rise) + avg_rise = np.mean(rise[np.where(rise>0)[0]]) # Calculate average rupture velocity lon_array = fault_out[:,1] @@ -422,4 +422,4 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na max_slip_rule,rank,size) else: print("ERROR: You're not allowed to run "+sys.argv[1]+" from the shell or it does not exist") - \ No newline at end of file + From 71b824a152b52ad78e018bb570b21df83208d9df Mon Sep 17 00:00:00 2001 From: Tara Nye <42422116+taranye96@users.noreply.github.com> Date: Mon, 14 Aug 2023 16:53:49 -0400 Subject: [PATCH 07/24] removed an unnecessary print statement --- src/python/mudpy/fakequakes.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/python/mudpy/fakequakes.py b/src/python/mudpy/fakequakes.py index 2df42aa..83b96d7 100644 --- a/src/python/mudpy/fakequakes.py +++ b/src/python/mudpy/fakequakes.py @@ -883,7 +883,6 @@ def get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter, # swf_r=randint(1,11) # shear_wave_fraction_shallow=1/60/60/24*swf_r # shear_wave_fraction_deep=1/60/60/24*swf_r - print(shear_wave_fraction_deep*86400) #I don't condone it but this cleans up the warnings warnings.filterwarnings("ignore") From 0467d2f5e5134e46df32a880066842a25fe39ad7 Mon Sep 17 00:00:00 2001 From: Tara Nye <42422116+taranye96@users.noreply.github.com> Date: Fri, 12 Apr 2024 12:09:22 -0700 Subject: [PATCH 08/24] Fixed bugs where a user-defined hypocenter was not being used to select the ruptue faults --- src/python/mudpy/fakequakes.py | 27 ++++++------ .../mudpy/generate_ruptures_parallel.py | 42 ++++++++++--------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/python/mudpy/fakequakes.py b/src/python/mudpy/fakequakes.py index 073c56b..7fa2164 100644 --- a/src/python/mudpy/fakequakes.py +++ b/src/python/mudpy/fakequakes.py @@ -533,12 +533,11 @@ def select_faults(whole_fault,Dstrike,Ddip,target_Mw,num_modes,scaling_law, #Select random subfault as center of the locus of L and W - if subfault_hypocenter==None: + if subfault_hypocenter is None: hypo_fault=randint(0,len(whole_fault)-1) else: #get subfault closest to hypo hypo_fault=subfault_hypocenter - if force_area==True and no_random==False: #Use entire fault model nothing more to do here folks selected_faults = arange(len(whole_fault)) @@ -627,10 +626,10 @@ def select_faults(whole_fault,Dstrike,Ddip,target_Mw,num_modes,scaling_law, width=60+10**normal(0,width_std) length=a/width - #so which subfault ended up being the middle? - center_subfault=hypo_fault + # #so which subfault ended up being the middle? + # center_subfault=hypo_fault # I'm not sure why this is getting defined here? - hypo_fault=int(hypo_fault) + # hypo_fault=int(hypo_fault) #Get max/min distances from hypocenter to all faults dstrike_max=Dstrike[:,hypo_fault].max() @@ -673,7 +672,7 @@ def select_faults(whole_fault,Dstrike,Ddip,target_Mw,num_modes,scaling_law, hypo_found=False - if len(selected_faults)>1: #there is mroe than 1 subfault + if len(selected_faults)>1: #there is more than 1 subfault i=randint(0,len(selected_faults)-1) hypo_fault=selected_faults[i] @@ -701,7 +700,7 @@ def select_faults(whole_fault,Dstrike,Ddip,target_Mw,num_modes,scaling_law, if use_hypo_fraction == True: #Need to find "center" of the selected faults. To do this look for the subfault - #witht he lowest combined maximum along strike and along dip distance to all + #with the lowest combined maximum along strike and along dip distance to all #other faults @@ -865,7 +864,7 @@ def get_rise_times(M0,slip,fault_array,rise_time_depths,stoc_rake,rise_time='MH2 -def get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter, +def get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter,shypo, rise_time_depths,M0,velmod,sigma_rise_time=0.2,shear_wave_fraction_shallow=0.49,shear_wave_fraction_deep=0.8): home,project_name,slip,fault_array,model_name,hypocenter,rise_time_depths,M0,velmod,shear_wave_fraction_shallow,shear_wave_fraction_deep @@ -929,6 +928,7 @@ def get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter, i_same_as_hypo=where(fault_array[:,3]==hypocenter[2])[0] dist=((fault_array[:,1]-hypocenter[0])**2+(fault_array[:,2]-hypocenter[1])**2)**0.5 i_hypo=argmin(dist) + #Get faults at same depth that are NOT the hypo i_same_as_hypo=setxor1d(i_same_as_hypo,i_hypo) #perturb @@ -938,7 +938,6 @@ def get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter, R=rand(len(i_same_as_hypo)) fault_array[i_same_as_hypo,3]=fault_array[i_same_as_hypo,3]+delta*R - #Loop over all faults t_onset=zeros(len(slip)) length2fault=zeros(len(slip)) @@ -1278,7 +1277,7 @@ def generate_ruptures(home,project_name,run_name,fault_name,slab_name,mesh_name, Lstrike,num_modes,Nrealizations,rake,rise_time,rise_time_depths,time_epi, max_slip,source_time_function,lognormal,slip_standard_deviation,scaling_law,ncpus, force_magnitude=False,force_area=False,mean_slip_name=None,hypocenter=None, - slip_tol=1e-2,force_hypocenter=False,no_random=False,shypo=None,use_hypo_fraction=True, + slip_tol=1e-2,force_hypocenter=False,no_random=False,use_hypo_fraction=True, shear_wave_fraction_shallow=0.49,shear_wave_fraction_deep=0.8,max_slip_rule=True): ''' Set up rupture generation-- use ncpus if available @@ -1305,7 +1304,7 @@ def generate_ruptures(home,project_name,run_name,fault_name,slab_name,mesh_name, Lstrike,num_modes,Nrealizations,rake,rise_time,rise_time_depths,time_epi, max_slip,source_time_function,lognormal,slip_standard_deviation,scaling_law,ncpus, force_magnitude,force_area,mean_slip_name,hypocenter,slip_tol,force_hypocenter, - no_random,shypo,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep,max_slip_rule) + no_random,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep,max_slip_rule) @@ -1316,7 +1315,7 @@ def run_generate_ruptures_parallel(home,project_name,run_name,fault_name,slab_na Lstrike,num_modes,Nrealizations,rake,rise_time,rise_time_depths,time_epi, max_slip,source_time_function,lognormal,slip_standard_deviation,scaling_law,ncpus, force_magnitude,force_area,mean_slip_name,hypocenter,slip_tol,force_hypocenter, - no_random,shypo,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep,max_slip_rule): + no_random,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep,max_slip_rule): from numpy import ceil from os import environ @@ -1337,7 +1336,7 @@ def run_generate_ruptures_parallel(home,project_name,run_name,fault_name,slab_na print("MPI: Starting " + str(Nrealizations_parallel*ncpus) + " FakeQuakes Rupture Generations on ", ncpus, "CPUs") mud_source=environ['MUD']+'/src/python/mudpy/' - mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'generate_ruptures_parallel.py run_parallel_generate_ruptures '+home+' '+project_name+' '+run_name+' '+fault_name+' '+str(slab_name)+' '+str(mesh_name)+' '+str(load_distances)+' '+distances_name+' '+UTM_zone+' '+str(tMw)+' '+model_name+' '+str(hurst)+' '+Ldip+' '+Lstrike+' '+str(num_modes)+' '+str(Nrealizations_parallel)+' '+str(rake)+' '+str(rise_time)+' '+str(rise_time_depths0)+' '+str(rise_time_depths1)+' '+str(time_epi)+' '+str(max_slip)+' '+source_time_function+' '+str(lognormal)+' '+str(slip_standard_deviation)+' '+scaling_law+' '+str(ncpus)+' '+str(force_magnitude)+' '+str(force_area)+' '+str(mean_slip_name)+' "'+str(hypocenter)+'" '+str(slip_tol)+' '+str(force_hypocenter)+' '+str(no_random)+' '+str(shypo)+' '+str(use_hypo_fraction)+' '+str(shear_wave_fraction_shallow)+' '+str(shear_wave_fraction_deep)+' '+str(max_slip_rule) + mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'generate_ruptures_parallel.py run_parallel_generate_ruptures '+home+' '+project_name+' '+run_name+' '+fault_name+' '+str(slab_name)+' '+str(mesh_name)+' '+str(load_distances)+' '+distances_name+' '+UTM_zone+' '+str(tMw)+' '+model_name+' '+str(hurst)+' '+Ldip+' '+Lstrike+' '+str(num_modes)+' '+str(Nrealizations_parallel)+' '+str(rake)+' '+str(rise_time)+' '+str(rise_time_depths0)+' '+str(rise_time_depths1)+' '+str(time_epi)+' '+str(max_slip)+' '+source_time_function+' '+str(lognormal)+' '+str(slip_standard_deviation)+' '+scaling_law+' '+str(ncpus)+' '+str(force_magnitude)+' '+str(force_area)+' '+str(mean_slip_name)+' "'+str(hypocenter)+'" '+str(slip_tol)+' '+str(force_hypocenter)+' '+str(no_random)+' '+str(use_hypo_fraction)+' '+str(shear_wave_fraction_shallow)+' '+str(shear_wave_fraction_deep)+' '+str(max_slip_rule) mpi=split(mpi) p=subprocess.Popen(mpi) p.communicate() @@ -1537,7 +1536,7 @@ def run_generate_ruptures(home,project_name,run_name,fault_name,slab_name,mesh_n #Calculate rupture onset times if force_hypocenter==False: #Use random hypo, otehrwise force hypo to user specified hypocenter=whole_fault[hypo_fault,1:4] - + t_onset=get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter, rise_time_depths,M0,velmod,shear_wave_fraction) fault_out[:,12]=0 diff --git a/src/python/mudpy/generate_ruptures_parallel.py b/src/python/mudpy/generate_ruptures_parallel.py index 01e3045..6c9ecba 100755 --- a/src/python/mudpy/generate_ruptures_parallel.py +++ b/src/python/mudpy/generate_ruptures_parallel.py @@ -11,14 +11,14 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na num_modes,Nrealizations,rake,rise_time,rise_time_depths0,rise_time_depths1,time_epi,max_slip, source_time_function,lognormal,slip_standard_deviation,scaling_law,ncpus,force_magnitude, force_area,mean_slip_name,hypocenter,slip_tol,force_hypocenter, - no_random,shypo,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep, + no_random,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep, max_slip_rule,rank,size): ''' Depending on user selected flags parse the work out to different functions ''' - from numpy import load,save,genfromtxt,log10,cos,sin,deg2rad,savetxt,zeros,where + from numpy import load,save,genfromtxt,log10,cos,sin,deg2rad,savetxt,zeros,where,argmin from time import gmtime, strftime from numpy.random import shuffle from mudpy import fakequakes @@ -38,12 +38,11 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na else: time_epi=UTCDateTime(time_epi) rise_time_depths=[rise_time_depths0,rise_time_depths1] - #hypocenter=[hypocenter_lon,hypocenter_lat,hypocenter_dep] tMw=tMw.split(',') target_Mw=zeros(len(tMw)) for rMw in range(len(tMw)): target_Mw[rMw]=float(tMw[rMw]) - + #Should I calculate or load the distances? if load_distances==1: @@ -63,6 +62,18 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na #Get TauPyModel velmod = TauPyModel(model=home+project_name+'/structure/'+model_name.split('.')[0]) + + # Define the subfault hypocenter (if hypocenter is prescribed) + if hypocenter is None: + shypo=None + else: + dist=((whole_fault[:,1]-hypocenter[0])**2+(whole_fault[:,2]-hypocenter[1])**2)**0.5 + shypo=argmin(dist) + + # Re-define hypocenter as the coordinates of the hypocenter subfault in + # case the original hypocenter did not perfectly align with a subfault + hypocenter = whole_fault[shypo,1:4] + #Now loop over the number of realizations realization=0 @@ -88,7 +99,6 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na current_target_Mw=target_Mw[kmag] ifaults,hypo_fault,Lmax,Wmax,Leff,Weff,option,Lmean,Wmean=fakequakes.select_faults(whole_fault,Dstrike,Ddip,current_target_Mw,num_modes,scaling_law, force_area,no_shallow_epi=False,no_random=no_random,subfault_hypocenter=shypo,use_hypo_fraction=use_hypo_fraction) - print(option) fault_array=whole_fault[ifaults,:] Dstrike_selected=Dstrike[ifaults,:][:,ifaults] Ddip_selected=Ddip[ifaults,:][:,ifaults] @@ -224,8 +234,7 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na #Calculate rupture onset times if force_hypocenter==False: #Use random hypo, otehrwise force hypo to user specified hypocenter=whole_fault[hypo_fault,1:4] - else: - hypocenter=whole_fault[shypo,1:4] + # edit ... # if rise_time==2: @@ -241,9 +250,7 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na shear_wave_fraction_shallow=1/60/60/24*2 shear_wave_fraction_deep= 1/60/60/24*2 - - - t_onset,length2fault=fakequakes.get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter,rise_time_depths, + t_onset,length2fault=fakequakes.get_rupture_onset(home,project_name,slip,fault_array,model_name,hypocenter,shypo,rise_time_depths, M0,velmod,shear_wave_fraction_shallow=shear_wave_fraction_shallow, shear_wave_fraction_deep=shear_wave_fraction_deep) fault_out[:,12]=0 @@ -395,19 +402,14 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na no_random=True elif no_random=='False': no_random=False - shypo=sys.argv[36] - if shypo=='None': - shypo=None - else: - shypo=int(shypo) - use_hypo_fraction=sys.argv[37] + use_hypo_fraction=sys.argv[36] if use_hypo_fraction=='True': use_hypo_fraction=True if use_hypo_fraction=='False': use_hypo_fraction=False - shear_wave_fraction_shallow=float(sys.argv[38]) - shear_wave_fraction_deep=float(sys.argv[39]) - max_slip_rule=sys.argv[40] + shear_wave_fraction_shallow=float(sys.argv[37]) + shear_wave_fraction_deep=float(sys.argv[38]) + max_slip_rule=sys.argv[39] if max_slip_rule=='True': max_slip_rule=True if max_slip_rule=='False': @@ -418,7 +420,7 @@ def run_parallel_generate_ruptures(home,project_name,run_name,fault_name,slab_na num_modes,Nrealizations,rake,rise_time,rise_time_depths0,rise_time_depths1,time_epi,max_slip, source_time_function,lognormal,slip_standard_deviation,scaling_law,ncpus,force_magnitude, force_area,mean_slip_name,hypocenter,slip_tol,force_hypocenter, - no_random,shypo,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep, + no_random,use_hypo_fraction,shear_wave_fraction_shallow,shear_wave_fraction_deep, max_slip_rule,rank,size) else: print("ERROR: You're not allowed to run "+sys.argv[1]+" from the shell or it does not exist") From 6ebdab524dba8a1f2cad8f52e5ab95467e020b8b Mon Sep 17 00:00:00 2001 From: JK Date: Tue, 18 Jun 2024 16:12:06 -0700 Subject: [PATCH 09/24] last round of testing --- TESTING | 1 + 1 file changed, 1 insertion(+) create mode 100644 TESTING diff --git a/TESTING b/TESTING new file mode 100644 index 0000000..038d718 --- /dev/null +++ b/TESTING @@ -0,0 +1 @@ +testing From 479c89b15811a1a65c290175d9a2139702d275ec Mon Sep 17 00:00:00 2001 From: JK Date: Tue, 18 Jun 2024 16:28:37 -0700 Subject: [PATCH 10/24] removing my tests --- TESTING | 1 - 1 file changed, 1 deletion(-) delete mode 100644 TESTING diff --git a/TESTING b/TESTING deleted file mode 100644 index 038d718..0000000 --- a/TESTING +++ /dev/null @@ -1 +0,0 @@ -testing From 41e08d6ed5fcb1cd19decfcfae4ba0edbc0ad814 Mon Sep 17 00:00:00 2001 From: JK Date: Mon, 1 Jul 2024 13:38:54 -0700 Subject: [PATCH 11/24] Edits to parallel and runslip under the runslip.inversionGFs function. Added capabilities to run a single force rather than a coupled force for greens functions and synthetics. the flag for it is single_force and changes how fk.pl runs the greens functions. For the synthetics it runs syn.c with only 6 greens parameters instead of 9. It also only requires three inputs on is the Magnitude of a m^2 force which I found in Allstadt 2013 on Mt. Meager which is 6e11 dyne --- src/python/mudpy/parallel.py | 147 +++++++++++++++++++++++++---------- src/python/mudpy/runslip.py | 38 +++++---- 2 files changed, 128 insertions(+), 57 deletions(-) diff --git a/src/python/mudpy/parallel.py b/src/python/mudpy/parallel.py index 1023762..e88bcc7 100644 --- a/src/python/mudpy/parallel.py +++ b/src/python/mudpy/parallel.py @@ -3,7 +3,7 @@ ''' -def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size): +def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force): ''' Compute GFs using Zhu & Rivera code for a given velocity model, source depth and station file. This function will make an external system call to fk.pl @@ -44,7 +44,8 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, pmax = %.3f kmax = %.3f insar = %s - ''' %(home,project_name,station_file,model_name,str(static),str(tsunami),dt,NFFT,dk,pmin,pmax,kmax,str(insar)) + single = %s + ''' %(home,project_name,station_file,model_name,str(static),str(tsunami),dt,NFFT,dk,pmin,pmax,kmax,str(insar),str(single_force)) print(out) #read your corresponding source file source=genfromtxt(home+project_name+'/data/model_info/mpi_source.'+str(rank)+'.fault') @@ -77,16 +78,28 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, print('MPI: processor #',rank,'is now working on subfault',int(source[ksource,0]),'(',ksource+1,'/',len(source),')') #Make the calculation if static==0: #Compute full waveform - command = "fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr - command=split(command) - p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) - p.communicate() - # Move files up one level and delete folder created by fk - files_list=glob(subfault_folder+'/'+model_name+'_'+depth+'/*.grn*') - for f in files_list: - newf=subfault_folder+'/'+f.split('/')[-1] - copy(f,newf) - rmtree(subfault_folder+'/'+model_name+'_'+depth) + if single_force==1: #compute for a single force and not coupled + command = "fk.pl -M"+model_name+"/"+depth+"/f -S1 -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr + command=split(command) + p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + p.communicate() + # Move files up one level and delete folder created by fk + files_list=glob(subfault_folder+'/'+model_name+'_'+depth+'/*.grn*') + for f in files_list: + newf=subfault_folder+'/'+f.split('/')[-1] + copy(f,newf) + rmtree(subfault_folder+'/'+model_name+'_'+depth) + else: + command = "fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr + command=split(command) + p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) + p.communicate() + # Move files up one level and delete folder created by fk + files_list=glob(subfault_folder+'/'+model_name+'_'+depth+'/*.grn*') + for f in files_list: + newf=subfault_folder+'/'+f.split('/')[-1] + copy(f,newf) + rmtree(subfault_folder+'/'+model_name+'_'+depth) else: #Compute only statics if insar==True: suffix='insar' @@ -106,7 +119,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, def run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,quasistatic2dynamic,tsunami, - time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,insar=False,okada=False,mu_okada=45e9,): + time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force=False,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 @@ -158,7 +171,8 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, insar = %s okada = %s mu = %.2e - ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(quasistatic2dynamic),str(time_epi),beta,custom_stf,impulse,insar,okada,mu_okada) + single = %s + ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(quasistatic2dynamic),str(time_epi),beta,custom_stf,impulse,insar,okada,mu_okada,single_force) print(out) #Read your corresponding source file @@ -233,6 +247,9 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, mu=get_mu(structure,zs) Mo=mu*ss_length*ds_length*1.0 Mw=(2./3)*(log10(Mo)-9.1) + + #Force of a square meter from a landslide in Dyne Allstadt 2013 on Mt. Meager in dyne + Mag=6e11 #Move to output folder if it doesn't exist create it #Check fist if folder exists @@ -267,39 +284,75 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, 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) + if single_force==True: + commandSS="syn -I -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -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)+" -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) + if single_force==True: + commandSS="syn -I -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -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: + 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)+ \ + if single_force==True: + commandSS="syn -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -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)+" -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)+ \ + 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) + 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) + if single_force==True: + commandSS="syn -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -S"+custom_stf+ \ + " -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() @@ -1249,7 +1302,12 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force insar=True elif insar=='False': insar=False - run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size) + single_force=sys.argv[15] + if single_force=='True': + single_force=True + elif single_force=='False': + single_force=False + run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force) elif sys.argv[1]=='run_parallel_synthetics': #Parse command line arguments @@ -1282,8 +1340,13 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force mu_okada=float(sys.argv[16]) NFFT = int(sys.argv[17]) dt = float(sys.argv[18]) + single_force=sys.argv[19] + if single_force=='True': + single_force=True + elif single_force=='False': + single_force=False - run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,quasistatic2dynamic,tsunami,time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,insar,okada,mu_okada) + run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,quasistatic2dynamic,tsunami,time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force,insar,okada,mu_okada) elif sys.argv[1]=='run_parallel_teleseismics_green': home=sys.argv[2] diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index f2cec60..826e910 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -177,7 +177,7 @@ def make_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,stat def make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,insar=False,okada=False): + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar=False,okada=False): ''' This routine set's up the computation of GFs for each subfault to all stations. The GFs are impulse sources, they don't yet depend on strike and dip. @@ -240,7 +240,7 @@ def make_parallel_green(home,project_name,station_file,fault_name,model_name,dt, print('Static Okada solution requested, no need to run GFs...') pass else: - mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_green '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(dt)+' '+str(NFFT)+' '+str(static)+' '+str(dk)+' '+str(pmin)+' '+str(pmax)+' '+str(kmax)+' '+str(tsunami)+' '+str(insar) + mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_green '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(dt)+' '+str(NFFT)+' '+str(static)+' '+str(dk)+' '+str(pmin)+' '+str(pmax)+' '+str(kmax)+' '+str(tsunami)+' '+str(insar)+' '+str(single_force) print(mpi) mpi=split(mpi) p=subprocess.Popen(mpi) @@ -366,7 +366,7 @@ def make_synthetics(home,project_name,station_file,fault_name,model_name,integra #Now make synthetics for source/station pairs def make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic, - tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,insar=False,okada=False,mu=45e9): + tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9): ''' This routine will take the impulse response (GFs) and pass it into the routine that will convovle them with the source time function according to each subfaults strike and dip. @@ -409,7 +409,7 @@ def make_parallel_synthetics(home,project_name,station_file,fault_name,model_nam #Make mpi system call print("MPI: Starting synthetics computation on", ncpus, "CPUs\n") mud_source=environ['MUD']+'/src/python/mudpy/' - mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_synthetics '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(integrate)+' '+str(static)+' '+str(quasistatic2dynamic)+' '+str(tsunami)+' '+str(time_epi)+' '+str(beta)+' '+str(custom_stf)+' '+str(impulse)+' '+str(insar)+' '+str(okada)+' '+str(mu)+' '+str(NFFT)+' '+str(dt) + mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_synthetics '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(integrate)+' '+str(static)+' '+str(quasistatic2dynamic)+' '+str(tsunami)+' '+str(time_epi)+' '+str(beta)+' '+str(custom_stf)+' '+str(impulse)+' '+str(insar)+' '+str(okada)+' '+str(mu)+' '+str(NFFT)+' '+str(dt)+' '+str(single_force) print(mpi) mpi=split(mpi) p=subprocess.Popen(mpi) @@ -421,7 +421,7 @@ def make_parallel_synthetics(home,project_name,station_file,fault_name,model_nam #Compute GFs for the ivenrse problem def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, dt,tsun_dt,NFFT,tsunNFFT,green_flag,synth_flag,dk,pmin, - pmax,kmax,beta,time_epi,hot_start,ncpus,custom_stf,quasistatic2dynamic=0, + pmax,kmax,beta,time_epi,hot_start,ncpus,custom_stf,single_force=False,quasistatic2dynamic=0, impulse=False): ''' This routine will read a .gflist file and compute the required GF type for each station @@ -460,7 +460,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False insar=False make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,insar) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar) i=where(GF[:,3]==1)[0] if len(i)>0 : #displ waveform print('Displacememnt GFs requested...') @@ -471,8 +471,10 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, f.close() static=0 tsunami=False + if single_force==1: #Using single force not coupled + single_force=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force) i=where(GF[:,4]==1)[0] if len(i)>0 : #vel waveform print('Velocity GFs requested...') @@ -483,8 +485,10 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, f.close() static=0 tsunami=False + if single_force==1: #Using single force not coupled + single_force=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force) if tgf_file!=None: #Tsunami print('Seafloor displacement GFs requested...') # static=0 @@ -492,7 +496,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=True station_file=tgf_file make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force) i=where(GF[:,6]==1)[0] if len(i)>0: #InSAR LOS print('InSAR GFs requested...') @@ -505,7 +509,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False insar=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,insar) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar) collect() #Synthetics are computed one station at a time if synth_flag==1: @@ -525,7 +529,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=False insar=False - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,insar) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar) #Decide which synthetics are required i=where(GF[:,3]==1)[0] if len(i)>0: #dispalcement waveform @@ -538,11 +542,13 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, f.close() integrate=1 static=0 + if single_force==1: #Using single force not coupled + single_force=True if tgf_file==None: # I am computing for stations on land tsunami=False else: #I am computing seafloor deformation for tsunami GFs, eventaully tsunami=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force) #Decide which synthetics are required i=where(GF[:,4]==1)[0] if len(i)>0: #velocity waveform @@ -555,11 +561,13 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, f.close() integrate=0 static=0 + if single_force==1: #Using single force not coupled + single_force=True if tgf_file==None: # I am computing for stations on land tsunami=False else: #I am computing seafloor deformation for tsunami GFs, eventaully tsunami=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force) #Decide which synthetics are required i=where(GF[:,5]==1)[0] if len(i)>0: #tsunami waveform @@ -574,7 +582,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=True station_file=tgf_file - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force) #Decide which synthetics are required i=where(GF[:,6]==1)[0] if len(i)>0: # InSAR LOS @@ -589,7 +597,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=False insar=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,insar) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar) From 9942ccc36f0687c000e4f9465e65d639f62df54a Mon Sep 17 00:00:00 2001 From: JK Date: Mon, 8 Jul 2024 13:37:51 -0700 Subject: [PATCH 12/24] Working on landslide feature and set up so that it runs properly with velocities adding the strikes to be oriented at 0 and 90 degrees to north and for now a dip of zero assumming that these are being used to descripe a vector for and the strike is the direction it is pointing and dip is the elevation change --- src/python/mudpy/inverse.py | 4 ++-- src/python/mudpy/parallel.py | 40 +++++++++++++++++++++--------------- src/python/mudpy/runslip.py | 2 +- 3 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/python/mudpy/inverse.py b/src/python/mudpy/inverse.py index 77d5f16..2ddf9ba 100644 --- a/src/python/mudpy/inverse.py +++ b/src/python/mudpy/inverse.py @@ -700,7 +700,7 @@ def getdata(home,project_name,GF_list,decimate,bandpass,quiet=False): #Read gf file and decide what needs to get loaded gf_file=home+project_name+'/data/station_info/'+GF_list GF=genfromtxt(gf_file,usecols=[3,4,5,6,7],skip_header=1,dtype='f8') - GFfiles=genfromtxt(gf_file,usecols=[8,9,10,11,12],dtype='U') + GFfiles=genfromtxt(gf_file,usecols=[8,9,10,11,12],dtype='U') stations=genfromtxt(gf_file,usecols=0,dtype='U') #Parse out filtering pass bands @@ -728,7 +728,6 @@ def getdata(home,project_name,GF_list,decimate,bandpass,quiet=False): for ksta in range(len(i)): if quiet==False: print('Assembling displacement waveforms from '+str(stations[i[ksta]])+' into data vector.') - #print(str(GFfiles[i[ksta],kgf])) n=read(GFfiles[i[ksta],kgf]+'.n') e=read(GFfiles[i[ksta],kgf]+'.e') u=read(GFfiles[i[ksta],kgf]+'.u') @@ -769,6 +768,7 @@ def getdata(home,project_name,GF_list,decimate,bandpass,quiet=False): for ksta in range(len(i)): if quiet==False: print('Assembling acceleration waveforms from '+stations[i[ksta]]+' into data vector.') + print(GFfiles[i[ksta]],kgf) n=read(GFfiles[i[ksta],kgf]+'.n') e=read(GFfiles[i[ksta],kgf]+'.e') u=read(GFfiles[i[ksta],kgf]+'.u') diff --git a/src/python/mudpy/parallel.py b/src/python/mudpy/parallel.py index e88bcc7..dc83b7a 100644 --- a/src/python/mudpy/parallel.py +++ b/src/python/mudpy/parallel.py @@ -205,8 +205,13 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, xs=source[1] ys=source[2] zs=source[3] - strike=source[4] - dip=source[5] + if single_force==True: + strikeSS=0 + strikeDS=90 + dip=0 + else: + strike=source[4] + dip=source[5] rise=source[6] if impulse==True: duration=0 @@ -243,13 +248,14 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, #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) - - #Force of a square meter from a landslide in Dyne Allstadt 2013 on Mt. Meager in dyne - Mag=6e11 + if single_force==True: + #Force of a square meter from a landslide in Dyne Allstadt 2013 on Mt. Meager in dyne + Mag=6e11 + else: + #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 if it doesn't exist create it #Check fist if folder exists @@ -285,11 +291,11 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, #First Stike-Slip GFs if custom_stf==None: if single_force==True: - commandSS="syn -I -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -D"+str(duration)+ \ + commandSS="syn -I -M"+str(Mag)+"/"+str(strikeSS)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -D"+str(duration)+ \ + commandDS="syn -I -M"+str(Mag)+"/"+str(strikeDS)+"/"+str(dip)+" -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: @@ -302,11 +308,11 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, commandDS=split(commandDS) else: if single_force==True: - commandSS="syn -I -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -S"+custom_stf+ \ + commandSS="syn -I -M"+str(Mag)+"/"+str(strikess)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -S"+custom_stf+ \ + commandDS="syn -I -M"+str(Mag)+"/"+str(strikeDS)+"/"+str(dip)+" -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: @@ -321,11 +327,11 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, #First Stike-Slip GFs if custom_stf==None: if single_force==True: - commandSS="syn -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -D"+str(duration)+ \ + commandSS="syn -M"+str(Mag)+"/"+str(strikeSS)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -D"+str(duration)+ \ + commandDS="syn -M"+str(Mag)+"/"+str(strikeDS)+"/"+str(dip)+" -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: @@ -338,11 +344,11 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, commandDS=split(commandDS) else: if single_force==True: - commandSS="syn -M"+str(Mag)+"/"+str(strike)+"/"+str(dip)+" -S"+custom_stf+ \ + commandSS="syn -M"+str(Mag)+"/"+str(strikeSS)+"/"+str(dip)+" -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(Mag)+"/"+str(strike)+"/"+str(dip)+" -S"+custom_stf+ \ + commandDS="syn -M"+str(Mag)+"/"+str(strikeDS)+"/"+str(dip)+" -S"+custom_stf+ \ " -A"+str(az[k])+" -O"+staname[k]+".subfault"+num+".DS.vel.x -G"+green_path+diststr+".grn.0" commandDS=split(commandDS) else: diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index 826e910..a4fc000 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -1,6 +1,6 @@ ''' Diego Melgar, 01/2014 -Runtime file for forward modeling and inverse kinematic slip inversions +Runtime file for forward modeling and in verse kinematic slip inversions ''' From c50001529ad53334fea51f194610ef6846be4837 Mon Sep 17 00:00:00 2001 From: Marcus Adair <46729081+Marcus-Adair@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:43:26 -0600 Subject: [PATCH 13/24] Create send_update_signal.yml --- .github/workflows/send_update_signal.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/send_update_signal.yml diff --git a/.github/workflows/send_update_signal.yml b/.github/workflows/send_update_signal.yml new file mode 100644 index 0000000..2a4f396 --- /dev/null +++ b/.github/workflows/send_update_signal.yml @@ -0,0 +1,22 @@ +name: Dispatch Event on Master Update + +on: + push: + branches: + - master + +jobs: + dispatch: + runs-on: ubuntu-latest + steps: + + # Send a signal to on_demand_fakequakes repo that MudPys been updated + - name: Send repository dispatch event + run: | + curl -L \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.CICD_PAT }}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/UO-Geophysics/on_demand_fakequakes/dispatches \ + -d '{"event_type":"repo-update","client_payload":{"unit":false,"integration":true}}' From 887ad3076227cfb247d01bcd35e81cce2ca4b46e Mon Sep 17 00:00:00 2001 From: Marcus Adair <46729081+Marcus-Adair@users.noreply.github.com> Date: Wed, 17 Jul 2024 09:48:18 -0600 Subject: [PATCH 14/24] Update send_update_signal.yml --- .github/workflows/send_update_signal.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/send_update_signal.yml b/.github/workflows/send_update_signal.yml index 2a4f396..9b7629e 100644 --- a/.github/workflows/send_update_signal.yml +++ b/.github/workflows/send_update_signal.yml @@ -9,8 +9,6 @@ jobs: dispatch: runs-on: ubuntu-latest steps: - - # Send a signal to on_demand_fakequakes repo that MudPys been updated - name: Send repository dispatch event run: | curl -L \ From f5883aa0e24a3539e8221fc39799d63b548fa274 Mon Sep 17 00:00:00 2001 From: Diego Melgar Date: Mon, 12 Aug 2024 10:47:54 -0700 Subject: [PATCH 15/24] Fixed repr error in insar GFs --- src/python/mudpy/parallel.py | 1 + src/python/mudpy/runslip.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/python/mudpy/parallel.py b/src/python/mudpy/parallel.py index 1023762..271d19c 100644 --- a/src/python/mudpy/parallel.py +++ b/src/python/mudpy/parallel.py @@ -1250,6 +1250,7 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force elif insar=='False': insar=False run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size) + elif sys.argv[1]=='run_parallel_synthetics': #Parse command line arguments diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index 2c2c3c0..2ea5717 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -498,7 +498,8 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, print('InSAR GFs requested...') f=open(home+project_name+'/data/station_info/'+station_file,'w') for k in range(len(i)): #Write temp .sta file - out=stations[i[k]]+'\t'+repr(GF[i[k],0])+'\t'+repr(GF[i[k],1])+'\n' + #out=stations[i[k]]+'\t'+repr(GF[i[k],0])+'\t'+repr(GF[i[k],1])+'\n' + out='%s\t%.8f\t%.8f\n' % (stations[i[k]],GF[i[k],0],GF[i[k],1]) f.write(out) f.close() static=1 From b9cc782eba1c3d2e906e8ddc8905a0ebf99aee64 Mon Sep 17 00:00:00 2001 From: Diego Melgar Date: Mon, 12 Aug 2024 11:05:23 -0700 Subject: [PATCH 16/24] Fixed repr error in insar synths --- src/python/mudpy/runslip.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index 2ea5717..c76c58c 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -583,7 +583,8 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, #Make dummy station file f=open(home+project_name+'/data/station_info/'+station_file,'w') for k in range(len(i)): - out=stations[i[k]]+'\t'+repr(GF[i[k],0])+'\t'+repr(GF[i[k],1])+'\n' + #out=stations[i[k]]+'\t'+repr(GF[i[k],0])+'\t'+repr(GF[i[k],1])+'\n' + out='%s\t%.8f\t%.8f\n' % (stations[i[k]],GF[i[k],0],GF[i[k],1]) f.write(out) f.close() integrate=0 From 9a31611ad607b33feaaf1141483a44eaea61557b Mon Sep 17 00:00:00 2001 From: Diego Melgar Date: Thu, 29 May 2025 09:26:47 -0700 Subject: [PATCH 17/24] Too many changes to give them a pithy commit message --- examples/notebooks/planar_geometry.ipynb | 118 +++++++++++++++++++++++ src/python/mudpy/forward.py | 31 ++++-- src/python/mudpy/gmttools.py | 25 +++-- src/python/mudpy/insartools.py | 2 +- src/python/mudpy/runslip.py | 13 +++ src/python/mudpy/view.py | 26 ++++- 6 files changed, 197 insertions(+), 18 deletions(-) create mode 100644 examples/notebooks/planar_geometry.ipynb diff --git a/examples/notebooks/planar_geometry.ipynb b/examples/notebooks/planar_geometry.ipynb new file mode 100644 index 0000000..5b5fd65 --- /dev/null +++ b/examples/notebooks/planar_geometry.ipynb @@ -0,0 +1,118 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Make the faulty geometry that is going to be used in FakeQuakes\n", + "\n", + "We're going to start with a planar geometry" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append('/Users/dmelgarm/code/MudPy/src/python')\n", + "from mudpy import forward" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "#Parameters of hte fault grometry\n", + "\n", + "fout = '/Users/dmelgarm/Seattle_fault/Geometries/planar.fault'\n", + "strike = 90 # south dipping east-west strike\n", + "dip = 40\n", + "nstrike = 30 \n", + "dx_dip = 2.0 # in km\n", + "dx_strike = 2.0 # in km\n", + "center_of_fault = [-122.402, 47.579, 5.0] # lon, lat, depth (km)\n", + "num_updip = 3\n", + "num_downdip = 3\n", + "rise_time = 2.0\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hi\n" + ] + } + ], + "source": [ + "forward.makefault(fout,strike,dip,nstrike,dx_dip,dx_strike,center_of_fault,num_updip,num_downdip,rise_time)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "from mudpy import view" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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AE4//XRReVNAtD7FKkfoKdInIzz77LO2Rc0VV1zB3XffnbA+MjIyePHFFxk7diwAd999N2vWrOm3su4ttLa28t577wFtx7joNoi8oHSGYRh98oVL6B4+nw+AnJycgS1IP5OoDQv9h9yDvYPPP/+cmpoasrKy9johtr/Jysri+9//vi2Q9AWmafL3v/8dgFNOOSWutfzll1/OuHHjgPiCw66SB8CUKVM45JBDevxB+6STTuKqq67qIJDE8oc//AFdj0zT33rrrW6fIxQK2ZbU48aN45BDDulRWfdmeiySWJbFG2+8AfT9g0opxX/+8x9OOeUUBg8ejMvlIjs7m1GjRnHCCSdw//33s3HjxoTp16xZw/XXX8/48ePxer2kpaUxatQorrrqKpYtW5YwXXunb++88w5nnnkmJSUlOByODp1rzpw5XHLJJYwYMYK0tDTS09MZPnw4kyZN4pZbbuGrr75KeK5Fixaxbt06nE4nJ598ctxjZs2axcknn0x+fj7p6emMHj2aW265hdra2sSVt4Oo055nnnkGpRRPPPEEkydPJjc3l+zsbCZPntxGcQRYuXIlV199NSNGjMDj8TB48GCuvPJKtmzZ0uX5tm3bxm233cbEiRPJzc3F7XYzbNgwLr74Yr788ssu03eGz+fjnnvuYfz48aSnp5Ofn88xxxxjDwZdOQxdsmQJd999N8cffzz77LMPGRkZZGZmMmbMGH7605922ibaO8j1+/3cf//9HHrooeTm5tp1DB2dbM6fP58LL7yQkpIS0tLS2Geffbj11ltpaGiw8/f7/Tz88MNMnDiR7OxssrKyOProo3n77be7rJdU98lQKMTrr7/OT3/6Uw477DBKSkpwuVzk5+czdepU/vSnP9HS0tKrc9xyyy12ff7mN7/psL+nfTfqzC89PT0px34ej4eHHnoIgHA4zMMPP9zhmLKyMjRN46677uo0r9i+1h6fz8fzzz/PZZddxsSJEykuLsblclFYWMjxxx/PE088QTAY7LK8iQiFQrbzZ8Mw+Nvf/tbhmAULFvCTn/yEfffdl8zMTDIyMthvv/244YYbunRg+9Zbb3H22WczdOhQ3G43WVlZjBgxgqOPPpq7776703vy/vvv4/P5KCoq4vDDD7e3b9++3f5/VlZWD666LT1tMz1t79Ex4YorrrC3xXOYBjvHhKjz2ah4F/vrqn2l8pq7Q+zYF3X+1r78sWWvr6/n6aef5oILLuDAAw+0HSYPHjyY0047jf/9738opRKeLxX9rbPrSOZ+tSdRG45l7ty5XHrppZSVleHxeMjJyWHChAnceeednT6rk3UyG69eog78nn32WQA+/vjjDtcT+77S3nFlbW0tt9xyC6NHj7afqd/73vc6fTFP1jF3PGfTfXUPYtuCaZo89thjHHnkkQwaNAhd1+06S9bRfWcOPtvn0drayv/7f/+PAw44wHYCedRRR/Hvf/87bt5lZWWUl5fbfx977LEdrj+2bKnoD+3zeP755znxxBMpLi7GMIy4be/VV1/l3HPPZejQoXg8HnJzczniiCO4//77O33+h0IhHnvsMY499lgGDRqE0+kkLy+P0aNHc/rpp/Poo49SXV2dMH3UWuh73/temyUCqWi7XdHbsat9X/78888555xzGDJkCG63m6FDh3LllVd26kSzt+8K7fvdF198wcUXX8ywYcNwuVz97lD/s88+o6amBoDzzz8/4XHnnXceEHlPae+kfVfJo78YNGgQhYWFAGzevLnb6d966y37/ao3ViTdaUu9eY4lyuPNN9/ke9/7HkVFRaSlpbHvvvty8803U1dX1yFt9LkUXWb07LPPdhhXu+XIvafOTD799FMFqMzMTOX3+9vsS6Xj1nA4rL7//e936ZDmgQceiJv3I488opxOZ8J0DodDPf7443HTxjp+ueWWWzqkjXWO9sADD3RZxlNPPTVhHdxzzz0KUMcff3zc/b/+9a8T5jt8+HD10UcfdeoALLrviSeeUKeddlrCvH7/+98rpZR6++23VWZmZtxjhg4dqjZv3pzwWv73v/+pjIyMTuvijjvuiJu2K2efW7duVWPGjEmY749+9KNO86ivr+/yPjmdTvWPf/wj7vljHVy98MILavz48R3Sz5gxQynV1oneP/7xj4TtcMKECaqhoUFVV1erI444Iu4xmqapZ599NmGdK9V5n+yJc+Tp06d3WVejR49W69evj5u+s/sQCoXU5Zdfbl/bI4880uGYnvbdZcuW2cdceumlSV2rUkpZlmU71CwuLu6wP1lnm+3bQSzXX399l3V6xBFHqLq6urh5d+aYsbm5WZ100kkKUG63W73wwgsdru/mm2/u1FlYRkaGev311+Oe+9prr+2y7Ndcc03CernyyisVoH784x+32X7zzTfb6V988cWE6ZOhN+N9T9t7V07voj+lOnf2Fv3Ftq9kHFv25pq7QzLXGVv2M888s8vjzzjjjISO5FLR3+I5b+vO/WpPojasVKR/3XjjjZ3mmZ+frz7//PO4eSfraC5evSTjwC92zIh1XPnhhx/aecb73XjjjXHLkaxj7nhjVl/dg2i6xx57TB1zzDEJ22eyDlM7c/AZm8fLL7+sDjjggITXccEFF6hwONwmfWd1Hq9sqegP0TzuuOMOddFFF3U4X2zbq6+v79KZ9siRI9WqVas6nKepqSnhu0zsb+bMmQmvY9SoUQpQ//rXv9psT0Xb7cpxa2/Hrti+/PDDD9tOhuONB4sXL46bRyrfFf7yl78owzDapO2q30b7d6I66i4PPvignV9nzpbfffdd+7iXXnppl8wjEfH6UW8IBoPK5XIpQP3gBz/odvqzzjpLAcowjC4d2XZGd9pSb55j8fK44447Erb/kpIStWLFijZpY9ttol937k+PRZLoy8DZZ5/dYV8qRZInn3zS3nfuueeqjz/+WG3atElt27ZNff311+qf//ynOvXUU9X06dM75Pu3v/3NTnvCCSeoN954Q23ZskVVV1erTz75RJ166qkKIpO0eNFkojeqpKREQUTk+Pjjj9X27dvVhg0b7DQrVqywG83BBx+sXnrpJbVu3TpVXV2tFi1apF577TX1ox/9SF100UUJ6+CQQw5RgHr00Uc77Hv66aft6zjggAPUm2++qaqqqtTatWvVgw8+qDIyMlR5eXnCOlRqZ+ctLy9XTqdT3X777Wrp0qWqpqZGzZkzx36gGYah3nnnHeX1etWECRPU66+/riorK9WmTZvUQw89pBwOhwLUxRdfHPc63nzzTXsSdsghh6j//e9/auPGjaq2tlZ99dVXbdrGk08+2SF9Zy9epmmqKVOm2OmvvfZa9d1336mamhr19ddfq0suucR+cCfKo76+Xo0bN07ddttt6t1331VLlixR1dXVatWqVeqVV15R06ZNU4ByuVzqu+++65A+9sWopKREeTwedffdd6tly5apmpoaNX/+fLVkyRKl1M5+MGTIEOV2u9W0adPUhx9+qLZv367WrFmjfvOb39h53X777eqMM85QmZmZ6oEHHlCrV69WNTU16v3337dFIa/Xq2pqauLWu1Kd98meiCR/+9vf1Mknn6z+/ve/q88++0ytW7dObd++XS1cuFA9+OCDdr844ogj4qZPdC9bWlrsvudyudR//vOfuOfuad994okn7LRPPfVUUtcaJdqGALV69eo2+1Lxknr77berc845Rz377LPqiy++UBs3blSVlZVq/vz56o477lC5ubkKIi/V8Ugkkmzfvl0ddthhdjuJd49jhdbzzjtPffDBB6qyslJVVVWpt99+W02aNElBJNLPokWL2qR9//337bTHHXecmjVrltqwYYOqqqpS3377rZo5c6Y677zz1E033RS33KZpqqKiIgWo1157rc2+2JeR3Nxc9de//jXhi19n9Ha872l7tyxLNTU1qccee8w+f1NTU4efUkr5/X7V1NSkhg0bpgD1m9/8psNxsS/eXYkkvb3m7hC9zs7KH1v2H/3oR+rSSy9V//3vf9VXX32lNm/erDZv3qy++OILdcMNN6i0tDQFqFtuuSXu+fpKJOnO/YqlszaslFL33nuvnd+hhx6qZs2apaqqqtS6devU9OnTldfrtfvn2rVrkyprsvUSCoVUU1OTuvjiixWgpk6d2uF6fD6ffXzsJLG8vFxlZmaqBx98UK1du1ZVVVWpt956Sx100EH2MfFEtt6IJH11D2KfzbquqxtuuEEtWLBA1dTUqCVLlqh58+YppVIvksS+Vy1fvlxVV1erjz76SB133HH2MbHR5pSKPAeXLFli73/rrbc6XH+ssJJKkSQ6ll122WXqyy+/VNXV1Wr16tXq448/VkpF2tPUqVMVRAT3W265Rc2fP1/V1NSoiooKNWPGDDsyyOjRo1Vzc3Ob89x+++12OX7605+qL7/8Um3dutXu/48//rg6+uijE4riixcvVhAReGtraxPek5623a5Ekt6OXdG+XF5erjRNU6eddpr66KOP7LnDn/70J1vYnjJlStw8UvWuUFRUpBwOh5o0aZJ6++237ff5N954I266KKkWSX784x8rQOm6roLBYMLjVq1aZZ/3D3/4wy6ZRyKix6dKJHnhhRfsPB966KFupa2pqbEFlu9973u9Kkd32lIqRZKysjIFqGnTpqmPP/5YVVdXq+XLl6vbbrvNnouOGjWqzbMtEAiopqYme/y6+OKLO4yr7T8id0aPRZJ9991XAXG/bqdSJDn77LMVRMSH7oQA27p1qx2i8Gc/+1nC4y688EIFqPHjx3fYF71RgDr//PMTnv/RRx9VEBEYEoVq6ozNmzfbwkL7r5R+v18VFBTYD6OGhoYO6d977702X4c7E0kA9fzzz3fYX1NTY7/EGYahJkyY0KbhRbntttsURCa3jY2Nbfa1trbaLzCnn366CoVCca83apUzaNCgDufo7MXrv//9r30Nd911V9y8r776avuYnoaePf/88xWgfvjDH3bY1/4L2Jtvvpkwn9h+cOqpp3b4kqSUsl9qDcNQDodDffbZZx2OWbFihX1///73vyc8X2d9MraPxXsZi/7av+x0xubNm1VOTo4C1OzZszvsj3cva2pq7Ml4Zmameu+99zqk623fvfXWW+1rnTt3btLXo5RSf/zjH+207cuWipfUrvjuu++UYRhK07QOIo1S8Scc69evV6NHj1YQsYD59ttvO6T75ptv7DZ03333xT13MBhURx55pN1eY/nlL3+pAFVYWNijEHJz5sxRgEpPT487rnzve99r068Mw1AHHXSQ+vGPf6wef/zxLsN8pmK874qu2nt/hwDuj2tORLLl74y33nrLHgfaP0u6c47O+lsqQwB31oYrKyuV2+1WgDrssMPitvEvvvjCnhidc8453SprLJ3VS7IhgGMniZqmxX1naGxsVPvtt5+CiHjZnWd1smVK5T1Qqu17zl//+teE+aRaJAHUM8880yF9KBRSxx57rILIhL+ioqJH5VAqtSIJoG6++eaEeTz88MMKIla1n376adxjKioq7HfT9pbcEyZMUIA688wzOy1rIv7whz8oQB177LEd9qWi7fY2BHBXY1fs3OGKK66Im8f9999vH7N8+fJulyHZdwWIiKbdfW6nWiSJWufk5+d3elxDQ4N93l/+8pe7ZB6JiB6fCpGktbVV7bPPPgpQWVlZavv27d1K/+c//7nTOV936E5bSqVIApHVFfHmkrEGFPfee2+Py9EVPfJJsnz5clauXIlhGJx66qk9ySJpwuEwEAlL1R1HlI899hh+v5/8/Hz+9Kc/JTzuj3/8IwCLFy+2Pfa3xzAMHnrooYTnj5YxIyOD3NzcpMsY5bXXXkMpxUEHHdQhfOLrr79ur9v8wx/+gNfr7ZD++OOP56yzzkrqXFOmTIm7Di8vL48TTjgBiDg2uu+++0hLS+tw3AUXXABAMBhkwYIFbfY9//zzVFZW4nA4+Pvf/57QIdFvf/tb0tPT2b59ux3VIhmia2yLioq4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ElsX0TS7Wh59yTPPPGNb+06aNIn//ve/3RZsolYkQPciuXTBrjiuRlm/fr0dCSiVdNuSpKqqyjb5T6Tmx06wkwlnGTVTbZ8WIhOVr776imuuuYacnBx8Ph/vvfced999N8ceeywlJSVMnz69w9fjnrx0+f3+uNujA1lnvPDCC9x3332Ul5djWRbz5s1j+vTpnH322RQWFnLNNdfQ2NjYId2sWbMIBAIMHTrUNh2KJTpId9VJk+3E8ZZ89OQY6PjFPpV13p7Yh1VGRkanx3ZWFw8++KAtkJx++um8+OKLLF++nOrqapqammhqauLNN9+0j4+ajcYjmXYByddnMsfFs5JIpk92F9M0Ofvss1m3bh0ZGRncdtttfPzxx2zcuJHa2lq7ri688EKg83oKhUL2/UtPT++y3nrbjmIH8qVLl3YrnyVLltj/33fffbtdjs5obGzkzDPPZPv27QwaNIg//vGPzJ07l82bN1NfX2/XaXTJVWd16vP57GvOysrq9EtBTyegsXXqdDr56KOPuPXWWykuLiYYDPLpp59y7733csopp1BUVMRvf/vbuON9VMCbPHmy/eUsWcrLy7nyyiuZM2eOLZwA/N///V+b43rbZlLZ3vuLvhxve8v69eu54IILaG5upqysjEcffZSvv/6arVu30tDQYNdn1Bx/V6jPzuiqDUctDrt6DscKmZ1ZKfYnyb5bDHR5uzOOJPtsThW7Sx1G6ax+UvG8KC8v55tvvuHSSy8lPT2dhoYGXn/9dW699VaOOOIIRowYwb/+9a+4+bz22mtAcu8yfVHvqRy7Ei05b0/797pUviv0d19IRNSasa6urlPLoliLgPbWpLtKHn3FCy+8wI9//GPb/cJbb73V5XynPZZl2X1rn332YdKkSSkr3646rkLfja3dtiR5/fXXsSyLcePGtVkqEEvsF9j6+vou1Z3Yr73xTNOKior485//zCOPPMK3337LF198wezZs5k1axZVVVXccMMNrF+/vs0X0szMTOrr6/nFL36R9JfT3uByubj55pu5+eabWbVqFXPnzuWTTz7hjTfeoLKykr/+9a98+eWXfPHFF20Gzq4sAKKNoLN49DAwa+baEy3r97//fV555ZU+yRt6Vxd/+ctfgIgJ2vPPPx/3mFjRbncgmT7ZXT7++GMWL14MRAbu733ve3GP6+peQKT/Tp8+nfPOO4+5c+dy4okn8s4775CdnR33+N723dg11B999FGbtb+doZTik08+AaC4uLjDV6xk1PzOXlZeeOEFKisr0XWdDz/8MOFX52QG+4kTJ/KDH/yA6667jldeeYVzzz2XmTNnxrU2i+07Dz/8MNdff32X+ccjKyuL//f//h+///3vWbJkCXPnzuWjjz7izTffpKGhgd///vcsWrSoQ99P1kS+K/7whz/w5JNPUl9fz/z589vs622bSWV77y/6+xnXHZ5++mn8fj9er5cvvviCoqKiuMfF+3AQpbf9LZV01Yaj4kdXz+HY/e0tv5L9Wpjqa072eTrQ5U3VOAKpL3tP67A79Fd/iH1efPvtt3F9XCXDyJEj+cc//sGTTz7JV199xdy5c/nggw94//33Wb9+PZdeeinV1dVtnkctLS22f41k7nNf1Hsqxq7eksp3hV2FqAW4ZVmsX78+4RL0WEvO9lbju0oefcGbb77JRRddhGmajBkzhnfffbdH1swffPABmzZtAojrJ6mvSeXY2p25Xm/G1s7otiVJMmb9sRO1ZL7kLlu2DIioru0dl8ZiGAaHHHII1157LS+99BIVFRW2SvbnP/+ZmpqaDmWIXVffX+yzzz788Ic/5Mknn6SiooJrrrkGiCxDeeONN+zjTNPkrbfeAhLXZ1lZGQBr1qzp1ConWocDSbTOv/3225TnnZ2dbQ8YXa1fT7S/traWiooKAPuLcDwWLVrUs0IOEH2x/C3qlDc3NzfhhBGSr6szzzyTF154AZfLxZdffsmJJ56Y8ItVb/vumDFjbDO8F198MWkHrO+88w4bN24EImbG7Qf7qLVGZ2aamzdvTrgvWqcHHHBAwpeeYDDIypUrkyrvNddcw1//+lc0TeO1117j3HPPjTtGZGdn219CUjEeaprG+PHjueqqq/j3v//N5s2bbcfRr776ahuHztXV1cyZMwfofft0Op22dU978+TetplUt/f+YCCfcV0Rrc/jjjsu4SRj48aNnU40etvfUkUybTj6nI61RItHVIiLTRMlmesNhUIpXzLV2buDaZq288CelBdSc49SOY5AW6eNqWhfXb1/Rfe3r8Pu0F/9Ifb9PRVji8vlYsqUKdx44428/fbbrFmzhlGjRgFwzz33YJqmfew777yD3+9nyJAhTJw4scu8e9p2OyMVY1dvSfW7wq5A7P384osvEh4X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W9XMmTPV2LFjla7ravTo0QmvsbN7OWvWLOXxeBSgDj74YFVTU9Nmf2/7rlJKbd26tc29nDx5snruuefU2rVrVU1NjVq6dKl69NFH1fDhw+1jLrnkEmWaZtz8li9frhwOhwLU+PHj1bvvvqtqamrUxo0b1YwZM9TQoUPtthevf6xatcruG6NGjVIvvfSS2rJli6qoqFAzZsxQpaWlKj093S5PvHGnszb19NNPK13XFaBOOukk1dra2mb/rbfeapdt/PjxasaMGWr16tWqrq5ObdmyRX322Wfq/vvvV4cccogaN25cm7RHH320GjdunLrnnnvURx99pDZv3qxqa2vVsmXL1PTp0+22MmTIEPu8ra2tKj09XQFqzpw5cetUKaV+9atfKUCVlpaqm266Sb355ptq7dq1qq6uTm3evFm9++676tJLL1WapilAZWVlqfXr13fIpzdtJhXtvbKy0r6/V111ldq0aZMKBoMqFAqpUCjU5thrr71WASovL099+OGHqrm52T4utv3F9tt4pKKf9IRoG73zzjvj7v/www/tck2cOFG9++67qrKyUq1du1ZNnz5d5ebmquLiYpWXl5cwn972N6U6f4Ync7+SbcNKKXXvvffaZTniiCPUO++8Yz+nH3nkEbt9eb3eDs8VpZSqra1VXq9XAWro0KHqpZdeUtu3b1dbtmxRM2fOVOPGjVP5+fkqJycnYZ298MILdhn+/ve/q9raWvt6Yt+vYu9PWVmZysrKUg899JBav3692r59u3r77bfVhAkT7GMef/zxuNd85JFHKkC53W718MMPq4qKClVdXa0+/vhjddpppylN0+x3k572me7cg2Tec6I89dRT9vFnnXWW+vbbb1VdXZ1avny5uueee1RaWlqb9tXZu0BZWZlyOp3qjjvuUCtXrlQ1NTXqk08+UdOmTbOPufXWW+OWY/z48QpQhx9+uFqyZIny+/329VuWZR+Xiv7QVb+NEgwG1THHHGPnddppp6nXX39dbdq0SdXV1an169erWbNmqZtvvlkNGzZMXXPNNW3Sa5qmpk2bpv7yl7+or7/+WlVWVqqqqio1f/58dcMNN9hj+dlnn22n+fjjj+3x3e/3JyxbKtpubB7t72sqxq5k5w6J7kdfvyvEY8mSJWru3Ln278orr7Tr4aWXXmqzr6KiokP62P6Q6Lrr6urU0KFD7XHwiSeeUJs3b1YbNmxQ9913X5v5XPtn5q6WR0NDQ5s6mTt3rn39p5xySod97Vm2bJkaNGiQXYY5c+aopqamhL+WlpYEd24n0T6bmZmZ1PFRYudF8Z5N3WlLqXiORftPWVmZAtQJJ5ygPvnkE1VdXa1WrFihfvvb3yqn02n3D5/P1yGPBx98UAHK5XKpl19+WTU0NMR9x+qKpEUS0zTtG/rGG28kleb9999X+fn5duUn+p1wwgkdJklRYicwiX5lZWVqxYoVcdM/9dRTKi0trcs88vLyOqTtjkjSVf5paWnq5ZdfttN89913ClAOh0PV1dV1WZe//vWvE+Y9dOhQNXv2bPvvgRRJlFLqjTfesB8gnf0Mw1C1tbXdKsOWLVvUmDFjEuZ5+eWXqzvuuENBRCxpz7Zt29oISu1/Rx11lHrrrbeSejEaaJGkO32yuyKJUkr95z//sR/U7X+6rqtHH32002vs6l6+++67dt886KCDVHV1dZv9vem7UWpra9UPfvCDLvPIzMxUDz74YJuX0njcf//9CfMoLS1Vy5Yt67R/dJbe4/GoF154odNxp6s29cwzz9hCyQknnNDm4WFZlvr973+f8J7G/tqLztEydfbLz89vM4l57bXXFKAKCws7fSjdfffdXeYdO9Z1NlHqTZvpbXuPvT/xfrEsXbrUFgnb/2JfGroSSXp7zT0lmcnWz372s4Rlyc3NVZ9++mmX+fS2v3X1DO/qfiXbhpWK9K8bb7yxyz7y+eefJ8yjszaYk5OjPvnkk07rzO/320Je+19sm42dCM6ePdueMMT7/epXv0pY3qVLl6qCgoKEfWb69Om97jPduQedtYX2WJalTjvttITnPuqoo9Qbb7xh/93Zu8BLL71kix3xfueff37cj4BKte3j7X/tn9W97Q/JiiRKKdXY2KjOPffcLscVQP3yl79skzaZNAcddJDatm2bneaXv/ylAtS5557bablS0XY7E0mU6v3Y1VuRRKm+f1dIVOZkfvHKm4xIolRk7hP9cBzvN3bsWLVp06ZOy7or5BHbhpL5tSf6fpzsr6t52fr1623x8Yorruj02PakUiRRqvfPsdh2fdtttyWskyFDhqjly5fHLUNVVZU9P2r/66pfxpL0cpu5c+eyfft2MjIymDZtWlJppk2bxtq1a3nwwQeZNm0aRUVFuFwuMjIyGDFiBBdddBFvvvkm7777rr1GrD3vvPMOjz76KGeeeSZjx44lNzcXh8NBQUEBRx11FH/6059YvHhxwnWqP/rRj1i3bh133XUXkyZNIj8/H8MwyMjIYPTo0Vx00UX897//ZcOGDclWRQfuu+8+/vnPf3L55Zdz0EEHUVRUhMPhICsri4MPPpibbrqJ5cuXc+aZZ9ppomsvjz766KQ8GN977728/fbbnHTSSeTm5uLxeNhnn3341a9+xTfffNMrE61Uc+qpp7J27VoeeOABjj32WAYNGoTD4SA9PZ2RI0dy1llnMWPGDCorK+NGM+qMwYMHM3/+fO6++272228/PB4Pubm5HHnkkfzzn/9kxowZtsdjr9fbIX1RURFfffUVN9xwA+Xl5TidTvLy8pg0aRL/93//x+zZs0lLS0tJPfQ1PemT3eGCCy7g448/5rTTTiM3NxeXy0VpaSnnnXcen3zyCdddd12v8j/hhBN4/fXXSUtLY8GCBRx33HFUV1fb+1PRd3Nzc/nf//7HvHnzuP766znggAPamDhHuf/++/nVr37V5Trom266iddff53jjjuOnJwcux/edNNNLFiwoEsv6LHpvV4vbrebsrIyfvSjH/HVV19xzjnnJFFzibnssst49tlnMQyD9957j9NPP902d9c0jdtuu41Vq1Zx0003MWHCBHJycjAMA6/Xy/jx47nyyit5/fXXbSeJUZ599lmeeOIJLrjgAvbff38KCgowDIOcnBwOP/xw7r77blasWNEm3Fx0jDv99NPR9cSPmjvuuIOVK1fyyCOPcN555zFu3Di8Xq99r8vLy/n+97/PE088wfLlyzsNadebNpOK9v7EE09w3333ccghh5CVlZWwPY0dO5bPP/+c8847j9LS0ja+CbpLfzzjesJf/vIXnnnmGY444ggyMjJIS0tj1KhRXHfddXz77bdJ+QnobX/riq7uV7JtGCL964EHHmDOnDlcfPHFDBs2DLfbjdfr5eCDD+a3v/0tK1eu7OCLJJZoGzz99NNtvxllZWX89Kc/ZcGCBW38vcXD7Xbz8ccfc9111zF69OhOQ4NHiYZr/dWvfsU+++xjP1NPPPFE3nzzTR588MGEaceOHcvXX3/Nj3/8Y4YOHYrT6aSoqIizzjqLTz75hF/84hddnj+V96A7aJrGSy+9xMMPP8zBBx9Meno6WVlZTJw4kUceeYTZs2cn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Cfi2W0ybNg1N05gxYwZ//OMf8Xq9XHzxxei6jpSSlJQUhg4dytdff82SJUvQdZ3FixczcOBA3G63P0CybNky7rrrLsLDwxk3btwJHyDZm80GrWniYzZOLjugjRs3ApCSktJkgAR8hVy/++47/7kH47///S8Aw4YN2+85K1as8GctAXz22Wc8/vjjPPbYYzz88MMHPQdFUY4vKkiiKIqiKIfZ9ddf3+hYWFgYkyZNYtKkSdTU1LBgwQJmz57N+PHjiYiIYPz48UyYMIFTTjnlqLQftSGwIQA7iZ7bqDOzqNR/wq3tolofRqSnCkNa+N9KOOzAXpkkIoQqRzSmFvhWw5IaEWIn8XoODZkjABYWOjpFxLJTJPkuIXIBJzXaLgqNdBK9p9DBMw5B44CH3W6nbdu2tG3bFq/XS3FxMYWFhfz222/Y7Xbi4uJISEggIiLimAqYlJSUsGrVKnr16tWiAIlpmtxxxx2kp6ezcOFCEhMTD+Msj31t27bl4Ycfxm6389JLL3H33XfjdruZNGkSQggSEhJ44okn+PXXX6moqGDEiBH07NmT+vp6f4vkpUuXctttt7F161aeeeYZRo0adZQf1ZFltx9ckKSysjLguMPhwOFoHEBt6DgTFRW132s23NZwbmv973//49NPPwXgT3/6U6PbIyMjueOOO5g0aRJdunQhIiKC7Oxspk+fznvvvce0adOIiIhQtUwU5SSjgiSKoiiKcpSFhIRwySWXcMkll1BXV8c333zD7NmzmThxIk6nk3HjxjFhwgSGDRu2309eDyeBRrDVm2Cr956D2o1g/RHkTgCsiFC0knKwABGCJBLB3jt6fQViTZyk2Jc3eT/lRPgDJL4RLgS+BawF5BrLyNXXIRHYCCLB7EGydxBBMjLgOoZhkJiYSGJiIqZpUlpaSmFhIStWrEAIQVxc3DHRWrikpISVK1fSo0ePFgU5LMti6tSp/PjjjyxatMhfb+Nk1LCdBiA2NparrrqKiooKZs6cySOPPILH4/F33Rk0aBBffvkl48aN44cffuCUU06hX79+9OjRg23btvH222/7O9s0taA+0R1skCQ5OTng+F/+8hceffTRRuc31A86UNHlhuBKXV1dyye027Zt27jqqqsAuP322xk+fHijcyZMmMCECRMCjvXv3593332XmJgYXnzxRaZNm8a111570hTwVRRF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W2+9lYiICJ5//vlmPClN+/zzzykvLyciIoJx48a1eHxkZCR33HEHkyZNokuXLkRERJCdnc306dN57733mDZtGhEREUyZMuV3r1VQUMA333wDBAZsGgqu1tXVYRgGl112Gddeey19+vQhMTGRHTt28Nprr/HCCy9QW1vLAw88gGEY3H777YCvyPPll1/O5ZdfTl1d3SEr+nwyaG1NksPUTVxRFOWoUUESRVGUE8T777/vT6U/mtLT0xk3bhx1dXXcd999PPjgg80al5uby3nnnUdxcTGTJk1ixowZh2Q+lmXx4YcfAgdfqLLhk+j9tTM90QkhePPNN/n222/59ddf6dKlC19++SWzZ8/mvPPOIyEhwR8wGThw4JEPmABoGp4Jf8Yz6i70jHmIygKiPU5qtKV49T0BEAsbekA2iYbNXYfWzBWf5s6mId+kpqaG5cuX07Zt2yYzSA7ku+++Y8qUKfzzn//kyiuvpLa2lgULFhAcHOw/54knnmDTpk288sorJCQktOj6e2v4+3DZZZfhdDpbPH7ChAlMmDAh4Fj//v159913iYmJ4cUXX2TatGlce+21hIWFHfBaH374IaZpkpqaGtCGWAjBwoULmT17NnfccQf//e9/A8Z17NiR5557jp49e3L99ddTV1fHX//6V9xuN3feeSeapuH1ejEMo1WP8WTW2kwSFSRRFOVEowq3KoqiKIdMdnY2F1xwAZWVldxyyy0888wzzRqXn5/Pueeey44dOxg7dizvvvvuIVtgL1y4kO3bt+N0Orn00ktbfZ3i4mIKCwsBaNeu3SGZ2/Fo5MiRLF68mIEDBxIeHs4VV1zBrFmzKCgo4JlnniE/P59x48bRq1cv7r//fn755RfM39m+clgEhWMOuxrv6HvQTvk/2nr+Toh5Cg1vfczdrX0Fwt9aWLagXoUUvtVkQ4AkKSmJzp07t6jmxeLFi7nyyit5+eWXufLKKxFCEBISwiWXXMLo0aMB3+/Uc889x8CBA7ntttuafe19lZSUMH/+fACuueaaVl9nfx577DEcDgcVFRX7bUu8t4bsrn0Dl0VFRfzxj3/ktdde45VXXtlvdtx1113HwIEDAV9WyhtvvMELL7zgD5A0ZKQozacKtyqKovioIImiKIpySOydCXLllVfy2muvNWtcaWkp5513Hps3b+bss8/mk08+OaS1AxoWY+PHjyciYt9WsM03ffp0pJRERETstzvOyWDw4MH07Nmz0fGQkBAuvfRSPvzwQ/Lz8/nHP/5BZWUlEydOpFu3btx9990sXrz4qGXhGDKORPc02tf/i3j3vcS77yXccyuwpyOO2xmEp5mvPTP4PGpra0lPT6dNmzZ06dKlRYvyn3/+mYkTJ/L8888zefLk/Y69/fbb8Xq9zJgx46AChx9//DEej4cOHTpwxhlntPo6+xMeHk6vXr0A2LRpU5PnNHRIys7OJiMjA4Crr746IIgWExPDn/70JwYPHswbb7zB9OnTyc7ObvJ6Z511lv//161bxz/+8Q+efPJJPB6PCpAoiqIoraaCJIqiKMpBKygo4LzzzmPHjh2MHz+ed955p1kLupqaGsaMGcOaNWs45ZRTmDdvXrNT5O+99146dOjAvffeu99z6urqmt1idO3atdx+++2sXbs24Hh9fT1PPfWUPyvm/vvvx64+Oj2goKAg0tLSeOedd8jPz+df//oXXq+XP/zhD3Tp0oU77riD7777Do/Hc8TnZsg4wswRhJlnE+H9AzGuv2G3dgd9hKAi+veL0JrOU6ixupKenk5CQoK/209zLVu2jEsvvZSnnnqKm2+++YBjMzMzEUIwfvx4EhMTA74+/vhjAJ555hkSExMPGLxr2Gpz9dVXH7YAwu9tR2u434bOM2eccQZJSUnous6yZct45ZVX0DSNq666igceeIC+ffvy9ttv8/zzzwf8XjYEWxq6ZYWEhHDVVVeRl5fHrFmzqK/ft7Wz0hyG4atL0tKvZjYtUxRFOW6oP2uKoihKgDvuuMNfw2Nvffv29Qc+hg0bxmeffea/7ZFHHvF/erxz586AT3j3duGFF/LQQw/5v//HP/7Br7/+CvgCJhdccEGT4wYMGMDLL78ccKy4uJitW7dSXFy838fy6aefUlVVRVxc3H6v3cDj8TBjxgxmzJhBXFwcKSkpgO9T79raWgBuuOEGHnjggQNeRwlkt9u58MILufDCC5kxYwaLFy/mk08+4aabbsLj8TB27FjS0tI4++yzcTgcR3x+QdbpBLlOxyO2YooitHAH3qqHMWq/a/J8S0+kMvIV0tPTiY+Pp2vXri0KOmRkZHDRRRfxl7/8hf/7v/9r1ljTNCkoKNjv7dXV1VRXV+83wLh582aWLFkC0KruTs1hmqZ/a8yBtqPNnz+ff//734AvcOlwOMjIyPDXJTn11FMZPHgwF198MZqm8fTTT/Puu+9imiZ33303ffv2RQiBy+UiKysLALfbzYABAzjzzDMZNWrU79ZDUZrW2q0zlnXo56IoinI0qSCJoiiKEqCqqoqSkpJGx8vK9hS9rKioCLjN5XL5/3/58uX7vXaXLl32O27NmjX7HWe08qPKhq02kyZN+t1rdOjQgccff5xffvmFdevWsX79etxuN/Hx8Vx44YXceOONjBo1qlXzUHxsNhvnnHMO55xzDq+++io//fQTs2bN4q677qKqqorRo0czYcIEzj333CPelcQm22OTvs5H7qTZWGX/wKj4F5p3GwBShOINn0R10J0sW7GTuLi4FgdIVq1axfjx47n//vuZOnVqs8aWl5fv97bJkyfzzjvv8PjjjzNt2rT9ntfwezB06FC6devW7Pm2xFtvvUV5eTm6ru83SAqwfft2fwbR+vXrycvL45xzzsEwDP7yl78wePBg/7kTJkxA13Wefvpp3n//fTweD//3f//H6aefzubNm1mwYAHgy1y54IILmtwGpjSfCpIoiqL4qO02iqIoSoCZM2cipTzg16JFi1o8RkrJzJkzA8Y9+uijzRq37/3tfZ/7XrPBokWLOPPMM5kwYQKzZ89GCIEQgu3btzd5fmRkpL/t6siRI2nfvj2GYVBUVERmZiaffvrpfmstmKbJ119/zR133MHAgQMJCwvD4XDQvn17rrnmGn/9hZZqqFVxoK8DbS1YsmQJaWlpxMXFERQURM+ePXn88cePie0Iuq4zYsQIXn75ZbZu3cr8+fNp06YNDz74IB06dOCaa65hzpw5VFdXH/nJCRve6Huo77CWuvaZ1KUso67TZqrCn+G3lbuIjY2lW7duLQqQZGVlMW7cOO666y7uv//+I1oz44MPPgCa191p1qxZTdYtqays5IorrmDZsmUBx03T5M033+Suu+4CfNlWbdu29d9u7V5Bm6aJlDJg/AsvvEC3bt2oqKjgySef5OGHHw4495ZbbkFKyX333cewYcP48MMPue2227jjjjsYOXKkf1tP3759iY2NbenTouyjoQVwS78OYQkpRVGUY4KQDRs7FUVRFOUEEhkZ2SjjBSAvL2+/2wH+/Oc/88QTTwDgdDpJTU3FNE02btyIx+MhODiYjz/+mLFjxwaMe+utt7jxxhsBX9ZL165dsdlsbNiwgbq6OgzD4NVXX+Xmm29u0WNoyBRITU0lPj6+yXO+//77JmukfPDBB1x77bWYpknbtm2Jj49nzZo1eDwehgwZwqJFiwLazB4rLMsiPT2dWbNmMXfuXLZv3855553HhAkTGD16NGFhYUelKGd9fT3Lly8nOjqaHj16tGgO69evZ/To0Vx//fU8+eSTh2z+zckkWbJkCaeffjo2m42dO3f+bjBh5syZXHfddbRv357c3Fz/8fLycqKiogDf71bHjh0xDIONGzf6s11Gjx7NnDlz/Nt+tm3bxpNPPsmf//xn2rVrR01NDW3btqWiooKpU6fy4osvous6/fr182eguVwu/7ar/v37s3LlShwOB0lJSVRUVFBaWhow36ioKH744Qf69OnT4udP8amsrCQiIoJnn60gKCi8xePr6iq5774IKioqCA9v+XhFUZRjjcokURRFUU5IvXr1YvLkybz22msH3AK0NyklZ599Np9++inl5eWsWrWKtWvXkpeXx4UXXkhtbS1XXHEF+fn5jcYNHDiQ9957j/LyctauXcuKFSvIz89n8uTJeL1ebr/9dlatWtWqx/LQQw/x008/NfnVVIAkNzeXG264AdM0efbZZ8nLyyMjI4ONGzfSrVs3fvvtN+67775WzeVw0zSNIUOG8Mwzz7Bu3Tp++eUX+vbty/PPP0+HDh2YOHEi77//PmVlZRypz3nq6+tJT08nKiqqxQGSTZs2MXbsWK6++mqeeOKJIx7gadhqc8EFFxxUtkVISAjPPvssEyZMIDY2ls2bN7NixQqcTidjxozh448/5ssvv/QHSDweD7feeitvvvkmf/zjH8nPz+fLL7+koqKC6OhoMjMz/dfOyMjwBxkdDoc/Q+TBBx/kmmuuITU1laqqKiorKwkJCSEiIoJu3bpxww038NNPP6kAySGiWgAriqL4qEwSRVEU5aTQsDg9UCZJSUkJMTExTd5WVVVFly5dKCwsZPr06UydOtV/W1lZGZGRkU0ugL1eLwMGDGDNmjXceeed/s4ezdGQKfD2228zefLkZo/7v//7P1577TXOP/98vv7664DbfvnlF4YNG4bNZiMvL4+EhIRmX/doklKSnZ3NrFmzmDNnDllZWZx11lmkpaUxduxYYmNjD0sAwuVysXz5ciIjI+nZs2eL7iM3N5cLLriAtLQ0XnrppYNq4Xu8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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "view.slip3D('/Users/dmelgarm/FakeQuakes/Seattle_fault/output/ruptures/planar1.000127.rupt')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "base", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/python/mudpy/forward.py b/src/python/mudpy/forward.py index 6d3fbe9..85153e6 100644 --- a/src/python/mudpy/forward.py +++ b/src/python/mudpy/forward.py @@ -3035,12 +3035,26 @@ def ssds2rake(ss,ds): return rake def makefault(fout,strike,dip,nstrike,dx_dip,dx_strike,epicenter,num_updip,num_downdip,rise_time): - ''' - Make a planar fault - - strike - Strike angle (degs) - dip - Dip angle (degs)200/5 - ''' + """ + Create a planar fault and write its properties to a file. + + Parameters: + + fout (str): Output file path to save the fault properties. + strike (float): Strike angle in degrees. + dip (float): Dip angle in degrees. + nstrike (int): Number of subfaults along the strike direction. + dx_dip (float): Distance between subfaults along the dip direction. + dx_strike (float): Distance between subfaults along the strike direction. + epicenter (tuple): Coordinates of the epicenter (longitude, latitude, depth). + num_updip (int): Number of subfaults updip from the epicenter. + num_downdip (int): Number of subfaults downdip from the epicenter. + rise_time (float): Rise time for the fault slip. + + Returns: + None + """ + from numpy import arange,sin,cos,deg2rad,r_,ones,arctan,rad2deg,zeros,isnan,unique,where,argsort import pyproj @@ -3128,6 +3142,11 @@ def makefault(fout,strike,dip,nstrike,dx_dip,dx_strike,epicenter,num_updip,num_d L=ones(loout.shape)*dx_strike*1000 W=ones(loout.shape)*dx_dip*1000 f=open(fout,'w') + # Write header line + header = "# No\tLongitude\tLatitude\tDepth(km)\tStrike\tDip\ttype\tRise Time\tLength(m)\tWidth(m)\n" + print('Hi') + f.write(header) + for k in range(len(x)): out='%i\t%.6f\t%.6f\t%.3f\t%.2f\t%.2f\t%.1f\t%.1f\t%.2f\t%.2f\n' % (k+1,loout[k],laout[k],zout[k],strike[k],dip[k],tw[k],rise[k],L[k],W[k]) f.write(out) diff --git a/src/python/mudpy/gmttools.py b/src/python/mudpy/gmttools.py index acc9cc6..6b55660 100644 --- a/src/python/mudpy/gmttools.py +++ b/src/python/mudpy/gmttools.py @@ -718,7 +718,7 @@ def read_neic_param(fault_file): -def triangular_rupt_2_gmt(meshfile,slipfile,outfile,kinematic_out_folder=None,percentage=0,is_total_model=True): +def triangular_rupt_2_gmt(meshfile,slipfile,outfile,kinematic_out_folder=None,percentage=0,is_total_model=True,output_variable='slip'): ''' DM Note: Modified from Brendan's script because he refused to do a pull request :) @@ -783,7 +783,7 @@ def triangular_rupt_2_gmt(meshfile,slipfile,outfile,kinematic_out_folder=None,pe risetime = list() duration = list() rig = list() - + onset_time = list() with open(slipfile, 'r') as f: next(f) @@ -798,6 +798,7 @@ def triangular_rupt_2_gmt(meshfile,slipfile,outfile,kinematic_out_folder=None,pe if is_total_model: rig.append(float(row[12])) else: + onset_time.append(float(row[12])) rig.append(float(row[13])) @@ -813,16 +814,25 @@ def triangular_rupt_2_gmt(meshfile,slipfile,outfile,kinematic_out_folder=None,pe TOTS = numpy.sqrt(numpy.power(SS,2)+numpy.power(DS,2)) FA = numpy.asarray(faultarea) RIG = numpy.asarray(rig) - + ONSET = numpy.asarray(onset_time) + #Total slip model moment = 0 fso = open(outfile,'w') slip_threshold=(percentage/100)*TOTS.max() - for i in range(0, numpy.amax(MESN)): + + print(len(MESN)) + print(len(ONSET)) + + for i in range(0, len(MESN)): a1 = numpy.where(MESN[i] == INVN)[0] totslip = numpy.sum(TOTS[a1]) -# print (i+1,totslip*100) + totonset = ONSET[i] + #print(a1) + #print(ONSET) + # print('Onset time is %.f' % (totonset)) + if (totslip >= slip_threshold): moment = moment+FA[i]*1000*1000*numpy.mean(RIG[a1])*totslip lon1 = "{0:.4f}".format(meshlon1[i]) @@ -834,7 +844,10 @@ def triangular_rupt_2_gmt(meshfile,slipfile,outfile,kinematic_out_folder=None,pe dep1 = "{0:.4f}".format(meshdep1[i]) dep2 = "{0:.4f}".format(meshdep2[i]) dep3 = "{0:.4f}".format(meshdep3[i]) - ts = "{0:.4f}".format(totslip) + if output_variable=='slip': + ts = "{0:.4f}".format(totslip) + elif output_variable == 'onset_time': + ts = "{0:.4f}".format(totonset) fso.write('> -Z'+ts+'\n') fso.write(lon1+' '+lat1+' '+dep1+'\n') fso.write(lon2+' '+lat2+' '+dep2+'\n') diff --git a/src/python/mudpy/insartools.py b/src/python/mudpy/insartools.py index 388efc5..5c4585a 100644 --- a/src/python/mudpy/insartools.py +++ b/src/python/mudpy/insartools.py @@ -43,7 +43,7 @@ def quadtree2mudpy(home,project_name,quadtree_file,gflist_file,prefix): -def un_nanify(infile,outfile): +def un_nanify(infile,outfile): from numpy import genfromtxt,savetxt,where,nan insar=genfromtxt(infile) i=where(infile[:,2]!=nan)[0] diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index c76c58c..c168b66 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -794,6 +794,19 @@ def run_inversion(home,project_name,run_name,fault_name,model_name,GF_list,G_fro # G[:,ids_zone] = 0 + #Zero out subfaults south of someplace (18.5 for Myanmar) + # print(' DANGER WILL ROBINSON: Forcing faults south of 18.5N to have GFs = 0') + # fault_geometry = genfromtxt('/Users/dmelgarm/Slip_inv/Myanmar_joint_hires/output/inverse_models/models/SM_SA_SD.0008.inv') + # izone = where(fault_geometry[:,2]<18.5)[0] + + # #Double indices because of ss and ds coordiante system + # iss_zone = 2*izone + # ids_zone = 2*izone + 1 + + # #Zero out those GFs + # G[:,iss_zone] = 0 + # G[:,ids_zone] = 0 + ####### END POLY FILTER STUFF diff --git a/src/python/mudpy/view.py b/src/python/mudpy/view.py index 7f4e15b..c271f26 100644 --- a/src/python/mudpy/view.py +++ b/src/python/mudpy/view.py @@ -287,7 +287,7 @@ def quick_static(gflist,datapath,scale=1): plt.show() -def slip3D(rupt,marker_size=60,clims=None,plot_onset=False,cmap=whitejet): +def slip3D(rupt,marker_size=60,clims=None,plot_onset=False,cmap=whitejet,show=False): ''' For complex fault geometries make a quick 3D plot of the rupture model @@ -352,7 +352,8 @@ def slip3D(rupt,marker_size=60,clims=None,plot_onset=False,cmap=whitejet): cb.set_label('Onset time (s)') plt.subplots_adjust(left=0.1, bottom=0.1, right=1.0, top=0.9, wspace=0, hspace=0) plt.title(rupt) - plt.show() + if show: + plt.show() @@ -1727,7 +1728,8 @@ def plot_data(home,project_name,gflist,vord,decimate,lowpass,t_lim,sort,scale,k_ def synthetics(home,project_name,run_name,run_number,gflist,vord,decimate,lowpass,t_lim, sort,scale,k_or_g,uncert=False,waveforms_as_accel=False,units='m',uncerth=0.01,uncertv=0.03, - tick_frequency=10,spoof_vel_as_disp=False,return_vectors=False): + tick_frequency=10,spoof_vel_as_disp=False,return_vectors=False,same_channel_amplitude=True, + show=False): ''' Plot synthetics vs real data @@ -1855,6 +1857,15 @@ def synthetics(home,project_name,run_name,run_number,gflist,vord,decimate,lowpas axe.yaxis.set_ticks([]) axu.yaxis.set_ticks([]) + if same_channel_amplitude == True: + ymax = max(abs(n[0].data.max()), abs(ns[0].data.max()), + abs(e[0].data.max()), abs(es[0].data.max()), + abs(u[0].data.max()), abs(us[0].data.max())) + ymin = -ymax + axn.set_ylim([ymin,ymax]) + axe.set_ylim([ymin,ymax]) + axu.set_ylim([ymin,ymax]) + #Annotations trange=t_lim[1]-t_lim[0] sign=1. @@ -1975,7 +1986,8 @@ def synthetics(home,project_name,run_name,run_number,gflist,vord,decimate,lowpas #axu.xaxis.set_ticks(xtick) #plt.subplots_adjust(left=0.2, bottom=0.05, right=0.8, top=0.95, wspace=0, hspace=0) plt.subplots_adjust(left=0.2, bottom=0.15, right=0.8, top=0.85, wspace=0, hspace=0) - plt.show() + if show: + plt.show() if return_vectors == True: @@ -2093,7 +2105,8 @@ def insar_residual(home,project_name,run_name,run_number,gflist,zlims): plt.grid() -def insar_results(home,project_name,run_name,run_number,gflist,zlims,cmap,figsize=(8,5),title=None,interpolate=True,method='linear',npts=100): +def insar_results(home,project_name,run_name,run_number,gflist,zlims,cmap,figsize=(8,5),title=None,interpolate=True,method='linear',npts=100, + show=False): ''' Plot insar observed in one panel and insar modeled in the other @@ -2179,6 +2192,9 @@ def insar_results(home,project_name,run_name,run_number,gflist,zlims,cmap,figsiz plt.xlabel('Longitude') plt.grid() plt.suptitle(title) + + if show: + plt.show() def tsunami_synthetics(home,project_name,run_name,run_number,gflist,t_lim,sort,scale): ''' From f53554d35620cea070c9a1ee1176be021bbbd3b3 Mon Sep 17 00:00:00 2001 From: Diego Melgar Date: Wed, 15 Oct 2025 08:41:25 -0700 Subject: [PATCH 18/24] Updates --- src/fk/bessel.f | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fk/bessel.f b/src/fk/bessel.f index 4535dc5..862bd25 100644 --- a/src/fk/bessel.f +++ b/src/fk/bessel.f @@ -1,7 +1,7 @@ # 1 "bessel.FF" # 1 "" 1 # 1 "" 3 -# 390 "" 3 +# 423 "" 3 # 1 "" 1 # 1 "" 2 # 1 "bessel.FF" 2 From 24eb8d18bc5397622efae8b835eed56909ec978c Mon Sep 17 00:00:00 2001 From: Diego Melgar Date: Thu, 16 Oct 2025 12:54:06 -0700 Subject: [PATCH 19/24] Added new CLI options to fk.pl, zero padding and sigma --- src/fk/fk.pl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/fk/fk.pl b/src/fk/fk.pl index 2d220b3..2fafe5a 100755 --- a/src/fk/fk.pl +++ b/src/fk/fk.pl @@ -53,8 +53,10 @@ taper applies a low-pass cosine filter at fc=(1-taper)*f_Niquest ($taper). -P: specify the min. and max. slownesses in term of 1/vs_at_the_source ($pmin/$pmax) and optionally kmax at zero frequency in term of 1/hs ($kmax). +-G: specify sigma, small imaginary frequency in 1/T ($sigma). -R: receiver depth ($r_depth). -S: 0=explosion; 1=single force; 2=double couple ($src). +-T: specify the number of samples before the first arrival ($tb). -U: 1=down-going wave only; -1=up-going wave only ($updn). -X: dump the input to cmd for debug ($fk). Examples @@ -73,6 +75,8 @@ my @value = split(/\//,substr($_,2)); if ($opt eq "D") { $deg2km = 6371*3.14159/180.; + } elsif ($opt eq "G") { + $sigma = $value[0]; } elsif ($opt eq "H") { $f1 = $value[0]; $f2 = $value[1]; } elsif ($opt eq "M") { @@ -96,6 +100,8 @@ $rdep = "_$r_depth"; } elsif ($opt eq "S") { $src = $value[0]; + } elsif ($opt eq "T") { + $tb = $value[0]; } elsif ($opt eq "U") { $updn = $value[0]; } elsif ($opt eq "X") { From 3159b946cd1d6ea15965e9cff3ef38de094c9b59 Mon Sep 17 00:00:00 2001 From: JK Date: Fri, 24 Oct 2025 12:10:39 -0700 Subject: [PATCH 20/24] Edits to mudpy to be used for landslides and modified so that any number of layers can be used for the velocity model --- src/fk/bessel.f | 55 +++++++++++++++++++++++++----------- src/fk/model.h | 2 +- src/python/mudpy/forward.py | 7 +++-- src/python/mudpy/inverse.py | 6 +--- src/python/mudpy/parallel.py | 17 +++++++---- src/python/mudpy/runslip.py | 6 ++-- src/python/mudpy/view.py | 46 ++++++++++++++++++------------ 7 files changed, 88 insertions(+), 51 deletions(-) diff --git a/src/fk/bessel.f b/src/fk/bessel.f index 4535dc5..11c790a 100644 --- a/src/fk/bessel.f +++ b/src/fk/bessel.f @@ -1,10 +1,42 @@ +# 0 "bessel.FF" +# 0 "" +# 0 "" +# 1 "/usr/include/stdc-predef.h" 1 3 4 + +# 17 "/usr/include/stdc-predef.h" 3 4 + + + + + + + + + + + + + + + + + + + +# 45 "/usr/include/stdc-predef.h" 3 4 + +# 55 "/usr/include/stdc-predef.h" 3 4 + + + + + + + + + +# 0 "" 2 # 1 "bessel.FF" -# 1 "" 1 -# 1 "" 3 -# 390 "" 3 -# 1 "" 1 -# 1 "" 2 -# 1 "bessel.FF" 2 ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc c bessel.FF: Compute Bessel function Jn(z) for n=0,1,2 c Reivsion History @@ -13,19 +45,10 @@ subroutine besselFn(z, aj0, aj1, aj2) IMPLICIT NONE real z, aj0, aj1, aj2 - - - - - - - - +# 17 "bessel.FF" aj0 = BesJ0(z) aj1 = BesJ1(z) aj2 = BesJN(2,z) - # 30 "bessel.FF" return end - diff --git a/src/fk/model.h b/src/fk/model.h index f662c0b..ec33afc 100644 --- a/src/fk/model.h +++ b/src/fk/model.h @@ -19,7 +19,7 @@ c xi--- mu/bulk_modulus. c si(3,6) ---- source coefs. of n=0,1,2. integer mb,stype,src,rcv,nlay,ndis,nt,updn c max. # of layers and receivers and time length - parameter(nlay=20, ndis=5000, nt=4096) + parameter(nlay=500, ndis=5000, nt=4096) real d(nlay),rho(nlay),mu(nlay),xi(nlay),si(3,6),epsilon complex ka(nlay),kb(nlay) PARAMETER (epsilon=0.0001) diff --git a/src/python/mudpy/forward.py b/src/python/mudpy/forward.py index 8f5692f..7ca5c28 100644 --- a/src/python/mudpy/forward.py +++ b/src/python/mudpy/forward.py @@ -2516,7 +2516,7 @@ def get_mu_and_area(home,project_name,fault_name,model_name): return mu,area -def get_source_time_function(mu,area,rise_time,t0,slip): +def get_source_time_function(mu,area,rise_time,t0,slip,single_force=0): ''' Compute source time function for a given rise time, right now it assumes 1m of slip and a triangle STF @@ -2528,7 +2528,10 @@ def get_source_time_function(mu,area,rise_time,t0,slip): t=linspace(t0,t0+rise_time,1000) Mdot=zeros(t.shape) #Triangle gradient - m=4*mu*area/(rise_time**2) + if single_force == 1: + m = 4/(rise_time**2) + else: + m=4*mu*area/(rise_time**2) #Upwards intercept b1=-m*t0 #Downwards intercept diff --git a/src/python/mudpy/inverse.py b/src/python/mudpy/inverse.py index 2ddf9ba..6099312 100644 --- a/src/python/mudpy/inverse.py +++ b/src/python/mudpy/inverse.py @@ -242,9 +242,6 @@ def getG(home,project_name,fault_name,model_name,GF_list,G_from_file,G_name,epic Ginsar_nwin=c_[Ginsar_nwin,Ginsar] Ginsar=Ginsar_nwin.copy() Ginsar_nwin=None #Release memory - print(Gstatic.shape) - print(Gvel.shape) - print(Ginsar.shape) G=concatenate([g for g in [Gstatic,Gdisp,Gvel,Gtsun,Ginsar] if g.size > 0]) print('Saving GF matrix to '+G_name+' this might take just a second...') save(G_name,G) @@ -768,7 +765,6 @@ def getdata(home,project_name,GF_list,decimate,bandpass,quiet=False): for ksta in range(len(i)): if quiet==False: print('Assembling acceleration waveforms from '+stations[i[ksta]]+' into data vector.') - print(GFfiles[i[ksta]],kgf) n=read(GFfiles[i[ksta],kgf]+'.n') e=read(GFfiles[i[ksta],kgf]+'.e') u=read(GFfiles[i[ksta],kgf]+'.u') @@ -2826,4 +2822,4 @@ def data_norms(home,project_name,GF_list,decimate=None,bandpass=[None,None,None] print("||InSAR|| = "+str(N)) else: print("||InSAR|| = NaN") - \ No newline at end of file + diff --git a/src/python/mudpy/parallel.py b/src/python/mudpy/parallel.py index dc83b7a..7e5712d 100644 --- a/src/python/mudpy/parallel.py +++ b/src/python/mudpy/parallel.py @@ -100,6 +100,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, newf=subfault_folder+'/'+f.split('/')[-1] copy(f,newf) rmtree(subfault_folder+'/'+model_name+'_'+depth) + print(command) else: #Compute only statics if insar==True: suffix='insar' @@ -250,7 +251,8 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, if single_force==True: #Force of a square meter from a landslide in Dyne Allstadt 2013 on Mt. Meager in dyne - Mag=6e11 + Mag=1e16 + else: #Get moment corresponding to 1 meter of slip on subfault mu=get_mu(structure,zs) @@ -323,6 +325,7 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, 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) + print(commandSS) else: #Make vel. #First Stike-Slip GFs if custom_stf==None: @@ -596,7 +599,7 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, r_dd = u_dd.copy() r_ds = u_ds.copy() r_ss = u_ss.copy() - + 10.1785/BSSA0830010130 #terms for t component t_dd = zeros(Nsites) t_ds = cstk*srak*cdip2+sstk*crak*cdip @@ -656,8 +659,12 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, #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 + #"coef" in the syn.c original source code ############JUSTIN EDITS############ + if single_force==True: + scale = Mag*1e-15 #definition used in syn.c line 139 + ############## END OF EDITS ################### + else: + scale = 10**(1.5*Mw+16.1-20) #definition used in syn.c #Scale radiation patterns accordingly radiation_pattern_ss *= scale @@ -1392,4 +1399,4 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,forceMT,mt,insar,rank,size) else: print('ERROR: You''re not allowed to run '+sys.argv[1]+' from the shell or it does not exist') - \ No newline at end of file + diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index 57d5d78..5993c22 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -700,12 +700,10 @@ def run_inversion(home,project_name,run_name,fault_name,model_name,GF_list,G_fro G=inv.getG(home,project_name,fault_name,model_name,GF_list,G_from_file,G_name,epicenter, rupture_speed,num_windows,decimate,bandpass,onset_file=onset_file) - - # Force faults inside a polygon to be zero (not contribute to inversion, # useful for testing sensitivites) # print(' DANGER WILL ROBINSON: Forcing faults in polygon to have GFs = 0') - + # print('Keep Zone 1, 2 and 3') # p = genfromtxt('/Users/dmelgarm/Coalcoman2022/kml/zone1.txt') # zone_poly1 = path.Path(p) @@ -855,7 +853,7 @@ def run_inversion(home,project_name,run_name,fault_name,model_name,GF_list,G_fro Ls=inv.getLs(home,project_name,fault_name,nfaults,num_windows,bounds) elif Ltype==0: #Tikhonov smoothing N=nfaults[0]*nfaults[1]*num_windows*2 #Get total no. of model parameters - Ls=eye(N) + Ls=eye(N) elif Ltype==3: #moment regularization N=nfaults[0]*nfaults[1]*num_windows*2 #Get total no. of model parameters Ls=ones((1,N)) diff --git a/src/python/mudpy/view.py b/src/python/mudpy/view.py index 7f4e15b..0517447 100644 --- a/src/python/mudpy/view.py +++ b/src/python/mudpy/view.py @@ -1110,12 +1110,13 @@ def panel_tile_slip(home,project_name,sliprate_path,nstrike,ndip,slip_min,slip_m -def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade=False): +def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade=False,single_force=0): ''' Tile plot of subfault source-time functions ''' import matplotlib.pyplot as plt from matplotlib import cm + import numpy as np from numpy import genfromtxt,unique,zeros,where,meshgrid,linspace,load,arange,expand_dims,squeeze,tile,r_ from mudpy.forward import get_source_time_function,add2stf from mudpy.inverse import d2epi,ds2rot @@ -1128,8 +1129,8 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade all_ss=f[:,8] all_ds=f[:,9] all=zeros(len(all_ss)*2) - iss=2*arange(0,len(all)/2,1) - ids=2*arange(0,len(all)/2,1)+1 + iss=2*arange(0,len(all)/2,1).astype(int) + ids=2*arange(0,len(all)/2,1).astype(int)+1 all[iss]=all_ss all[ids]=all_ds rot=ds2rot(expand_dims(all,1),beta) @@ -1186,17 +1187,17 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade slip_plus=slipCIplus[i] slip_minus=slipCIminus[i] #Get first source time function - t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0]) + t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0],single_force=single_force) if covfile !=None: - t1plus,M1plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_plus[0]) - t1minus,M1minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_minus[0]) + t1plus,M1plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_plus[0],single_force=single_force) + t1minus,M1minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_minus[0],single_force=single_force) #Loop over windows for kwin in range(nwin-1): #Get next source time function - t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1]) + t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1],single_force=single_force) if covfile !=None: - t2plus,M2plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_plus[kwin+1]) - t2minus,M2minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_minus[kwin+1]) + t2plus,M2plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_plus[kwin+1],single_force=single_force) + t2minus,M2minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_minus[kwin+1],single_force=single_force) #Add the soruce time functions t1,M1=add2stf(t1,M1,t2,M2) if covfile !=None: @@ -1213,7 +1214,8 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade Mmax=max(Mmax,M1.max()) #Done now plot them #get current axis - ax=axarr[int(idip[kfault]), int(istrike[kfault])] + ax=axarr[int(istrike[kfault])] + #ax=axarr[int(idip[kfault]), int(istrike[kfault])] ############################################### if shade: #Make contourf Mc=linspace(0,0.98*max(M1),100) @@ -1230,6 +1232,11 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade ax.plot(t1,M1plus,color='black') ax.plot(t1,M1minus,color='white',lw=2) #Plot curve +########################################## + #plt.figure(kfault) + #plt.title(f'{kfault}') + #plt.plot(t1,M1) +####################################### ax.plot(t1, M1,color='k') ax.grid() @@ -1240,7 +1247,8 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade #Go back and rescale all subplots by maximum moment for k in range(ndip): for k2 in range(nstrike): - ax=axarr[k,k2] + ax=axarr[k] + #ax=axarr[k,k2]########################################### ax.set_ylim([0,Mmax]) #Fix subplot arrangement plt.subplots_adjust(left=0.02, bottom=0.02, right=0.9, top=0.98, wspace=0, hspace=0) @@ -1260,7 +1268,7 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade return tout,Mout -def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize=True): +def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize=True,single_force=0): ''' Plot source time function of complete rupture ''' @@ -1288,8 +1296,7 @@ def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize= for kfault in range(nfault): if kfault%10==0: print('... working on subfault '+str(kfault)+' of '+str(nfault)) - #Get rupture times for subfault windows - i=where(num==unum[kfault])[0] + trup=f[i,12] #Get slips on windows ss=all_ss[i] @@ -1297,11 +1304,11 @@ def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize= #Add it up slip=(ss**2+ds**2)**0.5 if kfault==0:#Get first source time function - t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0]) + t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0],single_force=single_force) #Loop over windows for kwin in range(nwin-1): #Get next source time function - t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1]) + t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1],single_force=single_force) #Add the soruce time functions t1,M1=add2stf(t1,M1,t2,M2) #Get power @@ -1317,7 +1324,10 @@ def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize= plt.plot(t1,M1,color='k') plt.grid() plt.xlabel('Time(s)') - plt.ylabel('Moment Rate ('+r'$\times 10^{'+str(int(exp))+r'}$Nm/s)') + if single_force == 1: + plt.ylabel(f'Force Rate {exp} (Dyne or Newton/s)') + else: + plt.ylabel('Moment Rate ('+r'$\times 10^{'+str(int(exp))+r'}$Nm/s)') plt.subplots_adjust(left=0.3, bottom=0.3, right=0.7, top=0.7, wspace=0, hspace=0) if xlim!=None: plt.xlim(xlim) @@ -2974,4 +2984,4 @@ def slip2geo(ss,ds,strike): #Add em up x=xss+xds y=yss+yds - return x,y \ No newline at end of file + return x,y From a37c4ad16d5b9a9fe109f776d9d5a15ec78ba373 Mon Sep 17 00:00:00 2001 From: JK Date: Tue, 28 Oct 2025 14:35:50 -0700 Subject: [PATCH 21/24] velocity layers can be more than 20 lines can visualize forces of single forces small changes to optimize use of single force inversion --- src/fk/bessel.f | 55 +++++++++++++++++++++++++----------- src/fk/model.h | 2 +- src/python/mudpy/forward.py | 7 +++-- src/python/mudpy/inverse.py | 6 +--- src/python/mudpy/parallel.py | 13 ++++++--- src/python/mudpy/runslip.py | 6 ++-- src/python/mudpy/view.py | 46 ++++++++++++++++++------------ 7 files changed, 85 insertions(+), 50 deletions(-) diff --git a/src/fk/bessel.f b/src/fk/bessel.f index 4535dc5..11c790a 100644 --- a/src/fk/bessel.f +++ b/src/fk/bessel.f @@ -1,10 +1,42 @@ +# 0 "bessel.FF" +# 0 "" +# 0 "" +# 1 "/usr/include/stdc-predef.h" 1 3 4 + +# 17 "/usr/include/stdc-predef.h" 3 4 + + + + + + + + + + + + + + + + + + + +# 45 "/usr/include/stdc-predef.h" 3 4 + +# 55 "/usr/include/stdc-predef.h" 3 4 + + + + + + + + + +# 0 "" 2 # 1 "bessel.FF" -# 1 "" 1 -# 1 "" 3 -# 390 "" 3 -# 1 "" 1 -# 1 "" 2 -# 1 "bessel.FF" 2 ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc c bessel.FF: Compute Bessel function Jn(z) for n=0,1,2 c Reivsion History @@ -13,19 +45,10 @@ subroutine besselFn(z, aj0, aj1, aj2) IMPLICIT NONE real z, aj0, aj1, aj2 - - - - - - - - +# 17 "bessel.FF" aj0 = BesJ0(z) aj1 = BesJ1(z) aj2 = BesJN(2,z) - # 30 "bessel.FF" return end - diff --git a/src/fk/model.h b/src/fk/model.h index f662c0b..ec33afc 100644 --- a/src/fk/model.h +++ b/src/fk/model.h @@ -19,7 +19,7 @@ c xi--- mu/bulk_modulus. c si(3,6) ---- source coefs. of n=0,1,2. integer mb,stype,src,rcv,nlay,ndis,nt,updn c max. # of layers and receivers and time length - parameter(nlay=20, ndis=5000, nt=4096) + parameter(nlay=500, ndis=5000, nt=4096) real d(nlay),rho(nlay),mu(nlay),xi(nlay),si(3,6),epsilon complex ka(nlay),kb(nlay) PARAMETER (epsilon=0.0001) diff --git a/src/python/mudpy/forward.py b/src/python/mudpy/forward.py index 8f5692f..7ca5c28 100644 --- a/src/python/mudpy/forward.py +++ b/src/python/mudpy/forward.py @@ -2516,7 +2516,7 @@ def get_mu_and_area(home,project_name,fault_name,model_name): return mu,area -def get_source_time_function(mu,area,rise_time,t0,slip): +def get_source_time_function(mu,area,rise_time,t0,slip,single_force=0): ''' Compute source time function for a given rise time, right now it assumes 1m of slip and a triangle STF @@ -2528,7 +2528,10 @@ def get_source_time_function(mu,area,rise_time,t0,slip): t=linspace(t0,t0+rise_time,1000) Mdot=zeros(t.shape) #Triangle gradient - m=4*mu*area/(rise_time**2) + if single_force == 1: + m = 4/(rise_time**2) + else: + m=4*mu*area/(rise_time**2) #Upwards intercept b1=-m*t0 #Downwards intercept diff --git a/src/python/mudpy/inverse.py b/src/python/mudpy/inverse.py index 2ddf9ba..6099312 100644 --- a/src/python/mudpy/inverse.py +++ b/src/python/mudpy/inverse.py @@ -242,9 +242,6 @@ def getG(home,project_name,fault_name,model_name,GF_list,G_from_file,G_name,epic Ginsar_nwin=c_[Ginsar_nwin,Ginsar] Ginsar=Ginsar_nwin.copy() Ginsar_nwin=None #Release memory - print(Gstatic.shape) - print(Gvel.shape) - print(Ginsar.shape) G=concatenate([g for g in [Gstatic,Gdisp,Gvel,Gtsun,Ginsar] if g.size > 0]) print('Saving GF matrix to '+G_name+' this might take just a second...') save(G_name,G) @@ -768,7 +765,6 @@ def getdata(home,project_name,GF_list,decimate,bandpass,quiet=False): for ksta in range(len(i)): if quiet==False: print('Assembling acceleration waveforms from '+stations[i[ksta]]+' into data vector.') - print(GFfiles[i[ksta]],kgf) n=read(GFfiles[i[ksta],kgf]+'.n') e=read(GFfiles[i[ksta],kgf]+'.e') u=read(GFfiles[i[ksta],kgf]+'.u') @@ -2826,4 +2822,4 @@ def data_norms(home,project_name,GF_list,decimate=None,bandpass=[None,None,None] print("||InSAR|| = "+str(N)) else: print("||InSAR|| = NaN") - \ No newline at end of file + diff --git a/src/python/mudpy/parallel.py b/src/python/mudpy/parallel.py index dc83b7a..7fd8fa6 100644 --- a/src/python/mudpy/parallel.py +++ b/src/python/mudpy/parallel.py @@ -250,7 +250,8 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, if single_force==True: #Force of a square meter from a landslide in Dyne Allstadt 2013 on Mt. Meager in dyne - Mag=6e11 + Mag=1e16 + else: #Get moment corresponding to 1 meter of slip on subfault mu=get_mu(structure,zs) @@ -656,8 +657,12 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, #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 + #"coef" in the syn.c original source code ############JUSTIN EDITS############ + if single_force==True: + scale = Mag*1e-15 #definition used in syn.c line 139 + ############## END OF EDITS ################### + else: + scale = 10**(1.5*Mw+16.1-20) #definition used in syn.c #Scale radiation patterns accordingly radiation_pattern_ss *= scale @@ -1392,4 +1397,4 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,forceMT,mt,insar,rank,size) else: print('ERROR: You''re not allowed to run '+sys.argv[1]+' from the shell or it does not exist') - \ No newline at end of file + diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index 57d5d78..5993c22 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -700,12 +700,10 @@ def run_inversion(home,project_name,run_name,fault_name,model_name,GF_list,G_fro G=inv.getG(home,project_name,fault_name,model_name,GF_list,G_from_file,G_name,epicenter, rupture_speed,num_windows,decimate,bandpass,onset_file=onset_file) - - # Force faults inside a polygon to be zero (not contribute to inversion, # useful for testing sensitivites) # print(' DANGER WILL ROBINSON: Forcing faults in polygon to have GFs = 0') - + # print('Keep Zone 1, 2 and 3') # p = genfromtxt('/Users/dmelgarm/Coalcoman2022/kml/zone1.txt') # zone_poly1 = path.Path(p) @@ -855,7 +853,7 @@ def run_inversion(home,project_name,run_name,fault_name,model_name,GF_list,G_fro Ls=inv.getLs(home,project_name,fault_name,nfaults,num_windows,bounds) elif Ltype==0: #Tikhonov smoothing N=nfaults[0]*nfaults[1]*num_windows*2 #Get total no. of model parameters - Ls=eye(N) + Ls=eye(N) elif Ltype==3: #moment regularization N=nfaults[0]*nfaults[1]*num_windows*2 #Get total no. of model parameters Ls=ones((1,N)) diff --git a/src/python/mudpy/view.py b/src/python/mudpy/view.py index 7f4e15b..0517447 100644 --- a/src/python/mudpy/view.py +++ b/src/python/mudpy/view.py @@ -1110,12 +1110,13 @@ def panel_tile_slip(home,project_name,sliprate_path,nstrike,ndip,slip_min,slip_m -def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade=False): +def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade=False,single_force=0): ''' Tile plot of subfault source-time functions ''' import matplotlib.pyplot as plt from matplotlib import cm + import numpy as np from numpy import genfromtxt,unique,zeros,where,meshgrid,linspace,load,arange,expand_dims,squeeze,tile,r_ from mudpy.forward import get_source_time_function,add2stf from mudpy.inverse import d2epi,ds2rot @@ -1128,8 +1129,8 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade all_ss=f[:,8] all_ds=f[:,9] all=zeros(len(all_ss)*2) - iss=2*arange(0,len(all)/2,1) - ids=2*arange(0,len(all)/2,1)+1 + iss=2*arange(0,len(all)/2,1).astype(int) + ids=2*arange(0,len(all)/2,1).astype(int)+1 all[iss]=all_ss all[ids]=all_ds rot=ds2rot(expand_dims(all,1),beta) @@ -1186,17 +1187,17 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade slip_plus=slipCIplus[i] slip_minus=slipCIminus[i] #Get first source time function - t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0]) + t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0],single_force=single_force) if covfile !=None: - t1plus,M1plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_plus[0]) - t1minus,M1minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_minus[0]) + t1plus,M1plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_plus[0],single_force=single_force) + t1minus,M1minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip_minus[0],single_force=single_force) #Loop over windows for kwin in range(nwin-1): #Get next source time function - t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1]) + t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1],single_force=single_force) if covfile !=None: - t2plus,M2plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_plus[kwin+1]) - t2minus,M2minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_minus[kwin+1]) + t2plus,M2plus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_plus[kwin+1],single_force=single_force) + t2minus,M2minus=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip_minus[kwin+1],single_force=single_force) #Add the soruce time functions t1,M1=add2stf(t1,M1,t2,M2) if covfile !=None: @@ -1213,7 +1214,8 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade Mmax=max(Mmax,M1.max()) #Done now plot them #get current axis - ax=axarr[int(idip[kfault]), int(istrike[kfault])] + ax=axarr[int(istrike[kfault])] + #ax=axarr[int(idip[kfault]), int(istrike[kfault])] ############################################### if shade: #Make contourf Mc=linspace(0,0.98*max(M1),100) @@ -1230,6 +1232,11 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade ax.plot(t1,M1plus,color='black') ax.plot(t1,M1minus,color='white',lw=2) #Plot curve +########################################## + #plt.figure(kfault) + #plt.title(f'{kfault}') + #plt.plot(t1,M1) +####################################### ax.plot(t1, M1,color='k') ax.grid() @@ -1240,7 +1247,8 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade #Go back and rescale all subplots by maximum moment for k in range(ndip): for k2 in range(nstrike): - ax=axarr[k,k2] + ax=axarr[k] + #ax=axarr[k,k2]########################################### ax.set_ylim([0,Mmax]) #Fix subplot arrangement plt.subplots_adjust(left=0.02, bottom=0.02, right=0.9, top=0.98, wspace=0, hspace=0) @@ -1260,7 +1268,7 @@ def tile_moment(rupt,epicenter,nstrike,ndip,covfile,beta=0,vfast=0,vslow=0,shade return tout,Mout -def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize=True): +def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize=True,single_force=0): ''' Plot source time function of complete rupture ''' @@ -1288,8 +1296,7 @@ def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize= for kfault in range(nfault): if kfault%10==0: print('... working on subfault '+str(kfault)+' of '+str(nfault)) - #Get rupture times for subfault windows - i=where(num==unum[kfault])[0] + trup=f[i,12] #Get slips on windows ss=all_ss[i] @@ -1297,11 +1304,11 @@ def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize= #Add it up slip=(ss**2+ds**2)**0.5 if kfault==0:#Get first source time function - t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0]) + t1,M1=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[0],slip[0],single_force=single_force) #Loop over windows for kwin in range(nwin-1): #Get next source time function - t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1]) + t2,M2=get_source_time_function(mu[kfault],area[kfault],rise_time[kfault],trup[kwin+1],slip[kwin+1],single_force=single_force) #Add the soruce time functions t1,M1=add2stf(t1,M1,t2,M2) #Get power @@ -1317,7 +1324,10 @@ def source_time_function(rupt,epicenter,plot=True,xlim=None,ylim=None,normalize= plt.plot(t1,M1,color='k') plt.grid() plt.xlabel('Time(s)') - plt.ylabel('Moment Rate ('+r'$\times 10^{'+str(int(exp))+r'}$Nm/s)') + if single_force == 1: + plt.ylabel(f'Force Rate {exp} (Dyne or Newton/s)') + else: + plt.ylabel('Moment Rate ('+r'$\times 10^{'+str(int(exp))+r'}$Nm/s)') plt.subplots_adjust(left=0.3, bottom=0.3, right=0.7, top=0.7, wspace=0, hspace=0) if xlim!=None: plt.xlim(xlim) @@ -2974,4 +2984,4 @@ def slip2geo(ss,ds,strike): #Add em up x=xss+xds y=yss+yds - return x,y \ No newline at end of file + return x,y From ab7abfa420ba9bff84c6db7d1cb8e7db896defc5 Mon Sep 17 00:00:00 2001 From: JK Date: Thu, 4 Dec 2025 14:57:35 -0800 Subject: [PATCH 22/24] added tb for greens functions to pad with chosen number of zeros --- src/python/mudpy/green.py | 4 ++-- src/python/mudpy/parallel.py | 23 +++++++++++++---------- src/python/mudpy/runslip.py | 32 ++++++++++++++++---------------- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/python/mudpy/green.py b/src/python/mudpy/green.py index 89c83ad..70a2f64 100644 --- a/src/python/mudpy/green.py +++ b/src/python/mudpy/green.py @@ -35,13 +35,13 @@ def run_green(source,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax): if static==0: #Compute full waveform command=split("fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr) print("fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr) - #print(command) + print(command) p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) out,err=p.communicate() else: #Compute only statics command=split("fk.pl -M"+model_name+"/"+depth+"/f -N1 "+diststr) print("fk.pl -M"+model_name+"/"+depth+"/f -N1 "+diststr) - #print(command) + print(command) p=subprocess.Popen(command,stdout=open('staticgf','w'),stderr=subprocess.PIPE) out,err=p.communicate() #Log output diff --git a/src/python/mudpy/parallel.py b/src/python/mudpy/parallel.py index 89d8776..5be5f5a 100644 --- a/src/python/mudpy/parallel.py +++ b/src/python/mudpy/parallel.py @@ -3,7 +3,7 @@ ''' -def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force): +def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force,tb=50): ''' Compute GFs using Zhu & Rivera code for a given velocity model, source depth and station file. This function will make an external system call to fk.pl @@ -45,7 +45,8 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, kmax = %.3f insar = %s single = %s - ''' %(home,project_name,station_file,model_name,str(static),str(tsunami),dt,NFFT,dk,pmin,pmax,kmax,str(insar),str(single_force)) + tb = %s + ''' %(home,project_name,station_file,model_name,str(static),str(tsunami),dt,NFFT,dk,pmin,pmax,kmax,str(insar),str(single_force),str(tb)) print(out) #read your corresponding source file source=genfromtxt(home+project_name+'/data/model_info/mpi_source.'+str(rank)+'.fault') @@ -79,7 +80,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, #Make the calculation if static==0: #Compute full waveform if single_force==1: #compute for a single force and not coupled - command = "fk.pl -M"+model_name+"/"+depth+"/f -S1 -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr + command = "fk.pl -M"+model_name+"/"+depth+"/f -S1 -T"+str(tb)+" -G15 -N"+str(NFFT)+"/"+str(dt)+'/8/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr command=split(command) p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) p.communicate() @@ -90,7 +91,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, copy(f,newf) rmtree(subfault_folder+'/'+model_name+'_'+depth) else: - command = "fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr + command = "fk.pl -M"+model_name+"/"+depth+"/f -T"+str(tb)+" -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr command=split(command) p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) p.communicate() @@ -120,7 +121,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, def run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,quasistatic2dynamic,tsunami, - time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force=False,insar=False,okada=False,mu_okada=45e9): + time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force=False,insar=False,okada=False,mu_okada=45e9,tb=50): ''' 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 @@ -173,7 +174,8 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, okada = %s mu = %.2e single = %s - ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(quasistatic2dynamic),str(time_epi),beta,custom_stf,impulse,insar,okada,mu_okada,single_force) + tb = %s + ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(quasistatic2dynamic),str(time_epi),beta,custom_stf,impulse,insar,okada,mu_okada,single_force,tb) print(out) #Read your corresponding source file @@ -182,7 +184,7 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, #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) + tb=tb #Number of samples before first arrival (should be 50, NEVER CHANGE, if you do then adjust in fk.pl) ##Update from jk 12/3/2025 now can be changed with this input #Figure out custom STF if custom_stf.lower()!='none': @@ -901,7 +903,7 @@ def run_parallel_teleseismics_green(home,project_name,time_epi,station_file,mode -def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,forceMT,mt,insar,rank,size): +def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,forceMT,mt,insar,rank,size,single_force=False,tb=50): ''' 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 @@ -967,7 +969,7 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force mpi_source=genfromtxt(home+project_name+'/data/model_info/mpi_source.'+str(rank)+'.fault') #Constant parameters - tb=50 #Number of samples before first arrival (should be 50, NEVER CHANGE, if you do then adjust in fk.pl) + tb=tb #Number of samples before first arrival (should be 50, NEVER CHANGE, if you do then adjust in fk.pl) ##tb can be adjusted in fk now 12/3/2025 jk #Load structure model_file=home+project_name+'/structure/'+model_name @@ -1320,7 +1322,8 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force single_force=True elif single_force=='False': single_force=False - run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force) + tb=int(sys.argv[16]) + run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force,tb) elif sys.argv[1]=='run_parallel_synthetics': diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index ed20e7a..1bce3ed 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -177,7 +177,7 @@ def make_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,stat def make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar=False,okada=False): + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar=False,okada=False,tb=50): ''' This routine set's up the computation of GFs for each subfault to all stations. The GFs are impulse sources, they don't yet depend on strike and dip. @@ -240,7 +240,7 @@ def make_parallel_green(home,project_name,station_file,fault_name,model_name,dt, print('Static Okada solution requested, no need to run GFs...') pass else: - mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_green '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(dt)+' '+str(NFFT)+' '+str(static)+' '+str(dk)+' '+str(pmin)+' '+str(pmax)+' '+str(kmax)+' '+str(tsunami)+' '+str(insar)+' '+str(single_force) + mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_green '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(dt)+' '+str(NFFT)+' '+str(static)+' '+str(dk)+' '+str(pmin)+' '+str(pmax)+' '+str(kmax)+' '+str(tsunami)+' '+str(insar)+' '+str(single_force)+' '+str(tb) print(mpi) mpi=split(mpi) p=subprocess.Popen(mpi) @@ -366,7 +366,7 @@ def make_synthetics(home,project_name,station_file,fault_name,model_name,integra #Now make synthetics for source/station pairs def make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic, - tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9): + tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9,tb=50): ''' This routine will take the impulse response (GFs) and pass it into the routine that will convovle them with the source time function according to each subfaults strike and dip. @@ -409,7 +409,7 @@ def make_parallel_synthetics(home,project_name,station_file,fault_name,model_nam #Make mpi system call print("MPI: Starting synthetics computation on", ncpus, "CPUs\n") mud_source=environ['MUD']+'/src/python/mudpy/' - mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_synthetics '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(integrate)+' '+str(static)+' '+str(quasistatic2dynamic)+' '+str(tsunami)+' '+str(time_epi)+' '+str(beta)+' '+str(custom_stf)+' '+str(impulse)+' '+str(insar)+' '+str(okada)+' '+str(mu)+' '+str(NFFT)+' '+str(dt)+' '+str(single_force) + mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_synthetics '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(integrate)+' '+str(static)+' '+str(quasistatic2dynamic)+' '+str(tsunami)+' '+str(time_epi)+' '+str(beta)+' '+str(custom_stf)+' '+str(impulse)+' '+str(insar)+' '+str(okada)+' '+str(mu)+' '+str(NFFT)+' '+str(dt)+' '+str(single_force)+' '+str(tb) print(mpi) mpi=split(mpi) p=subprocess.Popen(mpi) @@ -422,7 +422,7 @@ def make_parallel_synthetics(home,project_name,station_file,fault_name,model_nam def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, dt,tsun_dt,NFFT,tsunNFFT,green_flag,synth_flag,dk,pmin, pmax,kmax,beta,time_epi,hot_start,ncpus,custom_stf,single_force=False,quasistatic2dynamic=0, - impulse=False): + impulse=False,tb=50): ''' This routine will read a .gflist file and compute the required GF type for each station ''' @@ -460,7 +460,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False insar=False make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar,tb=tb) i=where(GF[:,3]==1)[0] if len(i)>0 : #displ waveform print('Displacememnt GFs requested...') @@ -474,7 +474,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, if single_force==1: #Using single force not coupled single_force=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb) i=where(GF[:,4]==1)[0] if len(i)>0 : #vel waveform print('Velocity GFs requested...') @@ -488,7 +488,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, if single_force==1: #Using single force not coupled single_force=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb) if tgf_file!=None: #Tsunami print('Seafloor displacement GFs requested...') # static=0 @@ -496,7 +496,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=True station_file=tgf_file make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb) i=where(GF[:,6]==1)[0] if len(i)>0: #InSAR LOS print('InSAR GFs requested...') @@ -510,7 +510,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False insar=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar,tb=tb) collect() #Synthetics are computed one station at a time if synth_flag==1: @@ -530,7 +530,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=False insar=False - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar,tb=tb) #Decide which synthetics are required i=where(GF[:,3]==1)[0] if len(i)>0: #dispalcement waveform @@ -549,7 +549,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False else: #I am computing seafloor deformation for tsunami GFs, eventaully tsunami=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb) #Decide which synthetics are required i=where(GF[:,4]==1)[0] if len(i)>0: #velocity waveform @@ -568,7 +568,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False else: #I am computing seafloor deformation for tsunami GFs, eventaully tsunami=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb) #Decide which synthetics are required i=where(GF[:,5]==1)[0] if len(i)>0: #tsunami waveform @@ -583,7 +583,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=True station_file=tgf_file - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb) #Decide which synthetics are required i=where(GF[:,6]==1)[0] if len(i)>0: # InSAR LOS @@ -599,7 +599,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=False insar=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar,tb=tb) @@ -621,7 +621,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=0 tsunami=False insar=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,insar) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,insar,tb=tb) else: From ee9e7f63346a25b152bb5bc5a917e52f36325598 Mon Sep 17 00:00:00 2001 From: JK Date: Fri, 23 Jan 2026 11:00:18 -0800 Subject: [PATCH 23/24] updated to be set dates properly with dt when using a smth that changes it within the sac file --- src/python/mudpy/green.py | 23 ++++++++---------- src/python/mudpy/parallel.py | 47 +++++++++++++++++++----------------- src/python/mudpy/runslip.py | 41 +++++++++++++++---------------- 3 files changed, 55 insertions(+), 56 deletions(-) diff --git a/src/python/mudpy/green.py b/src/python/mudpy/green.py index 70a2f64..5c62779 100644 --- a/src/python/mudpy/green.py +++ b/src/python/mudpy/green.py @@ -5,7 +5,7 @@ -def run_green(source,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax): +def run_green(source,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,smth): ''' Compute GFs using Zhu & Rivera code for a given velocity model, source depth and station file. This function will make an external system call to fk.pl @@ -33,8 +33,8 @@ def run_green(source,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax): for k in range(len(d)): diststr=diststr+' %.3f' % d[k] #Truncate distance to 3 decimal palces (meters) if static==0: #Compute full waveform - command=split("fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr) - print("fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr) + command=split("fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/'+str(smth)+'/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr) + print("fk.pl -M"+model_name+"/"+depth+"/f -N"+str(NFFT)+"/"+str(dt)+'/'+str(smth)+'/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr) print(command) p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) out,err=p.communicate() @@ -57,7 +57,7 @@ def run_green(source,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax): 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): + subfault,time_epi,beta,impulse=False,okada=False,okada_mu=45e9,insar=False,tb=50): ''' 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 @@ -89,7 +89,7 @@ def run_syn(home,project_name,source,station_file,green_path,model_name,integrat #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 + #tb=50 #Number of samples before first arrival ## tb is now an input for run_syn and changes based on if there was an input added 12/10/2025 JK #Load structure model_file=home+project_name+'/structure/'+model_name structure=loadtxt(model_file,ndmin=2) @@ -466,7 +466,7 @@ def src2sta(station_file,source,output_coordinates=False): -def origin_time(st,time_epi,tb): +def origin_time(st,time_epi,tb,dt): ''' Make start time of synthetics correspond with epicentral time @@ -483,13 +483,10 @@ def origin_time(st,time_epi,tb): ''' from datetime import timedelta - - t1=st[0].stats.starttime #Waveform starttime - td=timedelta(seconds=st[0].stats.delta*tb) #Shift due to pre-first arrival samples - #Shift forward - t1=t1+td - #Shift to oring time - t1=time_epi+timedelta(minutes=t1.minute,seconds=t1.second,microseconds=t1.microsecond)-td + + p_wave_time = dt * tb + st[0].stats.sac.b #fk calculated time for p wave arrival time + padding = dt * tb #padding time input + t1 = time_epi + p_wave_time - padding #adjusted time for event, based on p wave arrival time and zero padding st[0].stats.starttime=t1 #Set default sac headers to avoid invalid SAC write st[0].stats.sac['nzyear'] = t1.year diff --git a/src/python/mudpy/parallel.py b/src/python/mudpy/parallel.py index 5be5f5a..d4858cc 100644 --- a/src/python/mudpy/parallel.py +++ b/src/python/mudpy/parallel.py @@ -3,7 +3,7 @@ ''' -def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force,tb=50): +def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force,tb=50,smth=1): ''' Compute GFs using Zhu & Rivera code for a given velocity model, source depth and station file. This function will make an external system call to fk.pl @@ -46,7 +46,8 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, insar = %s single = %s tb = %s - ''' %(home,project_name,station_file,model_name,str(static),str(tsunami),dt,NFFT,dk,pmin,pmax,kmax,str(insar),str(single_force),str(tb)) + smth = %s + ''' %(home,project_name,station_file,model_name,str(static),str(tsunami),dt,NFFT,dk,pmin,pmax,kmax,str(insar),str(single_force),str(tb),str(smth)) print(out) #read your corresponding source file source=genfromtxt(home+project_name+'/data/model_info/mpi_source.'+str(rank)+'.fault') @@ -80,7 +81,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, #Make the calculation if static==0: #Compute full waveform if single_force==1: #compute for a single force and not coupled - command = "fk.pl -M"+model_name+"/"+depth+"/f -S1 -T"+str(tb)+" -G15 -N"+str(NFFT)+"/"+str(dt)+'/8/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr + command = "fk.pl -M"+model_name+"/"+depth+"/f -S1 -T"+str(tb)+" -G15 -N"+str(NFFT)+"/"+str(dt)+'/'+str(smth)+'/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr command=split(command) p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) p.communicate() @@ -91,7 +92,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, copy(f,newf) rmtree(subfault_folder+'/'+model_name+'_'+depth) else: - command = "fk.pl -M"+model_name+"/"+depth+"/f -T"+str(tb)+" -N"+str(NFFT)+"/"+str(dt)+'/1/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr + command = "fk.pl -M"+model_name+"/"+depth+"/f -T"+str(tb)+" -N"+str(NFFT)+"/"+str(dt)+'/'+str(smth)+'/'+repr(dk)+' -P'+repr(pmin)+'/'+repr(pmax)+'/'+repr(kmax)+diststr command=split(command) p=subprocess.Popen(command,stdout=subprocess.PIPE,stderr=subprocess.PIPE) p.communicate() @@ -101,7 +102,6 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, newf=subfault_folder+'/'+f.split('/')[-1] copy(f,newf) rmtree(subfault_folder+'/'+model_name+'_'+depth) - print(command) else: #Compute only statics if insar==True: suffix='insar' @@ -121,7 +121,7 @@ def run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static, def run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,quasistatic2dynamic,tsunami, - time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force=False,insar=False,okada=False,mu_okada=45e9,tb=50): + time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force=False,insar=False,okada=False,mu_okada=45e9,tb=50,smth=1): ''' 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 @@ -175,7 +175,8 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, mu = %.2e single = %s tb = %s - ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(quasistatic2dynamic),str(time_epi),beta,custom_stf,impulse,insar,okada,mu_okada,single_force,tb) + smth = %s + ''' %(home,project_name,station_file,model_name,str(integrate),str(static),str(tsunami),str(quasistatic2dynamic),str(time_epi),beta,custom_stf,impulse,insar,okada,mu_okada,single_force,tb,smth) print(out) #Read your corresponding source file @@ -327,7 +328,6 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, 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) - print(commandSS) else: #Make vel. #First Stike-Slip GFs if custom_stf==None: @@ -391,9 +391,9 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, 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=origin_time(n,time_epi,tb,dt) + e=origin_time(e,time_epi,tb,dt) + z=origin_time(z,time_epi,tb,dt) 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') @@ -418,9 +418,9 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, 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=origin_time(n,time_epi,tb,dt) + e=origin_time(e,time_epi,tb,dt) + z=origin_time(z,time_epi,tb,dt) 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') @@ -446,9 +446,9 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, 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=origin_time(n,time_epi,tb,dt) + e=origin_time(e,time_epi,tb,dt) + z=origin_time(z,time_epi,tb.dt) 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') @@ -473,9 +473,9 @@ def run_parallel_synthetics(home,project_name,station_file,model_name,integrate, 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=origin_time(n,time_epi,tb,dt) + e=origin_time(e,time_epi,tb,dt) + z=origin_time(z,time_epi,tb.dt) 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') @@ -1323,7 +1323,8 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force elif single_force=='False': single_force=False tb=int(sys.argv[16]) - run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force,tb) + smth=int(sys.argv[17]) + run_parallel_green(home,project_name,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,tsunami,insar,rank,size,single_force,tb,smth) elif sys.argv[1]=='run_parallel_synthetics': @@ -1362,8 +1363,10 @@ def run_parallel_synthetics_mt3d(home,project_name,station_file,model_name,force single_force=True elif single_force=='False': single_force=False + tb=int(sys.argv[20]) + smth=int(sys.argv[21]) - run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,quasistatic2dynamic,tsunami,time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force,insar,okada,mu_okada) + run_parallel_synthetics(home,project_name,station_file,model_name,integrate,static,quasistatic2dynamic,tsunami,time_epi,beta,custom_stf,impulse,NFFT,dt,rank,size,single_force,insar,okada,mu_okada,tb,smth) elif sys.argv[1]=='run_parallel_teleseismics_green': home=sys.argv[2] diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index 1bce3ed..bc10f23 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -82,7 +82,7 @@ def rupt2fault(home,project_name,rupture_name): # Run green functions def make_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,okada=False): + hot_start,dk,pmin,pmax,kmax,okada=False,smth=1): ''' This routine set's up the computation of GFs for each subfault to all stations. The GFs are impulse sources, they don't yet depend on strike and dip. @@ -125,7 +125,7 @@ def make_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,stat source=loadtxt(fault_file,ndmin=2) for k in range(hot_start,source.shape[0]): #Run comptuation for 1 subfault - log=green.run_green(source[k,:],station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax) + log=green.run_green(source[k,:],station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,smth) #Write log f=open(logpath+'make_green.'+now+'.log','a') f.write(log) @@ -177,7 +177,7 @@ def make_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,stat def make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar=False,okada=False,tb=50): + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar=False,okada=False,tb=50,smth=1): ''' This routine set's up the computation of GFs for each subfault to all stations. The GFs are impulse sources, they don't yet depend on strike and dip. @@ -240,7 +240,7 @@ def make_parallel_green(home,project_name,station_file,fault_name,model_name,dt, print('Static Okada solution requested, no need to run GFs...') pass else: - mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_green '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(dt)+' '+str(NFFT)+' '+str(static)+' '+str(dk)+' '+str(pmin)+' '+str(pmax)+' '+str(kmax)+' '+str(tsunami)+' '+str(insar)+' '+str(single_force)+' '+str(tb) + mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_green '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(dt)+' '+str(NFFT)+' '+str(static)+' '+str(dk)+' '+str(pmin)+' '+str(pmax)+' '+str(kmax)+' '+str(tsunami)+' '+str(insar)+' '+str(single_force)+' '+str(tb)+' '+str(smth) print(mpi) mpi=split(mpi) p=subprocess.Popen(mpi) @@ -318,7 +318,7 @@ def make_parallel_teleseismics_green(home,project_name,station_file,fault_name,m #Now make synthetics for source/station pairs def make_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,tsunami,beta, - hot_start,time_epi,impulse=False,okada=False,mu=45e9,insar=False): + hot_start,time_epi,impulse=False,okada=False,mu=45e9,insar=False,tb=50): ''' This routine will take the impulse response (GFs) and pass it into the routine that will convovle them with the source time function according to each subfaults strike and dip. @@ -357,16 +357,15 @@ def make_synthetics(home,project_name,station_file,fault_name,model_name,integra print('ksource = ' + str(k)) subfault=str(k+1).rjust(4,'0') log=green.run_syn(home,project_name,source[k,:],station_file,green_path,model_name,integrate,static,tsunami, - subfault,time_epi,beta,impulse,okada,mu,insar=insar) + subfault,time_epi,beta,impulse,okada,mu,insar=insar,tb=tb) f=open(logpath+'make_synth.'+now+'.log','a') f.write(log) f.close() gc.collect() - #Now make synthetics for source/station pairs def make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic, - tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9,tb=50): + tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9,tb=50,smth=1): ''' This routine will take the impulse response (GFs) and pass it into the routine that will convovle them with the source time function according to each subfaults strike and dip. @@ -409,7 +408,7 @@ def make_parallel_synthetics(home,project_name,station_file,fault_name,model_nam #Make mpi system call print("MPI: Starting synthetics computation on", ncpus, "CPUs\n") mud_source=environ['MUD']+'/src/python/mudpy/' - mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_synthetics '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(integrate)+' '+str(static)+' '+str(quasistatic2dynamic)+' '+str(tsunami)+' '+str(time_epi)+' '+str(beta)+' '+str(custom_stf)+' '+str(impulse)+' '+str(insar)+' '+str(okada)+' '+str(mu)+' '+str(NFFT)+' '+str(dt)+' '+str(single_force)+' '+str(tb) + mpi='mpiexec -n '+str(ncpus)+' python '+mud_source+'parallel.py run_parallel_synthetics '+home+' '+project_name+' '+station_file+' '+model_name+' '+str(integrate)+' '+str(static)+' '+str(quasistatic2dynamic)+' '+str(tsunami)+' '+str(time_epi)+' '+str(beta)+' '+str(custom_stf)+' '+str(impulse)+' '+str(insar)+' '+str(okada)+' '+str(mu)+' '+str(NFFT)+' '+str(dt)+' '+str(single_force)+' '+str(tb)+' '+str(smth) print(mpi) mpi=split(mpi) p=subprocess.Popen(mpi) @@ -422,7 +421,7 @@ def make_parallel_synthetics(home,project_name,station_file,fault_name,model_nam def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, dt,tsun_dt,NFFT,tsunNFFT,green_flag,synth_flag,dk,pmin, pmax,kmax,beta,time_epi,hot_start,ncpus,custom_stf,single_force=False,quasistatic2dynamic=0, - impulse=False,tb=50): + impulse=False,tb=50,smth=1): ''' This routine will read a .gflist file and compute the required GF type for each station ''' @@ -460,7 +459,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False insar=False make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar,tb=tb) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar,tb=tb,smth=smth) i=where(GF[:,3]==1)[0] if len(i)>0 : #displ waveform print('Displacememnt GFs requested...') @@ -474,7 +473,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, if single_force==1: #Using single force not coupled single_force=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb,smth=smth) i=where(GF[:,4]==1)[0] if len(i)>0 : #vel waveform print('Velocity GFs requested...') @@ -488,7 +487,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, if single_force==1: #Using single force not coupled single_force=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb,smth=smth) if tgf_file!=None: #Tsunami print('Seafloor displacement GFs requested...') # static=0 @@ -496,7 +495,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=True station_file=tgf_file make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,tb=tb,smth=smth) i=where(GF[:,6]==1)[0] if len(i)>0: #InSAR LOS print('InSAR GFs requested...') @@ -510,7 +509,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False insar=True make_parallel_green(home,project_name,station_file,fault_name,model_name,dt,NFFT,static,tsunami, - hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar,tb=tb) + hot_start,dk,pmin,pmax,kmax,ncpus,single_force,insar,tb=tb,smth=smth) collect() #Synthetics are computed one station at a time if synth_flag==1: @@ -530,7 +529,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=False insar=False - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar,tb=tb) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar,tb=tb,smth=smth) #Decide which synthetics are required i=where(GF[:,3]==1)[0] if len(i)>0: #dispalcement waveform @@ -549,7 +548,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False else: #I am computing seafloor deformation for tsunami GFs, eventaully tsunami=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb,smth=smth) #Decide which synthetics are required i=where(GF[:,4]==1)[0] if len(i)>0: #velocity waveform @@ -568,7 +567,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, tsunami=False else: #I am computing seafloor deformation for tsunami GFs, eventaully tsunami=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb,smth=smth) #Decide which synthetics are required i=where(GF[:,5]==1)[0] if len(i)>0: #tsunami waveform @@ -583,7 +582,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=True station_file=tgf_file - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,tb=tb,smth=smth) #Decide which synthetics are required i=where(GF[:,6]==1)[0] if len(i)>0: # InSAR LOS @@ -599,7 +598,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=1 tsunami=False insar=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar,tb=tb) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,single_force,insar,tb=tb,smth=smth) @@ -621,7 +620,7 @@ def inversionGFs(home,project_name,GF_list,tgf_file,fault_name,model_name, static=0 tsunami=False insar=True - make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,insar,tb=tb) + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic,tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse,insar,tb=tb,smth=smth) else: From c7072277ab5957c0edf53ef6ca17ac8d02125f68 Mon Sep 17 00:00:00 2001 From: JK Date: Fri, 23 Jan 2026 12:09:49 -0800 Subject: [PATCH 24/24] rerouted make_synthetics to make_parallel_synethetics with a single cpu and removed run_syn because nothing uses it anymore --- src/python/mudpy/green.py | 291 ------------------------------------ src/python/mudpy/runslip.py | 35 +---- 2 files changed, 7 insertions(+), 319 deletions(-) diff --git a/src/python/mudpy/green.py b/src/python/mudpy/green.py index 5c62779..a86530b 100644 --- a/src/python/mudpy/green.py +++ b/src/python/mudpy/green.py @@ -56,297 +56,6 @@ def run_green(source,station_file,model_name,dt,NFFT,static,dk,pmin,pmax,kmax,sm -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,tb=50): - ''' - 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,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 ## tb is now an input for run_syn and changes based on if there was an input added 12/10/2025 JK - #Load structure - model_file=home+project_name+'/structure/'+model_name - structure=loadtxt(model_file,ndmin=2) - #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: #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="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 - 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 okada_synthetics(strike,dip,rake,length,width,lon_source,lat_source, depth_source,lon_obs,lat_obs,mu): ''' diff --git a/src/python/mudpy/runslip.py b/src/python/mudpy/runslip.py index bc10f23..14d822b 100644 --- a/src/python/mudpy/runslip.py +++ b/src/python/mudpy/runslip.py @@ -317,10 +317,11 @@ def make_parallel_teleseismics_green(home,project_name,station_file,fault_name,m #Now make synthetics for source/station pairs -def make_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,tsunami,beta, - hot_start,time_epi,impulse=False,okada=False,mu=45e9,insar=False,tb=50): +def make_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic, + tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9,tb=50,smth=1): ''' - This routine will take the impulse response (GFs) and pass it into the routine that will + **This routine was absolete so it was removed and rerouted to make_parallel_synthetics with single CPU** + This will take the impulse response (GFs) and pass it into the routine that will convovle them with the source time function according to each subfaults strike and dip. The result fo this computation is a time series dubbed a "synthetic" @@ -338,32 +339,10 @@ def make_synthetics(home,project_name,station_file,fault_name,model_name,integra OUT: Nothing ''' - from mudpy import green - import datetime - from numpy import loadtxt - import gc - - green_path=home+project_name+'/GFs/' - station_file=home+project_name+'/data/station_info/'+station_file - fault_file=home+project_name+'/data/model_info/'+fault_name - logpath=home+project_name+'/logs/' - #Time for log file - now=datetime.datetime.now() - now=now.strftime('%b-%d-%H%M') - #First read fault model file - source=loadtxt(fault_file,ndmin=2) - #Now compute synthetics please, one sub fault at a time - for k in range(hot_start,source.shape[0]): - print('ksource = ' + str(k)) - subfault=str(k+1).rjust(4,'0') - log=green.run_syn(home,project_name,source[k,:],station_file,green_path,model_name,integrate,static,tsunami, - subfault,time_epi,beta,impulse,okada,mu,insar=insar,tb=tb) - f=open(logpath+'make_synth.'+now+'.log','a') - f.write(log) - f.close() - gc.collect() + + make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic, + tsunami,beta,hot_start,time_epi,1,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9,tb=50,smth=1): -#Now make synthetics for source/station pairs def make_parallel_synthetics(home,project_name,station_file,fault_name,model_name,integrate,static,quasistatic2dynamic, tsunami,beta,hot_start,time_epi,ncpus,custom_stf,NFFT,dt,impulse=False,single_force=False,insar=False,okada=False,mu=45e9,tb=50,smth=1): '''