def image_data(self,dat,dt,minf,maxf,vel,jf=1,nhx=0,nhy=0,sym=True,nrmax=3,eps=0.,dtmax=5e-05,wav=None, ntx=0,nty=0,px=0,py=0,nthrds=1,sverb=True,wverb=False): """ 3D migration of shot profile data via the one-way wave equation (single-square root split-step fourier method). Parameters: dat - input shot profile data [ntr,nt] dt - temporal sampling of input data minf - minimum frequency to image in the data [Hz] maxf - maximum frequency to image in the data [Hz] vel - input migration velocity model [nz,ny,nx] jf - frequency decimation factor [1] nhx - number of subsurface offsets in x to compute [0] nhy - number of subsurface offsets in y to compute [0] sym - symmetrize the subsurface offsets [True] nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] wav - input wavelet [None,assumes an impulse at zero lag] ntx - size of taper in x direction [0] nty - size of taper in y direction [0] px - amount of padding in x direction (samples) [0] py - amount of padding in y direction (samples) [0] nthrds - number of OpenMP threads for frequency parallelization [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progress bar [False] Returns: an image created from the data [nhy,nhx,nz,ny,nx] """ # Make sure data are same size as coordinates if(dat.shape[0] != self.__ntr): raise Exception("Data must have same number of traces passed to constructor") # Get temporal axis nt = dat.shape[-1] # Create frequency domain source if(wav is None): wav = np.zeros(nt,dtype='float32') wav[0] = 1.0 self.__nwo,self.__ow,self.__dw,wfft = fft1(wav,dt,minf=minf,maxf=maxf) wfftd = wfft[::jf] self.__nwc = wfftd.shape[0] # Get the number of frequencies for imaging self.__dwc = self.__dw*jf if(sverb or wverb): print("Frequency axis: nw=%d ow=%f dw=%f"%(self.__nwc,self.__ow,self.__dwc)) # Create frequency domain data _,_,_,dfft = fft1(dat,dt,minf=minf,maxf=maxf) dfftd = dfft[:,::jf] # Allocate the data for one shot datw = np.zeros([self.__ny,self.__nx,self.__nwc],dtype='complex64') # Allocate the source for one shot sou = np.zeros([self.__nwc,self.__ny,self.__nx],dtype='complex64') # Single square root object ssf = ssr3(self.__nx ,self.__ny,self.__nz , # Spatial Sizes self.__dx ,self.__dy,self.__dz , # Spatial Samplings self.__nwc,self.__ow,self.__dwc,eps, # Frequency axis ntx,nty,px,py, # Taper and padding dtmax,nrmax,nthrds) # Reference velocities and threads # Compute slowness and reference slownesses slo = 1/vel ssf.set_slows(slo) # Allocate partial image array if(nhx == 0 and nhy == 0): imgtmp = np.zeros([self.__nz,self.__ny,self.__nx],dtype='float32') oimg = np.zeros([self.__nz,self.__ny,self.__nx],dtype='float32') else: if(sym): # Create axes self.__rnhx = 2*nhx+1; self.__ohx = -nhx*self.__dx; self.__dhx = self.__dx self.__rnhy = 2*nhy+1; self.__ohy = -nhy*self.__dy; self.__dhy = self.__dy imgtmp = np.zeros([self.__rnhy,self.__rnhx,self.__nz,self.__ny,self.__nx],dtype='float32') oimg = np.zeros([self.__rnhy,self.__rnhx,self.__nz,self.__ny,self.__nx],dtype='float32') else: # Create axes self.__rnhx = nhx+1; self.__ohx = 0; self.__dhx = self.__dx self.__rnhy = nhy+1; self.__ohy = 0; self.__dhy = self.__dy imgtmp = np.zeros([self.__rnhy,self.__rnhx,self.__nz,self.__ny,self.__nx],dtype='float32') oimg = np.zeros([self.__rnhy,self.__rnhx,self.__nz,self.__ny,self.__nx],dtype='float32') # Allocate memory necessary for extension ssf.set_ext(nhy,nhx,sym) # Loop over sources ntr = 0 for iexp in progressbar(range(self.__nexp),"nexp:",verb=sverb): # Get the source coordinates sy = self.__srcys[iexp]; sx = self.__srcxs[iexp] isy = int((sy-self.__oy)/self.__dy+0.5); isx = int((sx-self.__ox)/self.__dx+0.5) # Create the source wavefield for this shot sou[:] = 0.0 sou[:,isy,isx] = wfftd[:] # Inject the data for this shot datw[:] = 0.0 ssf.inject_data(self.__nrec[iexp],self.__recys[ntr:],self.__recxs[ntr:],self.__oy,self.__ox,dfftd[ntr:,:],datw) datwt = np.ascontiguousarray(np.transpose(datw,(2,0,1))) # [ny,nx,nwc] -> [nwc,ny,nx] # Initialize temporary image imgtmp[:] = 0.0 if(nhx == 0 and nhy == 0): # Conventional imaging ssf.migallw(datwt,sou,imgtmp,wverb) else: # Extended imaging ssf.migoffallw(datwt,sou,imgtmp,wverb) oimg += imgtmp # Increase number of traces ntr += self.__nrec[iexp] # Free memory for extension if(nhx != 0 or nhy != 0): ssf.del_ext() return oimg
def awemva(self,dimg,dat,dt,minf,maxf,vel,jf=1,nrmax=3,eps=0.,dtmax=5e-05,wav=None, ntx=0,nty=0,px=0,py=0,nthrds=1,sverb=True,wverb=False): """ 3D Adjoint WEMVA operator Parameters: dat - input shot profile data [ntr,nt] dt - temporal sampling of input data minf - minimum frequency to image in the data [Hz] maxf - maximum frequency to image in the data [Hz] vel - input migration velocity model [nz,ny,nx] jf - frequency decimation factor [1] nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] wav - input wavelet [None,assumes an impulse at zero lag] ntx - size of taper in x direction [0] nty - size of taper in y direction [0] px - amount of padding in x direction (samples) [0] py - amount of padding in y direction (samples) [0] nthrds - number of OpenMP threads for frequency parallelization [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progress bar [False] Returns: a slowness perturbation (adjoint wemva applied to image perturbation) [nz,ny,nx] """ # Make sure data are same size as coordinates if(dat.shape[0] != self.__ntr): raise Exception("Data must have same number of traces passed to constructor") # Get temporal axis nt = dat.shape[-1] # Create frequency domain source if(wav is None): wav = np.zeros(nt,dtype='float32') wav[0] = 1.0 self.__nwo,self.__ow,self.__dw,wfft = fft1(wav,dt,minf=minf,maxf=maxf) wfftd = wfft[::jf] self.__nwc = wfftd.shape[0] # Get the number of frequencies for imaging self.__dwc = self.__dw*jf if(sverb or wverb): print("Frequency axis: nw=%d ow=%f dw=%f"%(self.__nwc,self.__ow,self.__dwc)) # Create frequency domain data _,_,_,dfft = fft1(dat,dt,minf=minf,maxf=maxf) dfftd = dfft[:,::jf] # Allocate the data for one shot datw = np.zeros([self.__ny,self.__nx,self.__nwc],dtype='complex64') # Allocate the source for one shot sou = np.zeros([self.__nwc,self.__ny,self.__nx],dtype='complex64') # Single square root object ssf = ssr3(self.__nx ,self.__ny,self.__nz , # Spatial Sizes self.__dx ,self.__dy,self.__dz , # Spatial Samplings self.__nwc,self.__ow,self.__dwc,eps, # Frequency axis ntx,nty,px,py, # Taper and padding dtmax,nrmax,nthrds) # Reference velocities and threads # Compute slowness and reference slownesses slo = 1/vel ssf.set_slows(slo) # Allocate temporary partial image dslotmp = np.zeros([self.__nz,self.__ny,self.__nx],dtype='complex64') odslo = np.zeros([self.__nz,self.__ny,self.__nx],dtype='complex64') # Loop over sources ntr = 0 for iexp in progressbar(range(self.__nexp),"nexp:",verb=sverb): # Get the source coordinates sy = self.__srcys[iexp]; sx = self.__srcxs[iexp] isy = int((sy-self.__oy)/self.__dy+0.5); isx = int((sx-self.__ox)/self.__dx+0.5) # Create the source wavefield for this shot sou[:] = 0.0 sou[:,isy,isx] = wfftd[:] # Inject the data for this shot datw[:] = 0.0 ssf.inject_data(self.__nrec[iexp],self.__recys[ntr:],self.__recxs[ntr:],self.__oy,self.__ox,dfftd[ntr:,:],datw) datwt = np.ascontiguousarray(np.transpose(datw,(2,0,1))) # [ny,nx,nwc] -> [nwc,ny,nx] # Initialize temporary image dslotmp[:] = 0.0 # Adjoint WEMVA ssf.awemvaallw(sou,datwt,dslotmp,dimg,verb=wverb) odslo += dslotmp # Increase number of traces ntr += self.__nrec[iexp] return np.real(odslo)
def awemva(self, dimg, dat, dt, minf, maxf, vel, jf=1, nrmax=3, eps=0.0, dtmax=5e-05, wav=None, ntx=0, nty=0, px=0, py=0, nthrds=1, sverb=True, wverb=False) -> np.ndarray: """ Applies the forward WEMVA operator Parameters: dimg - the input image perturbation dat - the input data dt - temporal sampling interval minf - minimum frequency to image in the data [Hz] maxf - maximim frequency to image in the data [Hz] vel - input migration velocity model [nz,ny,nx] jf - frequency decimation factor [1] nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] wav - input wavelet [None,assumes an impulse at zero lag] ntx - size of taper in x direction [0] nty - size of taper in y direction [0] px - amount of padding in x direction (samples) [0] py - amount of padding in y direction (samples) [0] nthrds - number of OpenMP threads for parallelizing over frequency [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progress bar [False] Returns: a slowness perturbation (adjoint wemva applied to image) [nz,ny,nx] """ # Get temporal axis nt = dat.shape[-1] # Create frequency domain source if (wav is None): wav = np.zeros(nt, dtype='float32') wav[0] = 1.0 self.__nwo, self.__ow, self.__dw, wfft = self.fft1(wav, dt, minf=minf, maxf=maxf) wfftd = wfft[::jf] self.__nwc = wfftd.shape[ 0] # Get the number of frequencies for imaging self.__dwc = self.__dw * jf if (sverb or wverb): print("Frequency axis: nw=%d ow=%f dw=%f" % (self.__nwc, self.__ow, self.__dwc)) # Create frequency domain data _, _, _, dfft = self.fft1(dat, dt, minf=minf, maxf=maxf) dfftd = dfft[:, ::jf] datt = np.transpose( dfftd, (0, 1, 4, 2, 3)) # [nsy,nsx,ny,nx,nwc] -> [nsy,nsx,nwc,ny,nx] datw = np.ascontiguousarray( datt.reshape([self.__nexp, self.__nwc, self.__ny, self.__nx])) # Single square root object ssf = ssr3( self.__nx, self.__ny, self.__nz, # Spatial Sizes self.__dx, self.__dy, self.__dz, # Spatial Samplings self.__nwc, self.__ow, self.__dwc, eps, # Frequency axis ntx, nty, px, py, # Taper and padding dtmax, nrmax, nthrds) # Reference velocities # Compute slowness and reference slownesses slo = 1 / vel ssf.set_slows(slo) dsloar = np.zeros([self.__nexp, self.__nz, self.__ny, self.__nx], dtype='complex64') # Allocate the source for one shot sou = np.zeros([self.__nwc, self.__ny, self.__nx], dtype='complex64') # Loop over sources k = 0 for icrd in progressbar(self.__scoords, "nexp:", verb=sverb): # Get the source coordinates sy = icrd[0] sx = icrd[1] # Create the source for this shot sou[:] = 0.0 sou[:, sy, sx] = wfftd[:] ssf.awemvaallw(sou, datw[k], dsloar[k], dimg, verb=wverb) k += 1 # Sum over all partial images dslo = np.sum(dsloar, axis=0) return np.real(dslo)
def model_data(self,wav,dt,t0,minf,maxf,vel,ref,jf=1,nrmax=3,eps=0.,dtmax=5e-05,time=True, ntx=0,nty=0,px=0,py=0,nthrds=1,sverb=True,wverb=False): """ 3D modeling of single scattered (Born) data with the one-way wave equation (single square root (SSR), split-step Fourier method). Parameters: wav - the input wavelet (source time function) [nt] dt - sampling interval of wavelet t0 - time-zero of wavelet (e.g., peak of ricker wavelet) minf - minimum frequency to propagate [Hz] maxf - maximum frequency to propagate [Hz] vel - input velocity model [nz,ny,nx] ref - input reflectivity model [nz,ny,nx] jf - frequency decimation factor nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] time - return the data back in the time domain [True] ntx - size of taper in x direction (samples) [0] nty - size of taper in y direction (samples) [0] px - amount of padding in x direction (samples) py - amount of padding in y direction (samples) nthrds - number of OpenMP threads to use for frequency parallelization [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progress bar [False] Returns: the data at the surface (in time or frequency) [nw,nry,nrx] """ # Save wavelet temporal parameters nt = wav.shape[0]; it0 = int(t0/dt) # Create the input frequency domain source and get original frequency axis self.__nwo,self.__ow,self.__dw,wfft = fft1(wav,dt,minf=minf,maxf=maxf) wfftd = wfft[::jf] self.__nwc = wfftd.shape[0] # Get the number of frequencies to compute self.__dwc = jf*self.__dw if(sverb or wverb): print("Frequency axis: nw=%d ow=%f dw=%f"%(self.__nwc,self.__ow,self.__dwc)) # Single square root object ssf = ssr3(self.__nx ,self.__ny,self.__nz , # Spatial Sizes self.__dx ,self.__dy,self.__dz , # Spatial Samplings self.__nwc,self.__ow,self.__dwc,eps, # Frequency axis ntx,nty,px,py, # Taper and padding dtmax,nrmax,nthrds) # Reference velocities and threads # Compute slowness and reference slownesses slo = 1/vel ssf.set_slows(slo) # Allocate output data (surface wavefield) and receiver data datw = np.zeros([self.__nwc,self.__ny,self.__nx],dtype='complex64') recw = np.zeros([self.__ntr,self.__nwc],dtype='complex64') # Allocate the source for one shot sou = np.zeros([self.__nwc,self.__ny,self.__nx],dtype='complex64') # Loop over sources ntr = 0 for iexp in progressbar(range(self.__nexp),"nexp:",verb=sverb): # Get the source coordinates sy = self.__srcys[iexp]; sx = self.__srcxs[iexp] isy = int((sy-self.__oy)/self.__dy+0.5); isx = int((sx-self.__ox)/self.__dx+0.5) # Create the source for this shot sou[:] = 0.0 sou[:,isy,isx] = wfftd[:] # Downward continuation datw[:] = 0.0 ssf.modallw(ref,sou,datw,wverb) # Restrict to receiver locations datwt = np.ascontiguousarray(np.transpose(datw,(1,2,0))) # [nwc,ny,nx] -> [ny,nx,nwc] ssf.restrict_data(self.__nrec[iexp],self.__recys[ntr:],self.__recxs[ntr:],self.__oy,self.__ox,datwt,recw[ntr:,:]) # Increase number of traces ntr += self.__nrec[iexp] if(time): rect = ifft1(recw,self.__nwo,self.__ow,self.__dw,nt,it0) return rect else: return recw
def image_data(self, dat, dt, minf, maxf, vel, jf=1, nhx=0, nhy=0, sym=True, nrmax=3, eps=0.0, dtmax=5e-05, wav=None, ntx=0, nty=0, px=0, py=0, nthrds=1, sverb=True, wverb=False) -> np.ndarray: """ 3D migration of shot profile data via the one-way wave equation (single-square root split-step fourier method). Input data are assumed to follow the default geometry (sources and receivers on a regular grid) Parameters: dat - input shot profile data [nsy,nsx,nry,nrx,nt] dt - temporal sampling of input data minf - minimum frequency to image in the data [Hz] maxf - maximum frequency to image in the data [Hz] vel - input migration velocity model [nz,ny,nx] jf - frequency decimation factor nhx - number of subsurface offsets in x to compute [0] nhy - number of subsurface offsets in y to compute [0] sym - symmetrize the subsurface offsets [True] nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] wav - input wavelet [None,assumes an impulse at zero lag] ntx - size of taper in x direction [0] nty - size of taper in y direction [0] px - amount of padding in x direction (samples) [0] py - amount of padding in y direction (samples) [0] nthrds - number of OpenMP threads for parallelizing over frequency [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progress bar [False] Returns: an image created from the data [nhy,nhx,nz,ny,nx] """ # Get temporal axis nt = dat.shape[-1] # Create frequency domain source if (wav is None): wav = np.zeros(nt, dtype='float32') wav[0] = 1.0 self.__nwo, self.__ow, self.__dw, wfft = self.fft1(wav, dt, minf=minf, maxf=maxf) wfftd = wfft[::jf] self.__nwc = wfftd.shape[ 0] # Get the number of frequencies for imaging self.__dwc = self.__dw * jf if (sverb or wverb): print("Frequency axis: nw=%d ow=%f dw=%f" % (self.__nwc, self.__ow, self.__dwc)) # Create frequency domain data _, _, _, dfft = self.fft1(dat, dt, minf=minf, maxf=maxf) dfftd = dfft[:, ::jf] datt = np.transpose( dfftd, (0, 1, 4, 2, 3)) # [nsy,nsx,ny,nx,nwc] -> [nsy,nsx,nwc,ny,nx] datw = np.ascontiguousarray( datt.reshape([self.__nexp, self.__nwc, self.__ny, self.__nx])) # Single square root object ssf = ssr3( self.__nx, self.__ny, self.__nz, # Spatial Sizes self.__dx, self.__dy, self.__dz, # Spatial Samplings self.__nwc, self.__ow, self.__dwc, eps, # Frequency axis ntx, nty, px, py, # Taper and padding dtmax, nrmax, nthrds) # Reference velocities # Compute slowness and reference slownesses slo = 1 / vel ssf.set_slows(slo) # Allocate partial image array if (nhx == 0 and nhy == 0): imgar = np.zeros([self.__nexp, self.__nz, self.__ny, self.__nx], dtype='float32') else: if (sym): # Create axes self.__rnhx = 2 * nhx + 1 self.__ohx = -nhx * self.__dx self.__dhx = self.__dx self.__rnhy = 2 * nhy + 1 self.__ohy = -nhy * self.__dy self.__dhy = self.__dy # Allocate image array imgar = np.zeros([ self.__nexp, self.__rnhy, self.__rnhx, self.__nz, self.__ny, self.__nx ], dtype='float32') else: # Create axes self.__rnhx = nhx + 1 self.__ohx = 0 self.__dhx = self.__dx self.__rnhy = nhy + 1 self.__ohy = 0 self.__dhy = self.__dy # Allocate image array imgar = np.zeros([ self.__nexp, self.__rnhy, self.__rnhx, self.__nz, self.__ny, self.__nx ], dtype='float32') # Allocate memory necessary for extension ssf.set_ext(nhy, nhx, sym) # Allocate the source for one shot sou = np.zeros([self.__nwc, self.__ny, self.__nx], dtype='complex64') # Loop over sources k = 0 for icrd in progressbar(self.__scoords, "nexp:", verb=sverb): # Get the source coordinates sy = icrd[0] sx = icrd[1] # Create the source for this shot sou[:] = 0.0 sou[:, sy, sx] = wfftd[:] if (nhx == 0 and nhy == 0): # Conventional imaging ssf.migallw(datw[k], sou, imgar[k], wverb) else: # Extended imaging ssf.migoffallw(datw[k], sou, imgar[k], wverb) k += 1 # Sum over all partial images img = np.sum(imgar, axis=0) # Free memory for extension if (nhx != 0 or nhy != 0): ssf.del_ext() return img
def model_data(self, wav, dt, t0, minf, maxf, vel, ref, jf=1, nrmax=3, eps=0., dtmax=5e-05, time=True, ntx=0, nty=0, px=0, py=0, nthrds=1, sverb=True, wverb=False) -> np.ndarray: """ 3D modeling of single scattered (Born) data with the one-way wave equation (single square root (SSR), split-step Fourier method). Parameters: wav - the input wavelet (source time function) [nt] dt - sampling interval of wavelet t0 - time-zero of wavelet (e.g., peak of ricker wavelet) minf - minimum frequency to propagate [Hz] maxf - maximum frequency to propagate [Hz] vel - input velocity model [nz,ny,nx] ref - input reflectivity model [nz,ny,nx] jf - frequency decimation factor [1] nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] time - return the data back in the time domain [True] ntx - size of taper in x direction (samples) [0] nty - size of taper in y direction (samples) [0] px - amount of padding in x direction (samples) py - amount of padding in y direction (samples) nthrds - number of OpenMP threads for parallelizing over frequency [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progressbar [False] Returns the data at the surface (in time or frequency) [nw,nry,nrx] """ # Save wavelet temporal parameters nt = wav.shape[0] it0 = int(t0 / dt) # Create the input frequency domain source and get original frequency axis self.__nwo, self.__ow, self.__dw, wfft = self.fft1(wav, dt, minf=minf, maxf=maxf) wfftd = wfft[::jf] self.__nwc = wfftd.shape[0] # Get the number of frequencies to compute self.__dwc = jf * self.__dw if (sverb or wverb): print("Frequency axis: nw=%d ow=%f dw=%f" % (self.__nwc, self.__ow, self.__dwc)) # Single square root object ssf = ssr3( self.__nx, self.__ny, self.__nz, # Spatial Sizes self.__dx, self.__dy, self.__dz, # Spatial Samplings self.__nwc, self.__ow, self.__dwc, eps, # Frequency axis ntx, nty, px, py, # Taper and padding dtmax, nrmax, nthrds) # Reference velocities # Compute slowness and reference slownesses slo = 1 / vel ssf.set_slows(slo) # Allocate output data (surface wavefield) datw = np.zeros([self.__nexp, self.__nwc, self.__ny, self.__nx], dtype='complex64') # Allocate the source for one shot sou = np.zeros([self.__nwc, self.__ny, self.__nx], dtype='complex64') # Loop over sources k = 0 for icrd in progressbar(self.__scoords, "nexp:", verb=sverb): # Get the source coordinates sy = icrd[0] sx = icrd[1] # Create the source for this shot sou[:] = 0.0 sou[:, sy, sx] = wfftd[:] # Downward continuation ssf.modallw(ref, sou, datw[k], wverb) k += 1 # Reshape output data datwr = datw.reshape( [self.__nsy, self.__nsx, self.__nwc, self.__ny, self.__nx]) if (time): # Inverse fourier transform datt = self.data_f2t(datwr, self.__nwo, self.__ow, self.__dwc, nt, it0) return datt else: return datwr
def image_data(self, rec, owc, dwc, vel, nhx=0, nhy=0, sym=True, eps=0, nrmax=3, dtmax=5e-05, wav=None, ntx=0, nty=0, px=0, py=0, nthrds=1, sverb=True, wverb=False): """ 3D migration of shot profile data via the one-way wave equation (single-square root split-step fourier method). Input data are assumed to follow the default geometry (sources and receivers on a regular grid) Parameters: rec - flattened input shot profile data vel - input migration velocity model [nz,ny,nx] jf - frequency decimation factor nhx - number of subsurface offsets in x to compute [0] nhy - number of subsurface offsets in y to compute [0] sym - symmetrize the subsurface offsets [True] nrmax - maximum number of reference velocities [3] dtmax - maximum time error [5e-05] wav - input wavelet [None,assumes an impulse at zero lag] ntx - size of taper in x direction [0] nty - size of taper in y direction [0] px - amount of padding in x direction (samples) [0] py - amount of padding in y direction (samples) [0] nthrds - number of OpenMP threads for parallelizing over frequency [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progress bar [False] nchnks - number of chunks to distribute over cluster client - dask client for distributing work over a cluster Returns: an image created from the data [nhy,nhx,nz,ny,nx] """ # Make sure data are same size as coordinates if (rec.shape[0] != self.__ntr): raise Exception( "Data must have same number of traces passed to constructor") nwc = wav.shape[0] if (rec.shape[-1] != nwc): raise Exception("Data and wavelet must have same frequency axis") # Allocate source and data for one shot datw = np.zeros([self.__ny, self.__nx, nwc], dtype='complex64') sou = np.zeros([nwc, self.__ny, self.__nx], dtype='complex64') # Single square root object ssf = ssr3( self.__nx, self.__ny, self.__nz, # Spatial Sizes self.__dx, self.__dy, self.__dz, # Spatial Samplings nwc, owc, dwc, eps, # Frequency axis ntx, nty, px, py, # Taper and padding dtmax, nrmax, nthrds) # Reference velocities and threads # Compute slowness and reference slownesses slo = 1 / vel ssf.set_slows(slo) # Allocate partial image array if (nhx == 0 and nhy == 0): imgtmp = np.zeros([self.__nz, self.__ny, self.__nx], dtype='float32') oimg = np.zeros([self.__nz, self.__ny, self.__nx], dtype='float32') else: if (sym): # Create axes self.__rnhx = 2 * nhx + 1 self.__ohx = -nhx * self.__dx self.__dhx = self.__dx self.__rnhy = 2 * nhy + 1 self.__ohy = -nhy * self.__dy self.__dhy = self.__dy imgtmp = np.zeros([ self.__rnhy, self.__rnhx, self.__nz, self.__ny, self.__nx ], dtype='float32') oimg = np.zeros([ self.__rnhy, self.__rnhx, self.__nz, self.__ny, self.__nx ], dtype='float32') else: # Create axes self.__rnhx = nhx + 1 self.__ohx = 0 self.__dhx = self.__dx self.__rnhy = nhy + 1 self.__ohy = 0 self.__dhy = self.__dy imgtmp = np.zeros([ self.__rnhy, self.__rnhx, self.__nz, self.__ny, self.__nx ], dtype='float32') oimg = np.zeros([ self.__rnhy, self.__rnhx, self.__nz, self.__ny, self.__nx ], dtype='float32') # Allocate memory necessary for extension ssf.set_ext(nhy, nhx, sym, True) #ssf.set_ext(nhy,nhx,sym,False) # Loop over sources ntr = 0 for iexp in progressbar(range(self.__nexp), "nexp:", verb=sverb): # Get the source coordinates sy = self.__srcy[iexp] sx = self.__srcx[iexp] isy = int((sy - self.__oy) / self.__dy + 0.5) isx = int((sx - self.__ox) / self.__dx + 0.5) # Create the source wavefield for this shot sou[:] = 0.0 sou[:, isy, isx] = wav[:] # Inject the data for this shot datw[:] = 0.0 ssf.inject_data(self.__nrec[iexp], self.__recy[ntr:], self.__recx[ntr:], self.__oy, self.__ox, rec[ntr:, :], datw) datwt = np.ascontiguousarray(np.transpose( datw, (2, 0, 1))) # [ny,nx,nwc] -> [nwc,ny,nx] # Initialize temporary image imgtmp[:] = 0.0 if (nhx == 0 and nhy == 0): # Conventional imaging ssf.migallw(datwt, sou, imgtmp, wverb) else: # Extended imaging ssf.migoffallw(datwt, sou, imgtmp, wverb) #ssf.migoffallwbig(datwt,sou,imgtmp,wverb) oimg += imgtmp # Increase number of traces ntr += self.__nrec[iexp] # Free memory for extension if (nhx != 0 or nhy != 0): ssf.del_ext() return oimg
def model_data(self, wav, t0, owc, dwc, vel, ref, nrmax=3, eps=0., dtmax=5e-05, ntx=0, nty=0, px=0, py=0, nthrds=1, sverb=True, wverb=True): """ 3D modeling of single scattered (Born) data with the one-way wave equation (single square root (SSR), split-step Fourier method). Parameters: wav - the input wavelet (source time function) [nt] t0 - time zero of input wavelet owc - minimum frequency of wavelet dwc - frequency sampling of wavelet vel - input velocity model [nz,ny,nx] ref - input reflectivity model [nz,ny,nx] nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] ntx - size of taper in x direction (samples) [0] nty - size of taper in y direction (samples) [0] px - amount of padding in x direction (samples) py - amount of padding in y direction (samples) nthrds - number of OpenMP threads to use for frequency parallelization [1] sverb - verbosity flag for shot progress bar [True] wverb - verbosity flag for frequency progress bar [False] Returns: the data at the surface [nw,nry,nrx] """ # Get dimensions nwc = wav.shape[0] # Single square root object ssf = ssr3( self.__nx, self.__ny, self.__nz, # Spatial Sizes self.__dx, self.__dy, self.__dz, # Spatial Samplings nwc, owc, dwc, eps, # Frequency axis ntx, nty, px, py, # Taper and padding dtmax, nrmax, nthrds) # Reference velocities and threads # Compute slowness and reference slownesses slo = 1 / vel ssf.set_slows(slo) # Allocate output data (surface wavefield) and receiver data datw = np.zeros([nwc, self.__ny, self.__nx], dtype='complex64') recw = np.zeros([self.__ntr, nwc], dtype='complex64') # Allocate the source for one shot sou = np.zeros([nwc, self.__ny, self.__nx], dtype='complex64') # Loop over sources ntr = 0 for iexp in progressbar(range(self.__nexp), "nexp:", verb=sverb): # Get the source coordinates sy = self.__srcy[iexp] sx = self.__srcx[iexp] isy = int((sy - self.__oy) / self.__dy + 0.5) isx = int((sx - self.__ox) / self.__dx + 0.5) # Create the source for this shot sou[:] = 0.0 sou[:, isy, isx] = wav[:] # Downward continuation datw[:] = 0.0 ssf.modallw(ref, sou, datw, wverb) # Restrict to receiver locations datwt = np.ascontiguousarray(np.transpose( datw, (1, 2, 0))) # [nwc,ny,nx] -> [ny,nx,nwc] ssf.restrict_data(self.__nrec[iexp], self.__recy[ntr:], self.__recx[ntr:], self.__oy, self.__ox, datwt, recw[ntr:, :]) # Increase number of traces ntr += self.__nrec[iexp] # Apply phase shift to data to account for t0 recs = phzshft(recw, owc, dwc, t0) return recs
def image_data(self, dat, dt, minf, maxf, vel, jf=1, nrmax=3, eps=0., dtmax=5e-05, ntx=0, nty=0, px=0, py=0, nthrds=1, wverb=True): """ 3D migration of zero-offset data via the one-way wave equation (single-square root split-step fourier method) Parameters: dat - input shot profile data [ny,nx,nt] dt - temporal sampling of input data minf - minimum frequency to image in the data [Hz] maxf - maximum frequency to image in the data [Hz] vel - input migration velocity model [nz,ny,nx] jf - frequency decimation factor nrmax - maximum number of reference velocities [3] eps - stability parameter [0.] dtmax - maximum time error [5e-05] ntx - size of taper in x direction [0] nty - size of taper in y direction [0] px - amount of padding in x direction (samples) [0] py - amount of padding in y direction (samples) [0] nthrds - number of OpenMP threads for parallelizing over frequency [1] wverb - verbosity flag for frequency progress bar [True] Returns: an image created from the data [nz,ny,nx] """ # Get temporal axis nt = dat.shape[-1] # Create frequency domain source wav = np.zeros(nt, dtype='float32') wav[0] = 1.0 self.__nwo, self.__ow, self.__dw, wfft = self.fft1(wav, dt, minf=minf, maxf=maxf) wfftd = wfft[::jf] self.__nwc = wfftd.shape[ 0] # Get the number of frequencies for imaging self.__dwc = self.__dw * jf if (wverb): print("Frequency axis: nw=%d ow=%f dw=%f" % (self.__nwc, self.__ow, self.__dwc)) # Create frequency domain data _, _, _, dfft = self.fft1(dat, dt, minf=minf, maxf=maxf) dfftd = dfft[:, ::jf] datt = np.transpose(dfftd, (2, 0, 1)) # [ny,nx,nwc] -> [nwc,ny,nx] datw = np.ascontiguousarray( datt.reshape([self.__nwc, self.__ny, self.__nx])) # Single square root object ssf = ssr3( self.__nx, self.__ny, self.__nz, # Spatial Sizes self.__dx, self.__dy, self.__dz, # Spatial Samplings self.__nwc, self.__ow, self.__dwc, eps, # Frequency axis ntx, nty, px, py, # Taper and padding dtmax, nrmax, nthrds) # Reference velocities # Output image img = np.zeros([self.__nz, self.__ny, self.__nx], dtype='float32') # Compute slowness and reference slownesses slo = 2 / vel # Two-way travel time ssf.set_slows(slo) # Image for all frequencies ssf.migallwzo(datw, img, wverb) return img