Beispiel #1
0
  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
Beispiel #2
0
  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)
Beispiel #3
0
    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)
Beispiel #4
0
  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
Beispiel #5
0
    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
Beispiel #6
0
    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
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #9
0
    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