def forward_born(model, src_coords, wavelet, rec_coords, space_order=8, nb=40, isic=False, dt=None, free_surface=False):
    clear_cache()

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, rho, dm, damp = model.m, model.rho, model.dm, model.damp

    # Create the forward and linearized wavefield
    u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=space_order)
    du = TimeFunction(name="du", grid=model.grid, time_order=2, space_order=space_order)
    if len(model.shape) == 2:
        x,y = u.space_dimensions
    else:
        x,y,z = u.space_dimensions

    # Set up PDEs and rearrange
    ulaplace, rho = acoustic_laplacian(u, rho)
    dulaplace, _ = acoustic_laplacian(du, rho)

    if isic:
        # Sum ((u.dx * d, / rho).dx for x in dimensions)
        # space_order//2  so that u.dx.dx has the same radius as u.laplace
        du_aux = sum([first_derivative(first_derivative(u, dim=d, fd_order=space_order//2) * dm / rho, fd_order=space_order//2, dim=d)
                      for d in u.space_dimensions])
        lin_source = dm /rho * u.dt2 * m - du_aux
    else:
        lin_source = dm / rho * u.dt2

    stencil_u = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace)
    stencil_du = damp * (2.0 * du - damp * du.backward + dt**2 * rho / m * (dulaplace - lin_source))

    expression_u = [Eq(u.forward, stencil_u)]
    expression_du = [Eq(du.forward, stencil_du)]

    # Define source symbol with wavelet
    src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords)
    src.data[:] = wavelet[:]
    src_term = src.inject(field=u.forward, expr=src * rho * dt**2 / m)

    # Define receiver symbol
    rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords)
    rec_term = rec.interpolate(expr=du)

    expression = expression_u + expression_du + src_term + rec_term

    # Free surface
    if free_surface is True:
        expression += freesurface(u, space_order//2, model.nbpml)
        expression += freesurface(du, space_order//2, model.nbpml)

    # Create operator and run
    set_log_level('ERROR')
    subs = model.spacing_map
    subs[u.grid.time_dim.spacing] = dt
    op = Operator(expression, subs=subs, dse='advanced', dle='advanced')
    op()

    return rec.data
def forward_freq_modeling(model, src_coords, wavelet, rec_coords, freq, space_order=8, dt=None, factor=None, free_surface=False):
    # Forward modeling with on-the-fly DFT of forward wavefields
    clear_cache()

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, rho, damp = model.m, model.rho, model.damp

    freq_dim = Dimension(name='freq_dim')
    time = model.grid.time_dim
    if factor is None:
        factor = int(1 / (dt*4*np.max(freq)))
        tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor)
    if factor==1:
        tsave = time
    else:
        tsave = ConditionalDimension(name='tsave', parent=model.grid.time_dim, factor=factor)
    print("DFT subsampling factor: ", factor)

    # Create wavefields
    nfreq = freq.shape[0]
    u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order)
    f = Function(name='f', dimensions=(freq_dim,), shape=(nfreq,))
    f.data[:] = freq[:]
    ufr = Function(name='ufr', dimensions=(freq_dim,) + u.indices[1:], shape=(nfreq,) + model.shape_domain)
    ufi = Function(name='ufi', dimensions=(freq_dim,) + u.indices[1:], shape=(nfreq,) + model.shape_domain)

    ulaplace, rho = acoustic_laplacian(u, rho)

    # Set up PDE and rearrange
    stencil = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace)
    expression = [Eq(u.forward, stencil)]
    expression += [Eq(ufr, ufr + factor*u*cos(2*np.pi*f*tsave*factor*dt))]
    expression += [Eq(ufi, ufi - factor*u*sin(2*np.pi*f*tsave*factor*dt))]

    # Source symbol with input wavelet
    src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords)
    src.data[:] = wavelet[:]
    src_term = src.inject(field=u.forward, expr=src * dt**2 / m)

    # Data is sampled at receiver locations
    rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords)
    rec_term = rec.interpolate(expr=u)

    # Create operator and run

    expression += src_term + rec_term
    # Free surface
    if free_surface is True:
        expression += freesurface(u, space_order//2, model.nbpml)

    subs = model.spacing_map
    subs[u.grid.time_dim.spacing] = dt
    op = Operator(expression, subs=subs, dse='advanced', dle='advanced')
    cf = op.cfunction
    op()

    return rec.data, ufr, ufi
예제 #3
0
def forward_freq_modeling(model,
                          src_coords,
                          wavelet,
                          rec_coords,
                          freq,
                          space_order=8,
                          nb=40,
                          dt=None,
                          factor=None):
    # Forward modeling with on-the-fly DFT of forward wavefields
    clear_cache()

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, damp = model.m, model.damp
    freq_dim = Dimension(name='freq_dim')
    time = model.grid.time_dim
    if factor is None:
        factor = int(1 / (dt * 4 * np.max(freq)))
        tsave = ConditionalDimension(name='tsave',
                                     parent=model.grid.time_dim,
                                     factor=factor)
    if factor == 1:
        tsave = time
    else:
        tsave = ConditionalDimension(name='tsave',
                                     parent=model.grid.time_dim,
                                     factor=factor)
    print("DFT subsampling factor: ", factor)

    # Create wavefields
    nfreq = freq.shape[0]
    u = TimeFunction(name='u',
                     grid=model.grid,
                     time_order=2,
                     space_order=space_order)
    f = Function(name='f', dimensions=(freq_dim, ), shape=(nfreq, ))
    f.data[:] = freq[:]
    ufr = Function(name='ufr',
                   dimensions=(freq_dim, ) + u.indices[1:],
                   shape=(nfreq, ) + model.shape_domain)
    ufi = Function(name='ufi',
                   dimensions=(freq_dim, ) + u.indices[1:],
                   shape=(nfreq, ) + model.shape_domain)

    # Set up PDE and rearrange
    eqn = m * u.dt2 - u.laplace + damp * u.dt
    stencil = solve(eqn, u.forward, simplify=False, rational=False)[0]
    expression = [Eq(u.forward, stencil)]
    expression += [
        Eq(ufr, ufr + factor * u * cos(2 * np.pi * f * tsave * factor * dt))
    ]
    expression += [
        Eq(ufi, ufi - factor * u * sin(2 * np.pi * f * tsave * factor * dt))
    ]

    # Source symbol with input wavelet
    src = PointSource(name='src',
                      grid=model.grid,
                      ntime=nt,
                      coordinates=src_coords)
    src.data[:] = wavelet[:]
    src_term = src.inject(field=u.forward,
                          offset=model.nbpml,
                          expr=src * dt**2 / m)

    # Data is sampled at receiver locations
    rec = Receiver(name='rec',
                   grid=model.grid,
                   ntime=nt,
                   coordinates=rec_coords)
    rec_term = rec.interpolate(expr=u, offset=model.nbpml)

    # Create operator and run
    set_log_level('ERROR')
    expression += src_term + rec_term
    subs = model.spacing_map
    subs[u.grid.time_dim.spacing] = dt
    op = Operator(expression,
                  subs=subs,
                  dse='advanced',
                  dle='advanced',
                  name="Forward%s" % randint(1e5))
    op()

    return rec.data, ufr, ufi
예제 #4
0
def forward_modeling(model,
                     src_coords,
                     wavelet,
                     rec_coords,
                     save=False,
                     space_order=8,
                     nb=40,
                     free_surface=False,
                     op_return=False,
                     dt=None):
    clear_cache()

    # If wavelet is file, read it
    if isinstance(wavelet, str):
        wavelet = np.load(wavelet)

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, rho, damp = model.m, model.rho, model.damp

    # Create the forward wavefield
    if save is False and rec_coords is not None:
        u = TimeFunction(name='u',
                         grid=model.grid,
                         time_order=2,
                         space_order=space_order)
    else:
        u = TimeFunction(name='u',
                         grid=model.grid,
                         time_order=2,
                         space_order=space_order,
                         save=nt)

    # Set up PDE and rearrange
    ulaplace, rho = acoustic_laplacian(u, rho)
    H = symbols('H')
    eqn = m / rho * u.dt2 - H + damp * u.dt

    # Input source is wavefield
    if isinstance(wavelet, TimeFunction):
        wf_src = TimeFunction(name='wf_src',
                              grid=model.grid,
                              time_order=2,
                              space_order=space_order,
                              save=nt)
        wf_src._data = wavelet._data
        eqn -= wf_src

    # Rearrange expression
    stencil = solve(eqn, u.forward, simplify=False, rational=False)[0]
    expression = [Eq(u.forward, stencil.subs({H: ulaplace}))]

    # Free surface
    if free_surface is True:
        fs = DefaultDimension(name="fs", default_value=int(space_order / 2))
        expression += [
            Eq(u.forward.subs({u.indices[-1]: model.nbpml - fs - 1}),
               -u.forward.subs({u.indices[-1]: model.nbpml + fs + 1}))
        ]

    # Source symbol with input wavelet
    if src_coords is not None:
        src = PointSource(name='src',
                          grid=model.grid,
                          ntime=nt,
                          coordinates=src_coords)
        src.data[:] = wavelet[:]
        src_term = src.inject(field=u.forward,
                              offset=model.nbpml,
                              expr=src * rho * dt**2 / m)
        expression += src_term

    # Data is sampled at receiver locations
    if rec_coords is not None:
        rec = Receiver(name='rec',
                       grid=model.grid,
                       ntime=nt,
                       coordinates=rec_coords)
        rec_term = rec.interpolate(expr=u, offset=model.nbpml)
        expression += rec_term

    # Create operator and run
    set_log_level('ERROR')
    subs = model.spacing_map
    subs[u.grid.time_dim.spacing] = dt
    op = Operator(expression,
                  subs=subs,
                  dse='advanced',
                  dle='advanced',
                  name="Forward%s" % randint(1e5))
    if op_return is False:
        op()
        if rec_coords is None:
            return u
        else:
            return rec.data, u
    else:
        return op
예제 #5
0
def forward_born(model,
                 src_coords,
                 wavelet,
                 rec_coords,
                 space_order=8,
                 nb=40,
                 isic=False,
                 dt=None):
    clear_cache()

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, rho, dm, damp = model.m, model.rho, model.dm, model.damp

    # Create the forward and linearized wavefield
    u = TimeFunction(name="u",
                     grid=model.grid,
                     time_order=2,
                     space_order=space_order)
    du = TimeFunction(name="du",
                      grid=model.grid,
                      time_order=2,
                      space_order=space_order)
    if len(model.shape) == 2:
        x, y = u.space_dimensions
    else:
        x, y, z = u.space_dimensions

    # Set up PDEs and rearrange
    ulaplace, rho = acoustic_laplacian(u, rho)
    dulaplace, _ = acoustic_laplacian(du, rho)
    H = symbols('H')
    S = symbols('S')
    eqn = m / rho * u.dt2 - H + damp * u.dt
    stencil1 = solve(eqn, u.forward, simplify=False, rational=False)[0]
    eqn_lin = m / rho * du.dt2 - H + damp * du.dt + S
    if isic:
        # Sum ((u.dx * d, / rho).dx for x in dimensions)
        # space_order//2  so that u.dx.dx has the same radius as u.laplace
        du_aux = sum([
            first_derivative(
                first_derivative(u, dim=d, order=space_order // 2) * dm / rho,
                order=space_order // 2,
                dim=d) for d in u.space_dimensions
        ])
        lin_source = dm / rho * u.dt2 * m - du_aux
    else:
        lin_source = dm / rho * u.dt2

    stencil2 = solve(eqn_lin, du.forward, simplify=False, rational=False)[0]
    expression_u = [Eq(u.forward, stencil1.subs({H: ulaplace}))]
    expression_du = [
        Eq(du.forward, stencil2.subs({
            H: dulaplace,
            S: lin_source
        }))
    ]

    # Define source symbol with wavelet
    src = PointSource(name='src',
                      grid=model.grid,
                      ntime=nt,
                      coordinates=src_coords)
    src.data[:] = wavelet[:]
    src_term = src.inject(field=u.forward,
                          offset=model.nbpml,
                          expr=src * rho * dt**2 / m)

    # Define receiver symbol
    rec = Receiver(name='rec',
                   grid=model.grid,
                   ntime=nt,
                   coordinates=rec_coords)
    rec_term = rec.interpolate(expr=du, offset=model.nbpml)

    # Create operator and run
    set_log_level('ERROR')
    expression = expression_u + src_term + expression_du + rec_term
    subs = model.spacing_map
    subs[u.grid.time_dim.spacing] = dt
    op = Operator(expression,
                  subs=subs,
                  dse='advanced',
                  dle='advanced',
                  name="Born%s" % randint(1e5))
    op()

    return rec.data
def forward_modeling(model, src_coords, wavelet, rec_coords, save=False, space_order=8, nb=40, free_surface=False, op_return=False, u_return=False, dt=None, tsub_factor=1):
    clear_cache()

    # If wavelet is file, read it
    if isinstance(wavelet, str):
        wavelet = np.load(wavelet)

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, rho, damp = model.m, model.rho, model.damp

    # Create the forward wavefield
    if save is False and rec_coords is not None:
        u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order)
        eqsave = []
    elif save is True and tsub_factor > 1:
        u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order)
        time_subsampled = ConditionalDimension(name='t_sub', parent=u.grid.time_dim, factor=tsub_factor)
        nsave = (nt-1)//tsub_factor + 2
        usave = TimeFunction(name='us', grid=model.grid, time_order=2, space_order=space_order, time_dim=time_subsampled, save=nsave)
        eqsave = [Eq(usave.forward, u.forward)]
    else:
        u = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=space_order, save=nt)
        eqsave = []

    # Set up PDE
    ulaplace, rho = acoustic_laplacian(u, rho)
    stencil = damp * ( 2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace)

    # Input source is wavefield
    if isinstance(wavelet, TimeFunction):
        wf_src = TimeFunction(name='wf_src', grid=model.grid, time_order=2, space_order=space_order, save=nt)
        wf_src._data = wavelet._data
        stencil -= wf_src

    # Rearrange expression
    expression = [Eq(u.forward, stencil)]

     # Data is sampled at receiver locations
    if rec_coords is not None:
        rec = Receiver(name='rec', grid=model.grid, ntime=nt, coordinates=rec_coords)
        rec_term = rec.interpolate(expr=u)
        expression += rec_term

    # Create operator and run
    if save:
        expression += eqsave

    # Free surface
    kwargs = dict()
    if free_surface is True:
        expression += freesurface(u, space_order//2, model.nbpml)

    # Source symbol with input wavelet
    if src_coords is not None:
        src = PointSource(name='src', grid=model.grid, ntime=nt, coordinates=src_coords)
        src.data[:] = wavelet[:]
        src_term = src.inject(field=u.forward, expr=src * rho * dt**2 / m)
        expression += src_term

    # Create operator and run
    set_log_level('ERROR')
    subs = model.spacing_map
    subs[u.grid.time_dim.spacing] = dt
    op = Operator(expression, subs=subs, dse='advanced', dle='advanced')

    # Return data and wavefields
    if op_return is False:
        op()
        if save is True and tsub_factor > 1:
            if rec_coords is None:
                return usave
            else:
                return rec.data, usave
        else:
            if rec_coords is None:
                return u
            else:
                return rec.data, u

    # For optimal checkpointing, return operator only
    else:
        return op
예제 #7
0
def forward_modeling(model,
                     src_coords,
                     wavelet,
                     rec_coords,
                     save=False,
                     space_order=8,
                     nb=40,
                     op_return=False,
                     dt=None):
    clear_cache()

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, damp = model.m, model.damp

    # Create the forward wavefield
    if save is False:
        u = TimeFunction(name='u',
                         grid=model.grid,
                         time_order=2,
                         space_order=space_order)
    else:
        u = TimeFunction(name='u',
                         grid=model.grid,
                         time_order=2,
                         space_order=space_order,
                         save=nt)

    # Set up PDE and rearrange
    eqn = m * u.dt2 - u.laplace + damp * u.dt
    stencil = solve(eqn, u.forward)[0]
    expression = [Eq(u.forward, stencil)]

    # Source symbol with input wavelet
    src = PointSource(name='src',
                      grid=model.grid,
                      ntime=nt,
                      coordinates=src_coords)
    src.data[:] = wavelet[:]
    src_term = src.inject(field=u.forward,
                          offset=model.nbpml,
                          expr=src * dt**2 / m)

    # Data is sampled at receiver locations
    rec = Receiver(name='rec',
                   grid=model.grid,
                   ntime=nt,
                   coordinates=rec_coords)
    rec_term = rec.interpolate(expr=u, offset=model.nbpml)

    # Create operator and run
    set_log_level('ERROR')
    expression += src_term + rec_term
    op = Operator(expression,
                  subs=model.spacing_map,
                  dse='advanced',
                  dle='advanced',
                  name="Forward%s" % randint(1e5))
    if op_return is False:
        op(dt=dt)
        return rec.data, u
    else:
        return op
예제 #8
0
def forward_born(model,
                 src_coords,
                 wavelet,
                 rec_coords,
                 space_order=8,
                 nb=40,
                 isic=False,
                 dt=None):
    clear_cache()

    # Parameters
    nt = wavelet.shape[0]
    if dt is None:
        dt = model.critical_dt
    m, dm, damp = model.m, model.dm, model.damp

    # Create the forward and linearized wavefield
    u = TimeFunction(name="u",
                     grid=model.grid,
                     time_order=2,
                     space_order=space_order)
    du = TimeFunction(name="du",
                      grid=model.grid,
                      time_order=2,
                      space_order=space_order)
    if len(model.shape) == 2:
        x, y = u.space_dimensions
    else:
        x, y, z = u.space_dimensions

    # Set up PDEs and rearrange
    eqn = m * u.dt2 - u.laplace + damp * u.dt
    stencil1 = solve(eqn, u.forward)[0]
    if isic is not True:
        eqn_lin = m * du.dt2 - du.laplace + damp * du.dt + dm * u.dt2  # born modeling
    else:
        du_aux = sum([
            first_derivative(
                first_derivative(u, dim=d, order=space_order // 2) * dm,
                order=space_order // 2,
                dim=d) for d in u.space_dimensions
        ])
        eqn_lin = m * du.dt2 - du.laplace + damp * du.dt + (dm * u.dt2 * m -
                                                            du_aux)

    if isic is not True:
        stencil2 = solve(eqn_lin, du.forward)[0]
    else:
        stencil2 = solve(eqn_lin, du.forward, simplify=False,
                         rational=False)[0]

    expression_u = [Eq(u.forward, stencil1)]
    expression_du = [Eq(du.forward, stencil2)]

    # Define source symbol with wavelet
    src = PointSource(name='src',
                      grid=model.grid,
                      ntime=nt,
                      coordinates=src_coords)
    src.data[:] = wavelet[:]
    src_term = src.inject(field=u.forward,
                          offset=model.nbpml,
                          expr=src * dt**2 / m)

    # Define receiver symbol
    rec = Receiver(name='rec',
                   grid=model.grid,
                   ntime=nt,
                   coordinates=rec_coords)
    rec_term = rec.interpolate(expr=du, offset=model.nbpml)

    # Create operator and run
    set_log_level('ERROR')
    expression = expression_u + src_term + expression_du + rec_term
    op = Operator(expression,
                  subs=model.spacing_map,
                  dse='advanced',
                  dle='advanced',
                  name="Born%s" % randint(1e5))
    op(dt=dt)

    return rec.data
def forward(model,
            src_coords,
            rcv_coords,
            wav,
            dt=None,
            space_order=8,
            save=False):
    "Compute forward wavefield u = A(m)^{-1}*f and related quantities (u(xrcv))"

    clear_cache()

    # Setting time sampling
    if dt is None:
        dt = model.critical_dt

    # Physical parameters
    m, rho, damp = model.m, model.rho, model.damp

    # Setting adjoint wavefield
    nt = wav.shape[0]
    u = TimeFunction(name="u",
                     grid=model.grid,
                     time_order=2,
                     space_order=space_order,
                     save=None if not save else nt)

    # Set up PDE expression and rearrange
    ulaplace, rho = laplacian(u, rho)
    stencil = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m * ulaplace)
    expression = [Eq(u.forward, stencil)]

    # Setup adjoint source injected at receiver locations
    src = PointSource(name="src",
                      grid=model.grid,
                      ntime=nt,
                      coordinates=src_coords)
    src.data[:] = wav[:]
    src_term = src.inject(field=u.forward, expr=src * rho * dt**2 / m)
    expression += src_term

    # Setup adjoint wavefield sampling at source locations
    rcv = Receiver(name="rcv",
                   grid=model.grid,
                   ntime=nt,
                   coordinates=rcv_coords)
    adj_rcv = rcv.interpolate(expr=u)
    expression += adj_rcv

    # Create operator and run
    subs = model.spacing_map
    subs[u.grid.time_dim.spacing] = dt
    op = Operator(expression,
                  subs=subs,
                  dse="advanced",
                  dle="advanced",
                  name="forward")
    op()

    # Output
    if save:
        return rcv.data, u
    else:
        return rcv.data, None
def objTWRIdual_devito(model,
                       y,
                       src_coords,
                       rcv_coords,
                       wav,
                       dat,
                       Filter,
                       eps,
                       mode="eval",
                       objfact=np.float32(1),
                       comp_alpha=True,
                       grad_corr=False,
                       weight_fun_pars=None,
                       dt=None,
                       space_order=8):
    "Evaluate TWRI objective functional/gradients for current (m, y)"

    clear_cache()

    # Setting time sampling
    if dt is None:
        dt = model.critical_dt

    # Computing y in reduced mode (= residual) if not provided
    u0 = None
    y_was_None = y is None
    if y_was_None:
        u0rcv, u0 = forward(model,
                            src_coords,
                            rcv_coords,
                            wav,
                            dt=dt,
                            space_order=space_order,
                            save=(mode == "grad") and grad_corr)
        y = applyfilt(dat - u0rcv, Filter)
        PTy = applyfilt_transp(y, Filter)

    # Normalization constants
    nx = np.float32(model.m.size)
    nt, nr = np.float32(y.shape)
    etaf = npla.norm(wav.reshape(-1)) / np.sqrt(nt * nx)
    etad = npla.norm(applyfilt(dat, Filter).reshape(-1)) / np.sqrt(nt * nr)

    # Compute wavefield vy = adjoint(F(m))*Py
    norm_vPTy2, vPTy_src, vPTy = adjoint_y(model,
                                           PTy,
                                           src_coords,
                                           rcv_coords,
                                           weight_fun_pars=weight_fun_pars,
                                           dt=dt,
                                           space_order=space_order,
                                           save=(mode == "grad"))

    # <PTy, d-F(m)*f> = <PTy, d>-<adjoint(F(m))*PTy, f>
    PTy_dot_r = np.dot(PTy.reshape(-1), dat.reshape(-1)) - np.dot(
        vPTy_src.reshape(-1), wav.reshape(-1))

    # ||y||
    norm_y = npla.norm(y.reshape(-1))

    # Optimal alpha
    c1 = etaf**np.float32(2) / (np.float32(4) * etad**np.float32(2) * nx * nt)
    c2 = np.float32(1) / (etad * nr * nt)
    c3 = eps / np.sqrt(nr * nt)
    alpha = compute_optalpha(c1 * norm_vPTy2,
                             c2 * PTy_dot_r,
                             c3 * norm_y,
                             comp_alpha=comp_alpha)

    # Lagrangian evaluation
    fun = -alpha**np.float32(
        2) * c1 * norm_vPTy2 + alpha * c2 * PTy_dot_r - np.abs(
            alpha) * c3 * norm_y

    # Gradient computation
    if mode == "grad":

        # Physical parameters
        m, rho, damp = model.m, model.rho, model.damp

        # Create the forward wavefield
        u = TimeFunction(name="u",
                         grid=model.grid,
                         time_order=2,
                         space_order=space_order)

        # Set up PDE and rearrange
        ulaplace, rho = laplacian(u, rho)
        if weight_fun_pars is None:
            stencil = damp * (2.0 * u - damp * u.backward + dt**2 * rho / m *
                              (ulaplace + 2.0 * c1 / c2 * alpha * vPTy))
        else:
            weight = weight_fun(weight_fun_pars, model, src_coords)
            stencil = damp * (
                2.0 * u - damp * u.backward + dt**2 * rho / m *
                (ulaplace + 2.0 * c1 / c2 * alpha * vPTy / weight**2))
        expression = [Eq(u.forward, stencil)]

        # Setup source with wavelet
        nt = wav.shape[0]
        src = PointSource(name="src",
                          grid=model.grid,
                          ntime=nt,
                          coordinates=src_coords)
        src.data[:] = wav[:]
        src_term = src.inject(field=u.forward,
                              expr=src * rho * dt**2 / m)  #######
        expression += src_term

        # Setup data sampling at receiver locations
        rcv = Receiver(name="rcv",
                       grid=model.grid,
                       ntime=nt,
                       coordinates=rcv_coords)
        rcv_term = rcv.interpolate(expr=u)
        expression += rcv_term

        # Setup gradient wrt m
        gradm = Function(name="gradm", grid=model.grid)
        expression += [Inc(gradm, alpha * c2 * vPTy * u.dt2)]

        # Create operator and run
        subs = model.spacing_map
        subs[u.grid.time_dim.spacing] = dt
        op = Operator(expression,
                      subs=subs,
                      dse="advanced",
                      dle="advanced",
                      name="Grad")
        op()

        # Compute gradient wrt y
        if not y_was_None or grad_corr:
            norm_y = npla.norm(y)
            if norm_y == 0:
                grady_data = alpha * c2 * applyfilt(dat - rcv.data, Filter)
            else:
                grady_data = alpha * c2 * applyfilt(
                    dat - rcv.data, Filter) - np.abs(alpha) * c3 * y / norm_y

        # Correcting for reduced gradient
        if not y_was_None or (y_was_None and not grad_corr):

            gradm_data = gradm.data

        else:

            # Compute wavefield vy_ = adjoint(F(m))*grady
            _, _, vy_ = adjoint_y(model,
                                  applyfilt_transp(grady_data, Filter),
                                  src_coords,
                                  rcv_coords,
                                  dt=dt,
                                  space_order=space_order,
                                  save=True)

            # Setup reduced gradient wrt m
            gradm_corr = Function(name="gradmcorr", grid=model.grid)
            expression = [Inc(gradm_corr, vy_ * u0.dt2)]

            # Create operator and run
            subs = model.spacing_map
            subs[u.grid.time_dim.spacing] = dt
            op = Operator(expression,
                          subs=subs,
                          dse="advanced",
                          dle="advanced",
                          name="GradRed")
            op()

            # Reduced gradient post-processing
            gradm_data = gradm.data + gradm_corr.data

    # Return output
    if mode == "eval":
        return fun / objfact
    elif mode == "grad" and y_was_None:
        return fun / objfact, gradm_data / objfact
    elif mode == "grad" and not y_was_None:
        return fun / objfact, gradm_data / objfact, grady_data / objfact