示例#1
0
def ren(model, geometry, v, p, **kwargs):
    """
    Stencil created from Ren et al. (2014) viscoacoustic wave equation.

    https://academic.oup.com/gji/article/197/2/948/616510

    Parameters
    ----------
    v : VectorTimeFunction
        Particle velocity.
    p : TimeFunction
        Pressure field.
    """
    s = model.grid.stepping_dim.spacing
    f0 = geometry._f0
    vp = model.vp
    b = model.b
    qp = model.qp
    damp = model.damp

    # Angular frequency
    w = 2. * np.pi * f0

    # Density
    rho = 1. / b

    # Define PDE
    pde_v = v - s * b * grad(p)
    u_v = Eq(v.forward, damp * pde_v)

    pde_u = p - s * vp * vp * rho * div(v.forward) + \
        s * ((vp * vp * rho) / (w * qp)) * div(b * grad(p))
    u_p = Eq(p.forward, damp * pde_u)

    return [u_v, u_p]
示例#2
0
def sls_2nd_order(model, geometry, p, **kwargs):
    """
    Implementation of the 2nd order viscoacoustic wave-equation from Bai (2014).

    https://library.seg.org/doi/10.1190/geo2013-0030.1

    Parameters
    ----------
    p : TimeFunction
        Pressure field.
    """
    forward = kwargs.get('forward', True)
    space_order = p.space_order
    s = model.grid.stepping_dim.spacing
    b = model.b
    vp = model.vp
    damp = model.damp
    qp = model.qp
    f0 = geometry._f0

    # The stress relaxation parameter
    t_s = (sp.sqrt(1.+1./qp**2)-1./qp)/f0

    # The strain relaxation parameter
    t_ep = 1./(f0**2*t_s)

    # The relaxation time
    tt = (t_ep/t_s)-1.

    # Density
    rho = 1. / b

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

    if forward:

        pde_r = r + s * (tt / t_s) * rho * div(b * grad(p, shift=.5), shift=-.5) - \
            s * (1. / t_s) * r
        u_r = Eq(r.forward, damp * pde_r)

        pde_p = 2. * p - damp * p.backward + s * s * vp * vp * (1. + tt) * rho * \
            div(b * grad(p, shift=.5), shift=-.5) - s * s * vp * vp * r.forward
        u_p = Eq(p.forward, damp * pde_p)

        return [u_r, u_p]

    else:

        pde_r = r + s * (tt / t_s) * p - s * (1. / t_s) * r
        u_r = Eq(r.backward, damp * pde_r)

        pde_p = 2. * p - damp * p.forward + s * s * vp * vp * \
            div(b * grad((1. + tt) * rho * p, shift=.5), shift=-.5) - s * s * vp * vp * \
            div(b * grad(rho * r.backward, shift=.5), shift=-.5)
        u_p = Eq(p.backward, damp * pde_p)

        return [u_r, u_p]
示例#3
0
def blanch_symes(model, geometry, v, p, **kwargs):
    """
    Stencil created from from Blanch and Symes (1995) / Dutta and Schuster (2014)
    viscoacoustic wave equation.

    https://library.seg.org/doi/pdf/10.1190/1.1822695
    https://library.seg.org/doi/pdf/10.1190/geo2013-0414.1

    Parameters
    ----------
    v : VectorTimeFunction
        Particle velocity.
    p : TimeFunction
        Pressure field.
    """
    save = kwargs.get('save')

    s = model.grid.stepping_dim.spacing
    b = model.b
    vp = model.vp
    damp = model.damp
    qp = model.qp
    f0 = geometry._f0

    # The stress relaxation parameter
    t_s = (sp.sqrt(1. + 1. / qp**2) - 1. / qp) / f0

    # The strain relaxation parameter
    t_ep = 1. / (f0**2 * t_s)

    # The relaxation time
    tt = (t_ep / t_s) - 1.

    # Density
    rho = 1. / b

    # Bulk modulus
    bm = rho * (vp * vp)

    # Memory variable.
    r = TimeFunction(name="r",
                     grid=model.grid,
                     staggered=NODE,
                     save=geometry.nt if save else None,
                     time_order=1)

    # Define PDE
    pde_v = v - s * b * grad(p)
    u_v = Eq(v.forward, damp * pde_v)

    pde_r = r - s * (1. / t_s) * r - s * (1. / t_s) * tt * bm * div(v.forward)
    u_r = Eq(r.forward, damp * pde_r)

    pde_p = p - s * bm * (tt + 1.) * div(v.forward) - s * r.forward
    u_p = Eq(p.forward, damp * pde_p)

    return [u_v, u_r, u_p]
示例#4
0
def ren_1st_order(model, geometry, p, **kwargs):
    """
    Implementation of the 1st order viscoacoustic wave-equation from Ren et al. (2014).

    https://academic.oup.com/gji/article/197/2/948/616510

    Parameters
    ----------
    p : TimeFunction
        Pressure field.
    """
    forward = kwargs.get('forward', True)
    s = model.grid.stepping_dim.spacing
    f0 = geometry._f0
    vp = model.vp
    b = model.b
    qp = model.qp
    damp = model.damp

    # Particle velocity
    v = kwargs.pop('v')

    # Angular frequency
    w0 = 2. * np.pi * f0

    # Density
    rho = 1. / b

    eta = vp**2 / (w0 * qp)

    # Bulk modulus
    bm = rho * vp**2

    if forward:

        # Define PDE
        pde_v = v - s * b * grad(p)
        u_v = Eq(v.forward, damp * pde_v)

        pde_p = p - s * bm * div(v.forward) + \
            s * eta * rho * div(b * grad(p, shift=.5), shift=-.5)
        u_p = Eq(p.forward, damp * pde_p)

        return [u_v, u_p]

    else:

        pde_v = v + s * grad(bm * p)
        u_v = Eq(v.backward, pde_v * damp)

        pde_p = p + s * div(b * grad(rho * eta * p, shift=.5), shift=-.5) + \
            s * div(b * v.backward)
        u_p = Eq(p.backward, pde_p * damp)

        return [u_v, u_p]
示例#5
0
def deng_1st_order(model, geometry, p, **kwargs):
    """
    Implementation of the 1st order viscoacoustic wave-equation
    from Deng and McMechan (2007).

    https://library.seg.org/doi/pdf/10.1190/1.2714334

    Parameters
    ----------
    p : TimeFunction
        Pressure field.
    """
    forward = kwargs.get('forward', True)
    s = model.grid.stepping_dim.spacing
    f0 = geometry._f0
    vp = model.vp
    b = model.b
    qp = model.qp
    damp = model.damp

    # Particle velocity
    v = kwargs.pop('v')

    # Angular frequency
    w0 = 2. * np.pi * f0

    # Density
    rho = 1. / b

    # Bulk modulus
    bm = rho * vp**2

    if forward:

        # Define PDE
        pde_v = v - s * b * grad(p)
        u_v = Eq(v.forward, damp * pde_v)

        pde_p = p - s * bm * div(v.forward) - s * (w0 / qp) * p
        u_p = Eq(p.forward, damp * pde_p)

        return [u_v, u_p]

    else:

        pde_v = v + s * grad(bm * p)
        u_v = Eq(v.backward, pde_v * damp)

        pde_p = p + s * div(b * v.backward) - s * (w0 / qp) * p
        u_p = Eq(p.backward, pde_p * damp)

        return [u_v, u_p]
示例#6
0
def ren_2nd_order(model, geometry, p, **kwargs):
    """
    Implementation of the 2nd order viscoacoustic wave-equation from Ren et al. (2014).

    https://library.seg.org/doi/pdf/10.1190/1.2714334

    Parameters
    ----------
    p : TimeFunction
        Pressure field.
    """
    forward = kwargs.get('forward', True)

    s = model.grid.stepping_dim.spacing
    f0 = geometry._f0
    vp = model.vp
    b = model.b
    qp = model.qp
    damp = model.damp

    # Angular frequency
    w0 = 2. * np.pi * f0

    # Density
    rho = 1. / b

    eta = (vp * vp) / (w0 * qp)

    # Bulk modulus
    bm = rho * (vp * vp)

    if forward:

        pde_p = 2. * p - damp * p.backward + s * s * bm * \
            div(b * grad(p, shift=.5), shift=-.5) + s * s * eta * rho * \
            div(b * grad(p - p.backward, shift=.5) / s, shift=-.5)

        u_p = Eq(p.forward, damp * pde_p)

        return [u_p]

    else:

        pde_p = 2. * p - damp * p.forward + s * s * \
            div(b * grad(bm * p, shift=.5), shift=-.5) - s * s * \
            div(b * grad(((p.forward - p) / s) * rho * eta, shift=.5), shift=-.5)
        u_p = Eq(p.backward, damp * pde_p)

        return [u_p]
示例#7
0
def src_rec(v, tau, model, geometry):
    """
    Source injection and receiver interpolation
    """
    s = model.grid.time_dim.spacing
    # Source symbol with input wavelet
    src = PointSource(name='src',
                      grid=model.grid,
                      time_range=geometry.time_axis,
                      npoint=geometry.nsrc)
    rec1 = Receiver(name='rec1',
                    grid=model.grid,
                    time_range=geometry.time_axis,
                    npoint=geometry.nrec)
    rec2 = Receiver(name='rec2',
                    grid=model.grid,
                    time_range=geometry.time_axis,
                    npoint=geometry.nrec)

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

    # Create interpolation expression for receivers
    rec_term1 = rec1.interpolate(expr=tau[-1, -1])
    rec_term2 = rec2.interpolate(expr=div(v))

    return src_expr + rec_term1 + rec_term2
示例#8
0
def deng_mcmechan(model, geometry, v, p, **kwargs):
    """
    Stencil created from Deng and McMechan (2007) viscoacoustic wave equation.

    https://library.seg.org/doi/pdf/10.1190/1.2714334

    Parameters
    ----------
    v : VectorTimeFunction
        Particle velocity.
    p : TimeFunction
        Pressure field.
    """
    s = model.grid.stepping_dim.spacing
    f0 = geometry._f0
    vp = model.vp
    b = model.b
    qp = model.qp
    damp = model.damp

    # Angular frequency
    w = 2. * np.pi * f0

    # Density
    rho = 1. / b

    # Define PDE
    pde_v = v - s * b * grad(p)
    u_v = Eq(v.forward, damp * pde_v)

    pde_p = p - s * vp * vp * rho * div(v.forward) - s * (w / qp) * p
    u_p = Eq(p.forward, damp * pde_p)

    return [u_v, u_p]
示例#9
0
 def dm(self):
     """
     Create a simple model perturbation from the velocity as `dm = div(vp)`.
     """
     dm = Function(name="dm", grid=self.grid, space_order=self.space_order)
     Operator(Eq(dm, div(self.vp)), subs=self.spacing_map)()
     return dm
示例#10
0
def test_solve(so):
    """
    Test that our solve produces the correct output and faster than sympy's
    default behavior for an affine equation (i.e. PDE time steppers).
    """
    grid = Grid((10, 10, 10))
    u = TimeFunction(name="u", grid=grid, time_order=2, space_order=so)
    v = Function(name="v", grid=grid, space_order=so)
    eq = u.dt2 - div(v * grad(u))

    # Standard sympy solve
    t0 = time.time()
    sol1 = sympy.solve(eq.evaluate, u.forward, rational=False, simplify=False)[0]
    t1 = time.time() - t0

    # Devito custom solve for linear equation in the target ax + b (most PDE tie steppers)
    t0 = time.time()
    sol2 = solve(eq.evaluate, u.forward)
    t12 = time.time() - t0

    diff = sympy.simplify(sol1 - sol2)
    # Difference can end up with super small coeffs with different evaluation
    # so zero out everything very small
    assert diff.xreplace({k: 0 if abs(k) < 1e-10 else k
                          for k in diff.atoms(sympy.Float)}) == 0
    # Make sure faster (actually much more than 10 for very complex cases)
    assert t12 < t1/10
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)
示例#12
0
 def dm(self):
     """
     Create a simple model perturbation (in squared slowness) from the velocity
     as `dm = div(m)`.
     """
     dm = Function(name="dm", grid=self.grid, space_order=self.space_order)
     Operator(Eq(dm, div(self.m)))()
     return dm
示例#13
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
示例#14
0
 def test_shifted_div(self, shift, ndim):
     grid = Grid(tuple([11] * ndim))
     f = Function(name="f", grid=grid, space_order=4)
     df = div(f, shift=shift).evaluate
     ref = 0
     for d in grid.dimensions:
         x0 = None if shift is None else d + shift * d.spacing
         ref += getattr(f, 'd%s' % d.name)(x0=x0)
     assert df == ref.evaluate
示例#15
0
 def test_shifted_div_of_vectorfunction(self, shift, ndim):
     grid = Grid(tuple([11] * ndim))
     f = Function(name="f", grid=grid, space_order=4)
     df = div(grad(f), shift=shift).evaluate
     ref = 0
     for i, d in enumerate(grid.dimensions):
         x0 = None if shift is None else d + shift * d.spacing
         ref += getattr(grad(f)[i], 'd%s' % d.name)(x0=x0)
     assert df == ref.evaluate
示例#16
0
def deng_2nd_order(model, geometry, p, **kwargs):
    """
    Implementation of the 2nd order viscoacoustic wave-equation
    from Deng and McMechan (2007).

    https://library.seg.org/doi/pdf/10.1190/1.2714334

    Parameters
    ----------
    p : TimeFunction
        Pressure field.
    """
    forward = kwargs.get('forward', True)

    s = model.grid.stepping_dim.spacing
    f0 = geometry._f0
    vp = model.vp
    b = model.b
    qp = model.qp
    damp = model.damp

    # Angular frequency
    w0 = 2. * np.pi * f0

    # Density
    rho = 1. / b

    bm = rho * (vp * vp)

    if forward:

        pde_p = 2. * p - damp*p.backward + s * s * bm * \
            div(b * grad(p, shift=.5), shift=-.5) - s * s * w0/qp * (p - p.backward)/s
        u_p = Eq(p.forward, damp * pde_p)

        return [u_p]

    else:

        pde_p = 2. * p - damp * p.forward + s * s * w0 / qp * (p.forward - p) / s + \
            s * s * div(b * grad(bm * p, shift=.5), shift=-.5)
        u_p = Eq(p.backward, damp * pde_p)

        return [u_p]
示例#17
0
def test_shifted_div_of_vector(shift, ndim):
    grid = Grid(tuple([11] * ndim))
    v = VectorFunction(name="f", grid=grid, space_order=4)
    df = div(v, shift=shift).evaluate
    ref = 0

    for i, d in enumerate(grid.dimensions):
        x0 = (None if shift is None else d +
              shift[i] * d.spacing if type(shift) is tuple else d +
              shift * d.spacing)
        ref += getattr(v[i], 'd%s' % d.name)(x0=x0)

    assert df == ref.evaluate
示例#18
0
def ren_1st_order(model, geometry, p, **kwargs):
    """
    Implementation of the 1st order viscoacoustic wave-equation from Ren et al. (2014).

    https://academic.oup.com/gji/article/197/2/948/616510

    Parameters
    ----------
    p : TimeFunction
        Pressure field.
    """
    s = model.grid.stepping_dim.spacing
    f0 = geometry._f0
    vp = model.vp
    b = model.b
    qp = model.qp
    damp = model.damp

    # Particle velocity
    v = kwargs.pop('v')

    # Angular frequency
    w0 = 2. * np.pi * f0

    # Density
    rho = 1. / b

    # Define PDE
    pde_v = v - s * b * grad(p)
    u_v = Eq(v.forward, damp * pde_v)

    pde_p = p - s * vp * vp * rho * div(v.forward) + \
        s * ((vp * vp * rho) / (w0 * qp)) * div(b * grad(p, shift=.5), shift=-.5)
    u_p = Eq(p.forward, damp * pde_p)

    return [u_v, u_p]
示例#19
0
def test_shifted_div_of_tensor(shift, ndim):
    grid = Grid(tuple([11] * ndim))
    f = TensorFunction(name="f", grid=grid, space_order=4)
    df = div(f, shift=shift).evaluate

    ref = []
    for i, a in enumerate(grid.dimensions):
        elems = []
        for j, d in reversed(list(enumerate(grid.dimensions))):
            x0 = (None if shift is None else d +
                  shift[i][j] * d.spacing if type(shift) is tuple else d +
                  shift * d.spacing)
            ge = getattr(f[i, j], 'd%s' % d.name)(x0=x0)
            elems.append(ge.evaluate)
        ref.append(sum(elems))

    for i, d in enumerate(df):
        assert d == ref[i]
示例#20
0
def sls_1st_order(model, geometry, p, r=None, **kwargs):
    """
    Implementation of the 1st order viscoacoustic wave-equation
    from Blanch and Symes (1995) / Dutta and Schuster (2014).

    https://library.seg.org/doi/pdf/10.1190/1.1822695
    https://library.seg.org/doi/pdf/10.1190/geo2013-0414.1

    Parameters
    ----------
    p : TimeFunction
        Pressure field.
    r : TimeFunction
        Memory variable.
    """
    forward = kwargs.get('forward', True)
    space_order = p.space_order
    save = kwargs.get('save', False)
    save_t = geometry.nt if save else None
    s = model.grid.stepping_dim.spacing
    b = model.b
    vp = model.vp
    damp = model.damp
    qp = model.qp
    f0 = geometry._f0
    q = kwargs.get('q', 0)

    # Particle Velocity
    v = kwargs.pop('v')

    # The stress relaxation parameter
    t_s = (sp.sqrt(1.+1./qp**2)-1./qp)/f0

    # The strain relaxation parameter
    t_ep = 1./(f0**2*t_s)

    # The relaxation time
    tt = (t_ep/t_s)-1.

    # Density
    rho = 1. / b

    # Bulk modulus
    bm = rho * vp**2

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

    if forward:

        # Define PDE
        pde_v = v - s * b * grad(p)
        u_v = Eq(v.forward, damp * pde_v)

        pde_r = r - s * (1. / t_s) * r - s * (1. / t_s) * tt * rho * div(v.forward)
        u_r = Eq(r.forward, damp * pde_r)

        pde_p = p - s * bm * (tt + 1.) * div(v.forward) - s * vp**2 * r.forward + \
            s * vp**2 * q
        u_p = Eq(p.forward, damp * pde_p)

        return [u_v, u_r, u_p]

    else:

        # Define PDE
        pde_r = r - s * (1. / t_s) * r - s * p
        u_r = Eq(r.backward, damp * pde_r)

        pde_v = v + s * grad(rho * (1. + tt) * p) + s * \
            grad((1. / t_s) * rho * tt * r.backward)
        u_v = Eq(v.backward, damp * pde_v)

        pde_p = p + s * vp**2 * div(b * v.backward)
        u_p = Eq(p.backward, damp * pde_p)

        return [u_r, u_v, u_p]
示例#21
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)