def qtest_pocs(st_rec, st_orginal, alpharange, irange): """ Runs the selected method in a certain range of parameters (iterations and alpha), returns a table of Q values ,defined as: Q = 10 * log( || d_org || ^2 _2 / || d_org - d_rec || ^2 _2 ) The highest Q value is the one to be chosen. """ Qall = [] dmethod = 'reconstruct' method = 'linear' st_org = st_orginal.copy() data_org= stream2array(st_org, normalize=True) for alpha in alpharange: print("##################### CURRENT ALPHA %f #####################\n" % alpha ) for i in irange: print('POCS RECON WITH %i ITERATIONS' % i, end="\r") sys.stdout.flush() srs = st_rec.copy() st_pocsrec = pocs_recon(srs, maxiter=int(i), method=method, dmethod=dmethod, alpha=alpha) drec = stream2array(st_pocsrec, normalize=True) Q_tmp = np.linalg.norm(data_org,2)**2. / np.linalg.norm(data_org - drec,2)**2. Q = 10.*np.log(Q_tmp) Qall.append([alpha, i, Q]) Qmax = [0,0,0] for i in Qall: if i[2] > Qmax[2]: Qmax = i return Qall
noise = np.fromfile('../data/test_datasets/randnumbers/noisearr.txt') noise = noise.reshape(20,300) with open("../data/test_datasets/ricker/rickerlist.dat", 'r') as fh: rickerlist = np.array(fh.read().split()).astype('str') noisefoldlist = ["no_noise"] #,"10pct_noise", "20pct_noise", "50pct_noise", "60pct_noise", "80pct_noise"] noiselevellist = np.array([0.]) #, 0.1, 0.2, 0.5, 0.6, 0.8]) alphalist = np.linspace(0.01, 0.9, 10) maxiterlist = np.arange(11)[1:] bwlist = [1,2,4] taperlist = [2,4,5,8,200] stream_org = read_st('/home/s_schn42/dev/FK-Toolbox/data/test_datasets/ricker/original/SR.QHD') d0 = stream2array(stream_org.copy(), normalize=True) peaks = np.array([[-13.95 , 6.06 , 20.07 ],[ 8.46648822, 8.42680793, 8.23354933]]) errors = [] FPATH = '/home/s_schn42/dev/FK-Toolbox/data/test_datasets/ricker/' for i, noisefolder in enumerate(noisefoldlist): print("##################### NOISELVL %i %% #####################\n" % int(noiselevellist[i] * 100.) ) for filein in rickerlist: print("##################### CURRENT FILE %s #####################\n" % filein ) PICPATH = filein[:filein.rfind("/"):] + "/" + noisefolder + "/" FNAME = filein[filein.rfind("/"):].split('/')[1].split('.')[0] plotname = FPATH + FNAME + 'pocs_' + 'nlvl' + str(noiselevellist[i]) + '_linear''.png' plotname2 = FPATH + FNAME + 'pocs_' + 'nlvl' + str(noiselevellist[i]) + '_mask' '.png' if not os.path.isdir(PICPATH): os.mkdir(PICPATH) PATH = filein stream = read_st(PATH)
def radon_inverse(st, inv, event, p, weights, line_model, inversion_model, hyperparameters): """ This function inverts move-out data to the Radon domain given the inputs: :param st: :param inv: :param event: :param p: -- vector of slowness axis you would like to invert to. :param weights: -- weighting vector that determines importance of each trace. set vector to ones for no preference. :param line_model: select one of the following options for path integration: 'linear' - linear paths in the spatial domain (default) 'parabolic' - parabolic paths in the spatial domain. :param inversion model: select one of the following options for regularization schema: 'L2' - Regularized on the L2 norm of the Radon domain (default) 'L1' - Non-linear regularization based on L1 norm and iterative reweighted least sqaures (IRLS) see Sacchi 1997. 'Cauchy' - Non-linear regularization see Sacchi & Ulrych 1995 :param hyperparameters: trades-off between fitting the data and chosen damping. returns: radon domain is ordered size(R)==[length(p),length(t)], time-axis and distance-axis. Known limitations: - Assumes evenly sampled time axis. - Assumes move-out data isn't complex. References: Schultz, R., Gu, Y. J., 2012. Flexible Matlab implementation of the Radon Transform. Computers and Geosciences. An, Y., Gu, Y. J., Sacchi, M., 2007. Imaging mantle discontinuities using least-squares Radon transform. Journal of Geophysical Research 112, B10303. Author: R. Schultz, 2012 Translated to Python by: S. Schneider, 2016 """ # Check for Data type of variables. if not isinstance(st, Stream) or not isinstance(inv, Inventory) or not isinstance(event, Event): msg = "Wrong input type must be obspy Stream, Inventory and Event" raise TypeError if not isinstance(hyperparameters,list): msg = "Wrong input type of mu, must be list" raise TypeError # Define some array/matrices lengths. st_tmp = st.copy() M = stream2array(st_tmp) epi = epidist2nparray(attach_epidist2coords(inv, event, st_tmp)) delta = np.array([ epi.copy() ]) ref_dist = np.mean(delta) if not weights: weights = np.ones(delta.size) t = np.linspace(0,st_tmp[0].stats.delta * st_tmp[0].stats.npts, st_tmp[0].stats.npts) it=t.size print(it) iF=int(math.pow(2,nextpow2(it)+1)) # Double length iDelta=delta.size ip=len(p) iw=len(weights) #Exit if inconsistent data is input. if M.shape != (iDelta, it): print("Dimensions inconsistent!\nShape of M is not equal to (len(delta),len(t)) \nShape of M = (%i , %i)\n(len(delta),len(t)) = (%i, %i) \n" % (M.shape[0], M.shape[1], iDelta, it) ) R=0 return(R) if iw != iDelta: print("Dimensions inconsistent!\nlen(delta) ~= len(weights)\nlen(delta) = %i\nlen(weights) = %i\n" % (iDelta, iw)) R=0 return(R) #Exit if improper hyperparameters are entered. if inversion_model in ["L1", "Cauchy"]: if not len(hyperparameters == 2): print("Improper number of trade-off parameters\n") R=0 return(R) else: #The code's default is L2 inversion. if not len(hyperparameters) == 1: print("Improper number of trade-off parameters\n") R=0 return(R) #Preallocate space in memory. R=np.zeros((ip,it)) Rfft=np.zeros((ip,iF)) + 0j A=np.zeros((iDelta,ip)) + 0j Tshift=np.zeros((iDelta,ip)) + 0j AtA=np.zeros((ip,ip)) + 0j AtM=np.zeros((ip,1)) + 0j Ident=np.identity(ip) #Define some values Dist_array=delta-ref_dist dF=1./(t[0]-t[1]) Mfft=np.fft.fft(M,iF,1) W=sparse.spdiags(weights.conj().transpose(), 0, iDelta, iDelta).A dCOST=0. COST_curv=0. COST_prev=0. #Populate ray parameter then distance data in time shift matrix. for j in range(iDelta): if line_model == "parabolic": Tshift[j]=p else: #Linear is default Tshift[j]=p for k in range(ip): if line_model == 'parabolic': Tshift[:,k]=(2. * ref_dist * Tshift[:,k] * Dist_array.conj().transpose()) + (Tshift[:,k] * (Dist_array**2).conj().transpose()) else: #Linear is default Tshift[:,k]=Tshift[:,k] * Dist_array[0].conj().transpose() # Loop through each frequency. for i in range( int(math.floor((iF+1)/2)) ): print('Step %i of %i' % (i, int(math.floor((iF+1)/2))) ) # Make time-shift matrix, A. f = ((float(i)/float(iF))*dF) A = np.exp( (0.+1j)*2*pi*f * Tshift ) # M = A R ---> AtM = AtA R # Solve the weighted, L2 least-squares problem for an initial solution. AtA = dot( dot(A.conj().transpose(), W), A ) AtM = dot( A.conj().transpose(), dot( W, Mfft[:,i] ) ) mu = abs(np.trace(AtA)) * hyperparameters[0] Rfft[:,i] = sp.linalg.solve((AtA + mu*Ident), AtM) #Non-linear methods use IRLS to solve, iterate until convergence to solution. if inversion_model in ("Cauchy", "L1"): #Initialize hyperparameters. b=hyperparameters[1] lam=mu*b #Initialize cost functions. dCOST = float("Inf") if inversion_model == "Cauchy": COST_prev = np.linalg.norm( Mfft[:,i] - dot(A,Rfft[:,i]), 2 ) + lam*sum( np.log( abs(Rfft[:,i]**2 + b) ) ) elif inversion_model == "L1": COST_prev = np.linalg.norm( Mfft[:,i] - dot(A,Rfft[:,i]), 2 ) + lam*np.linalg.norm( abs(Rfft[:,i]+1), 1 ) itercount=1 #Iterate until negligible change to cost function. while dCost > 0.001 and itercount < 10: #Setup inverse problem. if inversion_model == "Cauchy": Q = sparse.spdiags( 1./( abs(Rfft[:,i]**2) + b), 0, ip, ip).A elif inversion_model == "L1": Q = sparse.spdiags( 1./( abs(Rfft[:,i]) + b), 0, ip, ip).A Rfft[:,i]=sp.linalg.solve( ( lam * Q + AtA ), AtM ) #Determine change to cost function. if inversion_model == "Cauchy": COST_cur = np.linalg.norm( Mfft[:,i]-A*Rfft[:,i], 2 ) + lam*sum( np.log( abs(Rfft[:,i]**2 + b )-np.log(b) ) ) elif inversion_model == "L1": COST_cur = np.linalg.norm( Mfft[:,i]-A*Rfft[:,i], 2 ) + lam*np.linalg.norm( abs(Rfft[:,i]+1) + b, 1 ) dCOST = 2*abs(COST_cur - COST_prev)/(abs(COST_cur) + abs(COST_prev)) COST_prev = COST_cur itercount += 1 #Assuming Hermitian symmetry of the fft make negative frequencies the complex conjugate of current solution. if i != 0: Rfft[:,iF-i] = Rfft[:,i].conjugate() R = np.fft.ifft(Rfft, iF) R = R[:,0:it] return R, t, epi