Exemplo n.º 1
0
def BornOperator(model, geometry, space_order=4, kernel='sls', time_order=2, **kwargs):
    """
    Construct an Linearized Born operator in an acoustic media.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    kernel : str, optional
        Type of discretization, centered or shifted.
    """
    # Create wavefields and a dm field
    p = TimeFunction(name='p', grid=model.grid, time_order=time_order,
                     space_order=space_order, staggered=NODE)
    P = TimeFunction(name='P', grid=model.grid, time_order=time_order,
                     space_order=space_order, staggered=NODE)
    rp = TimeFunction(name="rp", grid=model.grid, time_order=time_order,
                      space_order=space_order, staggered=NODE)
    rP = TimeFunction(name="rP", grid=model.grid, time_order=time_order,
                      space_order=space_order, staggered=NODE)
    dm = Function(name='dm', grid=model.grid, space_order=0)

    if time_order == 1:
        v = VectorTimeFunction(name="v", grid=model.grid,
                               time_order=time_order, space_order=space_order)
        kwargs.update({'v': v})

    # Equations kernels
    eq_kernel = kernels[kernel]
    eqn1 = eq_kernel(model, geometry, p, r=rp, **kwargs)

    s = model.grid.stepping_dim.spacing

    if time_order == 1:
        dv = VectorTimeFunction(name="dv", grid=model.grid,
                                time_order=time_order, space_order=space_order)
        kwargs.update({'v': dv})

        q = -dm * (p.forward - p) / s
    else:
        q = -dm * (p.forward - 2 * p + p.backward) / (s**2)

    eqn2 = eq_kernel(model, geometry, P, r=rP, q=q, **kwargs)

    # Add source term expression for p
    src_term, _ = src_rec(p, model, geometry)

    # Create receiver interpolation expression from P
    _, rec_term = src_rec(P, model, geometry)

    # Substitute spacing terms to reduce flops
    return Operator(eqn1 + src_term + rec_term + eqn2, subs=model.spacing_map,
                    name='Born', **kwargs)
Exemplo n.º 2
0
def ForwardOperator(model,
                    geometry,
                    space_order=4,
                    kernel='sls',
                    time_order=2,
                    save=False,
                    **kwargs):
    """
    Construct method for the forward modelling operator in a viscoacoustic medium.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    kernel : string, optional
        selects a viscoacoustic equation from the options below:
        sls (Standard Linear Solid) :
        1st order - Blanch and Symes (1995) / Dutta and Schuster (2014)
        viscoacoustic equation
        2nd order - Bai et al. (2014) viscoacoustic equation
        ren - Ren et al. (2014) viscoacoustic equation
        deng_mcmechan - Deng and McMechan (2007) viscoacoustic equation
        Defaults to sls 2nd order.
    save : int or Buffer
        Saving flag, True saves all time steps, False saves three buffered
        indices (last three time steps). Defaults to False.
    """
    # Create symbols for forward wavefield, particle velocity, source and receivers

    if time_order == 1:
        v = VectorTimeFunction(name="v",
                               grid=model.grid,
                               save=geometry.nt if save else None,
                               time_order=time_order,
                               space_order=space_order)
        kwargs.update({'v': v})

    p = TimeFunction(name="p",
                     grid=model.grid,
                     staggered=NODE,
                     save=geometry.nt if save else None,
                     time_order=time_order,
                     space_order=space_order)

    # Equations kernels
    eq_kernel = kernels[kernel]
    eqn = eq_kernel(model, geometry, p, save=save, **kwargs)

    srcrec = src_rec(p, model, geometry)

    # Substitute spacing terms to reduce flops
    return Operator(eqn + srcrec,
                    subs=model.spacing_map,
                    name='Forward',
                    **kwargs)
Exemplo n.º 3
0
def test_staggered_div():
    """
    Test that div works properly on expressions.
    From @speglish issue #1248
    """
    grid = Grid(shape=(5, 5))

    v = VectorTimeFunction(name="v", grid=grid, time_order=1, space_order=4)
    p1 = TimeFunction(name="p1", grid=grid, time_order=1, space_order=4, staggered=NODE)
    p2 = TimeFunction(name="p2", grid=grid, time_order=1, space_order=4, staggered=NODE)

    # Test that 1.*v and 1*v are doing the same

    v[0].data[:] = 1.
    v[1].data[:] = 1.

    eq1 = Eq(p1, div(1*v))
    eq2 = Eq(p2, div(1.*v))

    op1 = Operator([eq1])
    op2 = Operator([eq2])

    op1.apply(time_M=0)
    op2.apply(time_M=0)
    assert np.allclose(p1.data[:], p2.data[:], atol=0, rtol=1e-5)

    # Test div on expression
    v[0].data[:] = 5.
    v[1].data[:] = 5.

    A = Function(name="A", grid=grid, space_order=4, staggred=NODE, parameter=True)
    A._data_with_outhalo[:] = .5

    av = VectorTimeFunction(name="av", grid=grid, time_order=1, space_order=4)

    # Operator with A (precomputed A*v)
    eq1 = Eq(av, A*v)
    eq2 = Eq(p1, div(av))
    op = Operator([eq1, eq2])
    op.apply(time_M=0)

    # Operator with div(A*v) directly
    eq3 = Eq(p2, div(A*v))
    op2 = Operator([eq3])
    op2.apply(time_M=0)

    assert np.allclose(p1.data[:], p2.data[:], atol=0, rtol=1e-5)
Exemplo n.º 4
0
    def forward(self, src=None, rec1=None, rec2=None, lam=None, mu=None, b=None,
                v=None, tau=None, save=None, **kwargs):
        """
        Forward modelling function that creates the necessary
        data objects for running a forward modelling operator.

        Parameters
        ----------
        src : SparseTimeFunction or array_like, optional
            Time series data for the injected source term.
        rec1 : SparseTimeFunction or array_like, optional
            The interpolated receiver data of the pressure (tzz).
        rec2 : SparseTimeFunction or array_like, optional
            The interpolated receiver data of the particle velocities.
        v : VectorTimeFunction, optional
            The computed particle velocity.
        tau : TensorTimeFunction, optional
            The computed symmetric stress tensor.
        lam : Function, optional
            The time-constant first Lame parameter `rho * (vp**2 - 2 * vs **2)`.
        mu : Function, optional
            The Shear modulus `(rho * vs*2)`.
        b : Function, optional
            The time-constant inverse density (b=1 for water).
        save : int or Buffer, optional
            Option to store the entire (unrolled) wavefield.

        Returns
        -------
        Rec1(tzz), Rec2(div(v)), particle velocities v, stress tensor tau and
        performance summary.
        """
        # Source term is read-only, so re-use the default
        src = src or self.geometry.src
        # Create a new receiver object to store the result
        rec1 = rec1 or Receiver(name='rec1', grid=self.model.grid,
                                time_range=self.geometry.time_axis,
                                coordinates=self.geometry.rec_positions)
        rec2 = rec2 or Receiver(name='rec2', grid=self.model.grid,
                                time_range=self.geometry.time_axis,
                                coordinates=self.geometry.rec_positions)

        # Create all the fields vx, vz, tau_xx, tau_zz, tau_xz
        save_t = src.nt if save else None
        v = VectorTimeFunction(name='v', grid=self.model.grid, save=save_t,
                               space_order=self.space_order, time_order=1)
        tau = TensorTimeFunction(name='tau', grid=self.model.grid, save=save_t,
                                 space_order=self.space_order, time_order=1)
        kwargs.update({k.name: k for k in v})
        kwargs.update({k.name: k for k in tau})
        # Pick Lame parameters from model unless explicitly provided
        kwargs.update(self.model.physical_params(lam=lam, mu=mu, b=b))
        # Execute operator and return wavefield and receiver data
        summary = self.op_fwd(save).apply(src=src, rec1=rec1, rec2=rec2,
                                          dt=kwargs.pop('dt', self.dt), **kwargs)
        return rec1, rec2, v, tau, summary
Exemplo n.º 5
0
def GradientOperator(model, geometry, space_order=4, kernel='sls', time_order=2,
                     save=True, **kwargs):
    """
    Construct a gradient operator in an acoustic media.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    save : int or Buffer, optional
        Option to store the entire (unrolled) wavefield.
    kernel : selects a visco-acoustic equation from the options below:
        sls (Standard Linear Solid) :
        1st order - Blanch and Symes (1995) / Dutta and Schuster (2014)
        viscoacoustic equation
        2nd order - Bai et al. (2014) viscoacoustic equation
        ren - Ren et al. (2014) viscoacoustic equation
        deng_mcmechan - Deng and McMechan (2007) viscoacoustic equation
        Defaults to sls 2nd order.
    """
    # Gradient symbol and wavefield symbols
    save_t = geometry.nt if save else None

    grad = Function(name='grad', grid=model.grid)
    p = TimeFunction(name='p', grid=model.grid, time_order=time_order,
                     space_order=space_order, save=save_t, staggered=NODE)
    pa = TimeFunction(name='pa', grid=model.grid, time_order=time_order,
                      space_order=space_order, staggered=NODE)

    if time_order == 1:
        va = VectorTimeFunction(name="va", grid=model.grid, time_order=time_order,
                                space_order=space_order)
        kwargs.update({'v': va})

    # Equations kernels
    eq_kernel = kernels[kernel]
    eqn = eq_kernel(model, geometry, pa, forward=False, save=False, **kwargs)

    if time_order == 1:
        gradient_update = Eq(grad, grad - p.dt * pa)
    else:
        gradient_update = Eq(grad, grad + p.dt * pa.dt)

    # Add expression for receiver injection
    _, recterm = src_rec(pa, model, geometry, forward=False)

    # Substitute spacing terms to reduce flops
    return Operator(eqn + recterm + [gradient_update], subs=model.spacing_map,
                    name='Gradient', **kwargs)
Exemplo n.º 6
0
def AdjointOperator(model,
                    geometry,
                    space_order=4,
                    kernel='sls',
                    time_order=2,
                    **kwargs):
    """
    Construct an adjoint modelling operator in a viscoacoustic medium.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    kernel : selects a visco-acoustic equation from the options below:
        sls (Standard Linear Solid) :
        1st order - Blanch and Symes (1995) / Dutta and Schuster (2014)
        viscoacoustic equation
        2nd order - Bai et al. (2014) viscoacoustic equation
        ren - Ren et al. (2014) viscoacoustic equation
        deng_mcmechan - Deng and McMechan (2007) viscoacoustic equation
        Defaults to sls 2nd order.
    """
    if time_order == 1:
        va = VectorTimeFunction(name="va",
                                grid=model.grid,
                                save=None,
                                time_order=time_order,
                                space_order=space_order)
        kwargs.update({'v': va})

    pa = TimeFunction(name="pa",
                      grid=model.grid,
                      save=None,
                      time_order=time_order,
                      space_order=space_order,
                      staggered=NODE)

    # Equations kernels
    eq_kernel = kernels[kernel]
    eqn = eq_kernel(model, geometry, pa, forward=False, **kwargs)

    srcrec = src_rec(pa, model, geometry, forward=False)

    # Substitute spacing terms to reduce flops
    return Operator(eqn + srcrec,
                    subs=model.spacing_map,
                    name='Adjoint',
                    **kwargs)
Exemplo n.º 7
0
def ForwardOperator(model, geometry, space_order=4, save=False, **kwargs):
    """
    Construct method for the forward modelling operator in an elastic media.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    save : int or Buffer
        Saving flag, True saves all time steps, False saves three buffered
        indices (last three time steps). Defaults to False.
    """

    v = VectorTimeFunction(name='v',
                           grid=model.grid,
                           save=geometry.nt if save else None,
                           space_order=space_order,
                           time_order=1)
    tau = TensorTimeFunction(name='tau',
                             grid=model.grid,
                             save=geometry.nt if save else None,
                             space_order=space_order,
                             time_order=1)

    lam, mu, b = model.lam, model.mu, model.b

    dt = model.critical_dt
    u_v = Eq(v.forward, model.damp * v + model.damp * dt * b * div(tau))
    u_t = Eq(
        tau.forward,
        model.damp * tau + model.damp * dt * lam * diag(div(v.forward)) +
        model.damp * dt * mu * (grad(v.forward) + grad(v.forward).T))

    srcrec = src_rec(v, tau, model, geometry)
    op = Operator([u_v] + [u_t] + srcrec,
                  subs=model.spacing_map,
                  name="ForwardElastic",
                  **kwargs)
    # Substitute spacing terms to reduce flops
    return op
Exemplo n.º 8
0
    def forward(self, src=None, rec=None, v=None,tau=None, vp=None, save=None, **kwargs):
        """
        Forward modelling function that creates the necessary
        data objects for running a forward modelling operator.

        Parameters
        ----------
        src : SparseTimeFunction or array_like, optional
            Time series data for the injected source term.
        rec : SparseTimeFunction or array_like, optional
            The interpolated receiver data.
        v : VectorTimeFunction, optional
            The computed particle velocity.
        tau : TensorTimeFunction, optional
            The computed symmetric stress tensor.
        vp : Function or float, optional
            The time-constant velocity.
        save : int or Buffer, optional
            Option to store the entire (unrolled) wavefield.

        Returns
        -------
        Receiver, wavefield and performance summary
        """
        # Source term is read-only, so re-use the default
        src = src or self.geometry.src
        # Create a new receiver object to store the result
        rec = rec or self.geometry.rec

        # Create Create Forward wavefield

        v = v or VectorTimeFunction(name='v', grid=self.model.grid, save=self.geometry.nt,
                               space_order=self.space_order, time_order=1)
        tau = tau or TensorTimeFunction(name='tau', grid=self.model.grid, save=self.geometry.nt,
                                 space_order=self.space_order, time_order=1)
        # Pick vp from model unless explicitly provided
        vp = vp or self.model.vp

        # Execute operator and return wavefield and receiver data
        summary = self.op_fwd(save).apply(src=src, rec=rec, v=v, tau=tau, vp=vp,
                                          dt=kwargs.pop('dt', self.dt), **kwargs)
        return rec, v, tau, summary
Exemplo n.º 9
0
    def forward(self, src=None, rec=None, v=None, r=None, p=None, model=None,
                save=None, **kwargs):
        """
        Forward modelling function that creates the necessary
        data objects for running a forward modelling operator.

        Parameters
        ----------
        src : SparseTimeFunction or array_like, optional
            Time series data for the injected source term.
        rec : SparseTimeFunction or array_like, optional
            The interpolated receiver data.
        v : VectorTimeFunction, optional
            The computed particle velocity.
        r : TimeFunction, optional
            The computed attenuation memory variable.
        p : TimeFunction, optional
            Stores the computed wavefield.
        model : Model, optional
            Object containing the physical parameters.
        qp : Function, optional
            The P-wave quality factor.
        b : Function, optional
            The time-constant inverse density.
        vp : Function or float, optional
            The time-constant velocity.
        save : bool, optional
            Whether or not to save the entire (unrolled) wavefield.

        Returns
        -------
        Receiver, wavefield and performance summary
        """
        # Source term is read-only, so re-use the default
        src = src or self.geometry.src

        # Create a new receiver object to store the result
        rec = rec or self.geometry.rec

        # Create all the fields v, p, r
        save_t = src.nt if save else None

        if self.time_order == 1:
            v = v or VectorTimeFunction(name="v", grid=self.model.grid, save=save_t,
                                        time_order=self.time_order,
                                        space_order=self.space_order)
            kwargs.update({k.name: k for k in v})

        # Create the forward wavefield if not provided
        p = p or TimeFunction(name="p", grid=self.model.grid, save=save_t,
                              time_order=self.time_order, space_order=self.space_order,
                              staggered=NODE)

        # Memory variable:
        r = r or TimeFunction(name="r", grid=self.model.grid, save=save_t,
                              time_order=self.time_order, space_order=self.space_order,
                              staggered=NODE)

        model = model or self.model
        # Pick vp and physical parameters from model unless explicitly provided
        kwargs.update(model.physical_params(**kwargs))

        if self.kernel == 'sls':
            # Execute operator and return wavefield and receiver data
            # With Memory variable
            summary = self.op_fwd(save).apply(src=src, rec=rec, r=r, p=p,
                                              dt=kwargs.pop('dt', self.dt), **kwargs)
        else:
            # Execute operator and return wavefield and receiver data
            # Without Memory variable
            summary = self.op_fwd(save).apply(src=src, rec=rec, p=p,
                                              dt=kwargs.pop('dt', self.dt), **kwargs)
        return rec, p, v, summary
Exemplo n.º 10
0
    def adjoint(self, rec, srca=None, va=None, pa=None, r=None, model=None, **kwargs):
        """
        Adjoint modelling function that creates the necessary
        data objects for running an adjoint modelling operator.

        Parameters
        ----------
        rec : SparseTimeFunction or array-like
            The receiver data. Please note that
            these act as the source term in the adjoint run.
        srca : SparseTimeFunction or array-like
            The resulting data for the interpolated at the
            original source location.
        va : VectorTimeFunction, optional
            The computed particle velocity.
        pa : TimeFunction, optional
            Stores the computed wavefield.
        r : TimeFunction, optional
            The computed attenuation memory variable.
        model : Model, optional
            Object containing the physical parameters.
        vp : Function or float, optional
            The time-constant velocity.
        qp : Function, optional
            The P-wave quality factor.
        b : Function, optional
            The time-constant inverse density.

        Returns
        -------
        Adjoint source, wavefield and performance summary.
        """
        # Create a new adjoint source and receiver symbol
        srca = srca or PointSource(name='srca', grid=self.model.grid,
                                   time_range=self.geometry.time_axis,
                                   coordinates=self.geometry.src_positions)

        if self.time_order == 1:
            va = va or VectorTimeFunction(name="va", grid=self.model.grid,
                                          time_order=self.time_order,
                                          space_order=self.space_order)
            kwargs.update({k.name: k for k in va})
            kwargs['time_m'] = 0

        pa = pa or TimeFunction(name="pa", grid=self.model.grid,
                                time_order=self.time_order, space_order=self.space_order,
                                staggered=NODE)

        # Memory variable:
        r = r or TimeFunction(name="r", grid=self.model.grid, time_order=self.time_order,
                              space_order=self.space_order, staggered=NODE)

        model = model or self.model
        # Pick vp and physical parameters from model unless explicitly provided
        kwargs.update(model.physical_params(**kwargs))

        # Execute operator and return wavefield and receiver data
        if self.kernel == 'sls':
            # Execute operator and return wavefield and receiver data
            # With Memory variable
            summary = self.op_adj().apply(src=srca, rec=rec, pa=pa, r=r,
                                          dt=kwargs.pop('dt', self.dt), **kwargs)
        else:
            summary = self.op_adj().apply(src=srca, rec=rec, pa=pa,
                                          dt=kwargs.pop('dt', self.dt), **kwargs)
        return srca, pa, va, summary
Exemplo n.º 11
0
    def jacobian_adjoint(self,
                         rec,
                         p,
                         pa=None,
                         grad=None,
                         r=None,
                         va=None,
                         model=None,
                         checkpointing=False,
                         **kwargs):
        """
        Gradient modelling function for computing the adjoint of the
        Linearized Born modelling function, ie. the action of the
        Jacobian adjoint on an input data.

        Parameters
        ----------
        rec : SparseTimeFunction
            Receiver data.
        p : TimeFunction
            Full wavefield `p` (created with save=True).
        pa : TimeFunction, optional
            Stores the computed wavefield.
        grad : Function, optional
            Stores the gradient field.
        r : TimeFunction, optional
            The computed attenuation memory variable.
        va : VectorTimeFunction, optional
            The computed particle velocity.
        model : Model, optional
            Object containing the physical parameters.
        vp : Function or float, optional
            The time-constant velocity.
        qp : Function, optional
            The P-wave quality factor.
        b : Function, optional
            The time-constant inverse density.

        Returns
        -------
        Gradient field and performance summary.
        """
        dt = kwargs.pop('dt', self.dt)
        # Gradient symbol
        grad = grad or Function(name='grad', grid=self.model.grid)

        # Create the forward wavefield
        pa = pa or TimeFunction(name='pa',
                                grid=self.model.grid,
                                time_order=self.time_order,
                                space_order=self.space_order,
                                staggered=NODE)

        model = model or self.model
        # Pick vp and physical parameters from model unless explicitly provided
        kwargs.update(model.physical_params(**kwargs))

        if checkpointing:
            if self.time_order == 1:
                v = VectorTimeFunction(name="v",
                                       grid=self.model.grid,
                                       time_order=self.time_order,
                                       space_order=self.space_order)
                kwargs.update({k.name: k for k in v})

            p = TimeFunction(name='p',
                             grid=self.model.grid,
                             time_order=self.time_order,
                             space_order=self.space_order,
                             staggered=NODE)

            r = TimeFunction(name="r",
                             grid=self.model.grid,
                             time_order=self.time_order,
                             space_order=self.space_order,
                             staggered=NODE)

            l = [p, r] + v.values() if self.time_order == 1 else [p, r]
            cp = DevitoCheckpoint(l)
            n_checkpoints = None
            wrap_fw = CheckpointOperator(self.op_fwd(save=False),
                                         src=self.geometry.src,
                                         p=p,
                                         r=r,
                                         dt=dt,
                                         **kwargs)

            ra = TimeFunction(name="ra",
                              grid=self.model.grid,
                              time_order=self.time_order,
                              space_order=self.space_order,
                              staggered=NODE)

            if self.time_order == 1:
                for i in {k.name: k for k in v}.keys():
                    kwargs.pop(i)
                va = VectorTimeFunction(name="va",
                                        grid=self.model.grid,
                                        time_order=self.time_order,
                                        space_order=self.space_order)
                kwargs.update({k.name: k for k in va})
                kwargs['time_m'] = 0

            wrap_rev = CheckpointOperator(self.op_grad(save=False),
                                          p=p,
                                          pa=pa,
                                          r=ra,
                                          rec=rec,
                                          dt=dt,
                                          grad=grad,
                                          **kwargs)

            # Run forward
            wrp = Revolver(
                cp, wrap_fw, wrap_rev, n_checkpoints,
                rec.data.shape[0] - (1 if self.time_order == 1 else 2))
            wrp.apply_forward()
            summary = wrp.apply_reverse()
        else:
            if self.time_order == 1:
                va = va or VectorTimeFunction(name="va",
                                              grid=self.model.grid,
                                              time_order=self.time_order,
                                              space_order=self.space_order)
                kwargs.update({k.name: k for k in va})
                kwargs['time_m'] = 0

            # Memory variable:
            r = r or TimeFunction(name="r",
                                  grid=self.model.grid,
                                  time_order=self.time_order,
                                  space_order=self.space_order,
                                  staggered=NODE)

            summary = self.op_grad().apply(rec=rec,
                                           grad=grad,
                                           pa=pa,
                                           p=p,
                                           r=r,
                                           dt=dt,
                                           **kwargs)

        return grad, summary
Exemplo n.º 12
0
    def jacobian(self,
                 dmin,
                 src=None,
                 rec=None,
                 p=None,
                 P=None,
                 rp=None,
                 rP=None,
                 v=None,
                 dv=None,
                 model=None,
                 **kwargs):
        """
        Linearized Born modelling function that creates the necessary
        data objects for running an adjoint modelling operator.

        Parameters
        ----------
        src : SparseTimeFunction or array_like, optional
            Time series data for the injected source term.
        rec : SparseTimeFunction or array_like, optional
            The interpolated receiver data.
        p : TimeFunction, optional
            The forward wavefield.
        P : TimeFunction, optional
            The linearized wavefield.
        rp : TimeFunction, optional
            The computed attenuation memory variable.
        rP : TimeFunction, optional
            The computed attenuation memory variable.
        v : VectorTimeFunction, optional
            The computed particle velocity.
        dv : VectorTimeFunction, optional
            The computed particle velocity.
        model : Model, optional
            Object containing the physical parameters.
        vp : Function or float, optional
            The time-constant velocity.
        qp : Function, optional
            The P-wave quality factor.
        b : Function, optional
            The time-constant inverse density.
        """
        # Source term is read-only, so re-use the default
        src = src or self.geometry.src
        # Create a new receiver object to store the result
        rec = rec or self.geometry.rec

        # Create the forward wavefields u and U if not provided
        p = p or TimeFunction(name='p',
                              grid=self.model.grid,
                              time_order=self.time_order,
                              space_order=self.space_order,
                              staggered=NODE)
        P = P or TimeFunction(name='P',
                              grid=self.model.grid,
                              time_order=self.time_order,
                              space_order=self.space_order,
                              staggered=NODE)

        # Memory variable:
        rp = rp or TimeFunction(name='rp',
                                grid=self.model.grid,
                                time_order=self.time_order,
                                space_order=self.space_order,
                                staggered=NODE)
        # Memory variable:
        rP = rP or TimeFunction(name='rP',
                                grid=self.model.grid,
                                time_order=self.time_order,
                                space_order=self.space_order,
                                staggered=NODE)

        if self.time_order == 1:
            v = v or VectorTimeFunction(name="v",
                                        grid=self.model.grid,
                                        time_order=self.time_order,
                                        space_order=self.space_order)
            kwargs.update({k.name: k for k in v})

            dv = dv or VectorTimeFunction(name="dv",
                                          grid=self.model.grid,
                                          time_order=self.time_order,
                                          space_order=self.space_order)
            kwargs.update({k.name: k for k in dv})

        model = model or self.model
        # Pick vp and physical parameters from model unless explicitly provided
        kwargs.update(model.physical_params(**kwargs))

        # Execute operator and return wavefield and receiver data
        summary = self.op_born().apply(dm=dmin,
                                       p=p,
                                       P=P,
                                       src=src,
                                       rec=rec,
                                       rp=rp,
                                       rP=rP,
                                       dt=kwargs.pop('dt', self.dt),
                                       **kwargs)

        return rec, p, P, summary
Exemplo n.º 13
0
    def forward(self, src=None, rec1=None, rec2=None, v=None, tau=None, r=None,
                model=None, save=None, **kwargs):
        """
        Forward modelling function that creates the necessary
        data objects for running a forward modelling operator.

        Parameters
        ----------
        geometry : AcquisitionGeometry
            Geometry object that contains the source (src : SparseTimeFunction) and
            receivers (rec1(txx) : SparseTimeFunction, rec2(tzz) : SparseTimeFunction)
            and their position.
        v : VectorTimeFunction, optional
            The computed particle velocity.
        tau : TensorTimeFunction, optional
            The computed stress.
        r : TensorTimeFunction, optional
            The computed memory variable.
        model : Model, optional
            Object containing the physical parameters.
        lam : Function, optional
            The time-constant first Lame parameter rho * (vp**2 - 2 * vs **2).
        mu : Function, optional
            The Shear modulus (rho * vs*2).
        qp : Function, optional
            The P-wave quality factor (dimensionless).
        qs : Function, optional
            The S-wave quality factor (dimensionless).
        b : Function, optional
            The time-constant inverse density (1/rho=1 for water).
        save : bool, optional
            Whether or not to save the entire (unrolled) wavefield.

        Returns
        -------
        Rec1 (txx), Rec2 (tzz), particle velocities vx and vz, stress txx,
        tzz and txz, memory variables rxx, rzz, rxz and performance summary.
        """
        # Source term is read-only, so re-use the default
        src = src or self.geometry.src
        # Create a new receiver object to store the result
        rec1 = rec1 or self.geometry.new_rec(name='rec1')
        rec2 = rec2 or self.geometry.new_rec(name='rec2')

        # Create all the fields v, tau, r
        save_t = src.nt if save else None
        v = v or VectorTimeFunction(name="v", grid=self.model.grid, save=save_t,
                                    time_order=1, space_order=self.space_order)
        # Stress:
        tau = tau or TensorTimeFunction(name='t', grid=self.model.grid, save=save_t,
                                        space_order=self.space_order, time_order=1)
        # Memory variable:
        r = r or TensorTimeFunction(name='r', grid=self.model.grid, save=save_t,
                                    space_order=self.space_order, time_order=1)

        kwargs.update({k.name: k for k in v})
        kwargs.update({k.name: k for k in tau})
        kwargs.update({k.name: k for k in r})

        model = model or self.model
        # Pick physical parameters from model unless explicitly provided
        kwargs.update(model.physical_params(**kwargs))

        # Execute operator and return wavefield and receiver data
        summary = self.op_fwd(save).apply(src=src, rec1=rec1, rec2=rec2,
                                          dt=kwargs.pop('dt', self.dt), **kwargs)
        return rec1, rec2, v, tau, summary
Exemplo n.º 14
0
    def forward(self,
                src=None,
                rec=None,
                v=None,
                r=None,
                p=None,
                qp=None,
                b=None,
                vp=None,
                save=None,
                **kwargs):
        """
        Forward modelling function that creates the necessary
        data objects for running a forward modelling operator.

        Parameters
        ----------
        geometry : AcquisitionGeometry
            Geometry object that contains the source (SparseTimeFunction) and
            receivers (SparseTimeFunction) and their position.
        v : VectorTimeFunction, optional
            The computed particle velocity.
        r : TimeFunction, optional
            The computed memory variable.
        p : TimeFunction, optional
            Stores the computed wavefield.
        qp : Function, optional
            The P-wave quality factor.
        b : Function, optional
            The time-constant inverse density.
        vp : Function or float, optional
            The time-constant velocity.
        save : int or Buffer, optional
            Option to store the entire (unrolled) wavefield.

        Returns
        -------
        Receiver, wavefield and performance summary
        """
        # Source term is read-only, so re-use the default
        src = src or self.geometry.src

        # Create a new receiver object to store the result
        rec = rec or Receiver(name="rec",
                              grid=self.model.grid,
                              time_range=self.geometry.time_axis,
                              coordinates=self.geometry.rec_positions)

        # Create all the fields v, p, r
        save_t = src.nt if save else None
        v = v or VectorTimeFunction(name="v",
                                    grid=self.model.grid,
                                    save=save_t,
                                    time_order=1,
                                    space_order=self.space_order)

        # Create the forward wavefield if not provided
        p = p or TimeFunction(name="p",
                              grid=self.model.grid,
                              save=save_t,
                              time_order=1,
                              space_order=self.space_order,
                              staggered=NODE)

        # Memory variable:
        r = r or TimeFunction(name="r",
                              grid=self.model.grid,
                              save=save_t,
                              time_order=1,
                              space_order=self.space_order,
                              staggered=NODE)

        kwargs.update({k.name: k for k in v})

        # Pick physical parameters from model unless explicitly provided
        b = b or self.model.b
        qp = qp or self.model.qp

        # Pick vp from model unless explicitly provided
        vp = vp or self.model.vp

        if self.kernel == 'blanch_symes':
            # Execute operator and return wavefield and receiver data
            # With Memory variable
            summary = self.op_fwd(save).apply(src=src,
                                              rec=rec,
                                              qp=qp,
                                              r=r,
                                              p=p,
                                              b=b,
                                              vp=vp,
                                              dt=kwargs.pop('dt', self.dt),
                                              **kwargs)
        else:
            # Execute operator and return wavefield and receiver data
            # Without Memory variable
            summary = self.op_fwd(save).apply(src=src,
                                              rec=rec,
                                              qp=qp,
                                              p=p,
                                              b=b,
                                              vp=vp,
                                              dt=kwargs.pop('dt', self.dt),
                                              **kwargs)
        return rec, p, summary
Exemplo n.º 15
0
def ForwardOperator(model, geometry, space_order=4, save=False, **kwargs):
    """
    Construct method for the forward modelling operator in an elastic media.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    save : int or Buffer
        Saving flag, True saves all time steps, False saves three buffered
        indices (last three time steps). Defaults to False.
    """
    l, qp, mu, qs, ro, damp = \
        model.lam, model.qp, model.mu, model.qs, model.irho, model.damp
    s = model.grid.stepping_dim.spacing

    f0 = geometry._f0
    t_s = (sp.sqrt(1. + 1. / qp**2) - 1. / qp) / f0
    t_ep = 1. / (f0**2 * t_s)
    t_es = (1. + f0 * qs * t_s) / (f0 * qs - f0**2 * t_s)

    # Create symbols for forward wavefield, source and receivers
    # Velocity:
    v = VectorTimeFunction(name="v",
                           grid=model.grid,
                           save=geometry.nt if save else None,
                           time_order=1,
                           space_order=space_order)
    # Stress:
    tau = TensorTimeFunction(name='t',
                             grid=model.grid,
                             save=geometry.nt if save else None,
                             space_order=space_order,
                             time_order=1)
    # Memory variable:
    r = TensorTimeFunction(name='r',
                           grid=model.grid,
                           save=geometry.nt if save else None,
                           space_order=space_order,
                           time_order=1)

    # Particle velocity
    u_v = Eq(v.forward, damp * (v + s * ro * div(tau)))
    symm_grad = grad(v.forward) + grad(v.forward).T
    # Stress equations:
    u_t = Eq(
        tau.forward,
        damp *
        (r.forward + tau + s *
         (l * t_ep / t_s * diag(div(v.forward)) + mu * t_es / t_s * symm_grad))
    )

    # Memory variable equations:
    u_r = Eq(
        r.forward,
        damp * (r - s / t_s * (r + mu * (t_es / t_s - 1) * symm_grad + l *
                               (t_ep / t_s - 1) * diag(div(v.forward)))))
    src_rec_expr = src_rec(v, tau, model, geometry)

    # Substitute spacing terms to reduce flops
    return Operator([u_v, u_r, u_t] + src_rec_expr,
                    subs=model.spacing_map,
                    name='Forward',
                    **kwargs)
Exemplo n.º 16
0
def ForwardOperator(model, geometry, space_order=4, time_order = 1, save=False, **kwargs):
    """
    Construct method for the forward modelling operator in an elastic media.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    save : int or Buffer
        Saving flag, True saves all time steps, False saves three buffered
        indices (last three time steps). Defaults to False.
    """

    v = VectorTimeFunction(name='v', grid=model.grid,
                           space_order=space_order, time_order=time_order)
    tau = TensorTimeFunction(name='tau', grid=model.grid,
                             space_order=space_order, time_order=time_order)

    ## Symbolic physical parameters used from the model
    irho = model.irho
    c11 = model.c11
    c33 = model.c33
    c44 = model.c44
    c66 = model.c66
    c13 = model.c13

    # Model critical timestep computed from CFL condition for VTI media
    ts = model.grid.stepping_dim.spacing 
    damp = model.damp.data

    # Particle Velocity for each direction
    u_vx = Eq(v[0].forward, damp*v[0] + damp*ts*irho*(tau[0,0].dx + tau[1,0].dy + tau[2,0].dz) )
    u_vy = Eq(v[1].forward, damp*v[1] + damp*ts*irho*(tau[0,1].dx + tau[1,1].dy + tau[1,2].dz) )
    u_vz = Eq(v[2].forward, damp*v[2] + damp*ts*irho*(tau[0,2].dx + tau[2,1].dy + tau[2,2].dz) )

    # Stress for each direction in VTI Media:
    u_txx = Eq(tau[0,0].forward, damp*tau[0,0] + damp*ts*(c11*v[0].forward.dx + c11*v[1].forward.dy - 2*c66*v[1].forward.dy + c13*v[2].forward.dz) )
    u_tyy = Eq(tau[1,1].forward, damp*tau[1,1] + damp*ts*(c11*v[0].forward.dx - 2*c66*v[0].forward.dx + c11*v[1].forward.dy + c13*v[2].forward.dz) )
    u_tzz = Eq(tau[2,2].forward, damp*tau[2,2] + damp*ts*(c13*v[0].forward.dx + c13*v[1].forward.dy + c33*v[2].forward.dz) )

    u_txz = Eq(tau[0,2].forward, damp*tau[0,2] + damp*ts*(c44*v[2].forward.dx + c44*v[0].forward.dz) )
    u_tyz = Eq(tau[1,2].forward, damp*tau[1,2] + damp*ts*(c44*v[2].forward.dy + c44*v[1].forward.dz) )
    u_txy = Eq(tau[0,1].forward, damp*tau[0,1] + damp*ts*(c66*v[1].forward.dx + c66*v[0].forward.dy) )
    
    stencil = [u_vx, u_vy, u_vz, u_txx, u_tyy, u_tzz, u_txz, u_tyz, u_txy]
    #srcrec = src_rec(v, tau, model, geometry)

    src = PointSource(name='src', grid=model.grid, time_range=geometry.time_axis,
                      npoint=geometry.nsrc)
                      
    rec = Receiver(name='rec', grid=geometry.grid, time_range=geometry.time_axis,
                   npoint=geometry.nrec)

    # The source injection term
    src_xx = src.inject(field=tau[0, 0].forward, expr=src * ts)
    src_zz = src.inject(field=tau[-1, -1].forward, expr=src * ts)
    src_term = src_xx + src_zz
    if model.grid.dim == 3:
        src_yy = src.inject(field=tau[1, 1].forward, expr=src * ts)
        src_term += src_yy

    # Create interpolation expression for receivers
    rec_term = rec.interpolate(expr=v)

    srcrec = src_term + rec_term
    pde = stencil + srcrec

    # Substitute spacing terms to reduce flops
    op = Operator(pde, subs=model.spacing_map, name="ForwardElasticVTI", **kwargs)

    
    return op
Exemplo n.º 17
0
    def forward(self, src=None, rec1=None, rec2=None, lam=None, qp=None, mu=None, qs=None,
                irho=None, v=None, tau=None, r=None, save=None, **kwargs):
        """
        Forward modelling function that creates the necessary
        data objects for running a forward modelling operator.

        Parameters
        ----------
        geometry : AcquisitionGeometry
            Geometry object that contains the source (src : SparseTimeFunction) and
            receivers (rec1(txx) : SparseTimeFunction, rec2(tzz) : SparseTimeFunction)
            and their position.
        v : VectorTimeFunction, optional
            The computed particle velocity.
        tau : TensorTimeFunction, optional
            The computed stress.
        r : TensorTimeFunction, optional
            The computed memory variable.
        lambda : Function, optional
            The time-constant first Lame parameter (rho * vp**2 - rho * vs **2).
        qp : Function, optional
            The P-wave quality factor (dimensionless).
        mu : Function, optional
            The Shear modulus (rho * vs*2).
        qs : Function, optional
            The S-wave quality factor (dimensionless).
        irho : Function, optional
            The time-constant inverse density (1/rho=1 for water).
        save : int or Buffer, optional
            Option to store the entire (unrolled) wavefield.

        Returns
        -------
        Rec1 (txx), Rec2 (tzz), particle velocities vx and vz, stress txx,
        tzz and txz, memory variables rxx, rzz, rxz and performance summary.
        """
        # Source term is read-only, so re-use the default
        src = src or self.geometry.src
        # Create a new receiver object to store the result
        rec1 = rec1 or Receiver(name='rec1', grid=self.model.grid,
                                time_range=self.geometry.time_axis,
                                coordinates=self.geometry.rec_positions)
        rec2 = rec2 or Receiver(name='rec2', grid=self.model.grid,
                                time_range=self.geometry.time_axis,
                                coordinates=self.geometry.rec_positions)

        # Create all the fields v, tau, r
        save_t = src.nt if save else None
        v = VectorTimeFunction(name="v", grid=self.model.grid, save=save_t,
                               time_order=1, space_order=self.space_order)
        # Stress:
        tau = TensorTimeFunction(name='t', grid=self.model.grid, save=save_t,
                                 space_order=self.space_order, time_order=1)
        # Memory variable:
        r = TensorTimeFunction(name='r', grid=self.model.grid, save=save_t,
                               space_order=self.space_order, time_order=1)

        kwargs.update({k.name: k for k in v})
        kwargs.update({k.name: k for k in tau})
        kwargs.update({k.name: k for k in r})
        # Pick physical parameters from model unless explicitly provided
        lam = lam or self.model.lam
        qp = qp or self.model.qp
        mu = mu or self.model.mu
        qs = qs or self.model.qs
        irho = irho or self.model.irho
        # Execute operator and return wavefield and receiver data
        summary = self.op_fwd(save).apply(src=src, rec1=rec1, mu=mu, qp=qp, lam=lam,
                                          qs=qs, irho=irho, rec2=rec2,
                                          dt=kwargs.pop('dt', self.dt), **kwargs)
        return rec1, rec2, v, tau, summary
Exemplo n.º 18
0
def ForwardOperator(model,
                    geometry,
                    space_order=4,
                    kernel='blanch_symes',
                    save=False,
                    **kwargs):
    """
    Construct method for the forward modelling operator in a viscoacoustic media.

    Parameters
    ----------
    model : Model
        Object containing the physical parameters.
    geometry : AcquisitionGeometry
        Geometry object that contains the source (SparseTimeFunction) and
        receivers (SparseTimeFunction) and their position.
    space_order : int, optional
        Space discretization order.
    kernel : selects a visco-acoustic equation from the options below:
        blanch_symes - Blanch and Symes (1995) / Dutta and Schuster (2014)
        viscoacoustic equation
        ren - Ren et al. (2014) viscoacoustic equation
        deng_mcmechan - Deng and McMechan (2007) viscoacoustic equation
        Defaults to blanch_symes.
    save : int or Buffer
        Saving flag, True saves all time steps, False saves three buffered
        indices (last three time steps). Defaults to False.
    """
    s = model.grid.stepping_dim.spacing

    # Create symbols for forward wavefield, particle velocity, source and receivers
    # Velocity:
    v = VectorTimeFunction(name="v",
                           grid=model.grid,
                           save=geometry.nt if save else None,
                           time_order=1,
                           space_order=space_order)

    p = TimeFunction(name="p",
                     grid=model.grid,
                     staggered=NODE,
                     save=geometry.nt if save else None,
                     time_order=1,
                     space_order=space_order)

    src = PointSource(name="src",
                      grid=model.grid,
                      time_range=geometry.time_axis,
                      npoint=geometry.nsrc)

    rec = Receiver(name="rec",
                   grid=model.grid,
                   time_range=geometry.time_axis,
                   npoint=geometry.nrec)

    # Equations kernels
    eq_kernel = kernels[kernel]
    eqn = eq_kernel(model, geometry, v, p, save=save)

    # The source injection term
    src_term = src.inject(field=p.forward, expr=src * s)

    # Create interpolation expression for receivers
    rec_term = rec.interpolate(expr=p)

    # Substitute spacing terms to reduce flops
    return Operator(eqn + src_term + rec_term,
                    subs=model.spacing_map,
                    name='Forward',
                    **kwargs)