def src_rec(p, model, geometry, **kwargs): """ Forward case: Source injection and receiver interpolation Adjoint case: Receiver injection and source interpolation """ dt = model.grid.time_dim.spacing m = model.m # Source symbol with input wavelet 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) forward = kwargs.get('forward', True) time_order = p.time_order if forward: # The source injection term if(time_order == 1): src_term = src.inject(field=p.forward, expr=src * dt) else: src_term = src.inject(field=p.forward, expr=src * dt**2 / m) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=p) else: # Construct expression to inject receiver values if(time_order == 1): rec_term = rec.inject(field=p.backward, expr=rec * dt) else: rec_term = rec.inject(field=p.backward, expr=rec * dt**2 / m) # Create interpolation expression for the adjoint-source src_term = src.interpolate(expr=p) return src_term + rec_term
def JacobianOperator(model, geometry, space_order=4, **kwargs): """ Construct a Linearized Born operator in a TTI 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 staggered. """ dt = model.grid.stepping_dim.spacing m = model.m time_order = 2 # Create source and receiver symbols src = Receiver(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) # Create wavefields and a dm field u0 = TimeFunction(name='u0', grid=model.grid, save=None, time_order=time_order, space_order=space_order) v0 = TimeFunction(name='v0', grid=model.grid, save=None, time_order=time_order, space_order=space_order) du = TimeFunction(name="du", grid=model.grid, save=None, time_order=2, space_order=space_order) dv = TimeFunction(name="dv", grid=model.grid, save=None, time_order=2, space_order=space_order) dm = Function(name="dm", grid=model.grid, space_order=0) # FD kernels of the PDE FD_kernel = kernels[('centered', len(model.shape))] eqn1 = FD_kernel(model, u0, v0, space_order) # Linearized source and stencil lin_usrc = -dm * u0.dt2 lin_vsrc = -dm * v0.dt2 eqn2 = FD_kernel(model, du, dv, space_order, qu=lin_usrc, qv=lin_vsrc) # Construct expression to inject source values, injecting at u0(t+dt)/v0(t+dt) src_term = src.inject(field=u0.forward, expr=src * dt**2 / m) src_term += src.inject(field=v0.forward, expr=src * dt**2 / m) # Create interpolation expression for receivers, extracting at du(t)+dv(t) rec_term = rec.interpolate(expr=du + dv) # Substitute spacing terms to reduce flops return Operator(eqn1 + src_term + eqn2 + rec_term, subs=model.spacing_map, name='BornTTI', **kwargs)
def JacobianAdjOperator(model, geometry, space_order=4, save=True, **kwargs): """ Construct a linearized JacobianAdjoint modeling Operator in a TTI 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. """ dt = model.grid.stepping_dim.spacing m = model.m time_order = 2 # Gradient symbol and wavefield symbols u0 = TimeFunction(name='u0', grid=model.grid, save=geometry.nt if save else None, time_order=time_order, space_order=space_order) v0 = TimeFunction(name='v0', grid=model.grid, save=geometry.nt if save else None, time_order=time_order, space_order=space_order) du = TimeFunction(name="du", grid=model.grid, save=None, time_order=time_order, space_order=space_order) dv = TimeFunction(name="dv", grid=model.grid, save=None, time_order=time_order, space_order=space_order) dm = Function(name="dm", grid=model.grid) rec = Receiver(name='rec', grid=model.grid, time_range=geometry.time_axis, npoint=geometry.nrec) # FD kernels of the PDE FD_kernel = kernels[('centered', len(model.shape))] eqn = FD_kernel(model, du, dv, space_order, forward=False) dm_update = Inc(dm, - (u0 * du.dt2 + v0 * dv.dt2)) # Add expression for receiver injection rec_term = rec.inject(field=du.backward, expr=rec * dt**2 / m) rec_term += rec.inject(field=dv.backward, expr=rec * dt**2 / m) # Substitute spacing terms to reduce flops return Operator(eqn + rec_term + [dm_update], subs=model.spacing_map, name='GradientTTI', **kwargs)
def AdjointOperator(model, source, receiver, space_order=4, kernel='OT2', **kwargs): """ Constructor method for the adjoint modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp v = TimeFunction(name='v', grid=model.grid, save=None, time_order=2, space_order=space_order) srca = PointSource(name='srca', grid=model.grid, time_range=source.time_range, npoint=source.npoint) rec = Receiver(name='rec', grid=model.grid, time_range=receiver.time_range, npoint=receiver.npoint) s = model.grid.stepping_dim.spacing eqn = iso_stencil(v, m, s, damp, kernel, forward=False) # Construct expression to inject receiver values receivers = rec.inject(field=v.backward, expr=rec * s**2 / m, offset=model.nbpml) # Create interpolation expression for the adjoint-source source_a = srca.interpolate(expr=v, offset=model.nbpml) # Substitute spacing terms to reduce flops return Operator(eqn + receivers + source_a, subs=model.spacing_map, name='Adjoint', **kwargs)
def GradientOperator(model, source, receiver, space_order=4, save=True, kernel='OT2', **kwargs): """ Constructor method for the gradient operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp # Gradient symbol and wavefield symbols grad = Function(name='grad', grid=model.grid) u = TimeFunction(name='u', grid=model.grid, save=source.nt if save else None, time_order=2, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, save=None, time_order=2, space_order=space_order) rec = Receiver(name='rec', grid=model.grid, time_range=receiver.time_range, npoint=receiver.npoint) s = model.grid.stepping_dim.spacing eqn = iso_stencil(v, m, s, damp, kernel, forward=False) if kernel == 'OT2': gradient_update = Inc(grad, - u.dt2 * v) elif kernel == 'OT4': gradient_update = Inc(grad, - (u.dt2 + s**2 / 12.0 * u.laplace2(m**(-2))) * v) # Add expression for receiver injection receivers = rec.inject(field=v.backward, expr=rec * s**2 / m) # Substitute spacing terms to reduce flops return Operator(eqn + receivers + [gradient_update], subs=model.spacing_map, name='Gradient', **kwargs)
def AdjointOperator(model, geometry, space_order=4, kernel='OT2', **kwargs): """ Constructor method for the adjoint modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp v = TimeFunction(name='v', grid=model.grid, save=None, time_order=2, space_order=space_order) srca = PointSource(name='srca', 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) s = model.grid.stepping_dim.spacing eqn = iso_stencil(v, m, s, damp, kernel, forward=False) # Construct expression to inject receiver values receivers = rec.inject(field=v.backward, expr=rec * s**2 / m) # Create interpolation expression for the adjoint-source source_a = srca.interpolate(expr=v) # Substitute spacing terms to reduce flops return Operator(eqn + receivers + source_a, subs=model.spacing_map, name='Adjoint', **kwargs)
def GradientOperator(model, geometry, space_order=4, save=True, kernel='OT2', **kwargs): """ Constructor method for the gradient operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp # Gradient symbol and wavefield symbols grad = Function(name='grad', grid=model.grid) u = TimeFunction(name='u', grid=model.grid, save=geometry.nt if save else None, time_order=2, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, save=None, time_order=2, space_order=space_order) rec = Receiver(name='rec', grid=model.grid, time_range=geometry.time_axis, npoint=geometry.nrec) s = model.grid.stepping_dim.spacing eqn = iso_stencil(v, m, s, damp, kernel, forward=False) if kernel == 'OT2': gradient_update = Inc(grad, - u.dt2 * v) elif kernel == 'OT4': gradient_update = Inc(grad, - (u.dt2 + s**2 / 12.0 * u.laplace2(m**(-2))) * v) # Add expression for receiver injection receivers = rec.inject(field=v.backward, expr=rec * s**2 / m) # Substitute spacing terms to reduce flops return Operator(eqn + receivers + [gradient_update], subs=model.spacing_map, name='Gradient', **kwargs)
def GradientOperator(model, source, receiver, time_order=2, space_order=4, save=True, **kwargs): """ Constructor method for the gradient operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp # Gradient symbol and wavefield symbols grad = Function(name='grad', grid=model.grid) u = TimeFunction(name='u', grid=model.grid, save=save, time_dim=source.nt if save else None, time_order=2, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, save=False, time_order=2, space_order=space_order) rec = Receiver(name='rec', grid=model.grid, ntime=receiver.nt, npoint=receiver.npoint) # Get computational time-step value dt = model.critical_dt * (1.73 if time_order == 4 else 1.0) s = model.grid.stepping_dim.spacing eqn = iso_stencil(v, time_order, m, s, damp, forward=False) if time_order == 2: gradient_update = Eq(grad, grad - u.dt2 * v) else: gradient_update = Eq( grad, grad - (u.dt2 + s**2 / 12.0 * u.laplace2(m**(-2))) * v) # Add expression for receiver injection receivers = rec.inject(field=v.backward, expr=rec * dt**2 / m, offset=model.nbpml) # Substitute spacing terms to reduce flops return Operator(eqn + receivers + [gradient_update], subs=model.spacing_map, time_axis=Backward, name='Gradient', **kwargs)
def GradientOperator(model, geometry, space_order=4, save=True, kernel='OT2', **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 : str, optional Type of discretization, centered or shifted. """ m, damp = model.m, model.damp # Gradient symbol and wavefield symbols grad = Function(name='grad', grid=model.grid) u = TimeFunction(name='u', grid=model.grid, save=geometry.nt if save else None, time_order=2, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, save=None, time_order=2, space_order=space_order) rec = Receiver(name='rec', grid=model.grid, time_range=geometry.time_axis, npoint=geometry.nrec) s = model.grid.stepping_dim.spacing eqn = iso_stencil(v, m, s, damp, kernel, forward=False) if kernel == 'OT2': gradient_update = Inc(grad, -u.dt2 * v) elif kernel == 'OT4': gradient_update = Inc( grad, -(u.dt2 + s**2 / 12.0 * u.biharmonic(m**(-2))) * v) # Add expression for receiver injection receivers = rec.inject(field=v.backward, expr=rec * s**2 / m) # Substitute spacing terms to reduce flops return Operator(eqn + receivers + [gradient_update], subs=model.spacing_map, name='Gradient', **kwargs)
def BornOperator(model, geometry, space_order=4, kernel='OT2', **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. """ m, damp = model.m, model.damp # Create source and receiver symbols src = Receiver(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) # Create wavefields and a dm field u = TimeFunction(name="u", grid=model.grid, save=None, time_order=2, space_order=space_order) U = TimeFunction(name="U", grid=model.grid, save=None, time_order=2, space_order=space_order) dm = Function(name="dm", grid=model.grid, space_order=0) s = model.grid.stepping_dim.spacing eqn1 = iso_stencil(u, m, s, damp, kernel) eqn2 = iso_stencil(U, m, s, damp, kernel, q=-dm * u.dt2) # Add source term expression for u source = src.inject(field=u.forward, expr=src * s**2 / m) # Create receiver interpolation expression from U receivers = rec.interpolate(expr=U) # Substitute spacing terms to reduce flops return Operator(eqn1 + source + eqn2 + receivers, subs=model.spacing_map, name='Born', **kwargs)
def AdjointOperator(model, geometry, space_order=4, **kwargs): """ Construct an adjoint modelling operator in an tti 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. """ dt = model.grid.time_dim.spacing m = model.m time_order = 2 # Create symbols for forward wavefield, source and receivers p = TimeFunction(name='p', grid=model.grid, save=None, time_order=time_order, space_order=space_order) r = TimeFunction(name='r', grid=model.grid, save=None, time_order=time_order, space_order=space_order) srca = PointSource(name='srca', 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) # FD kernels of the PDE FD_kernel = kernels[('centered', len(model.shape))] stencils = FD_kernel(model, p, r, space_order, forward=False) # Construct expression to inject receiver values stencils += rec.inject(field=p.backward, expr=rec * dt**2 / m) stencils += rec.inject(field=r.backward, expr=rec * dt**2 / m) # Create interpolation expression for the adjoint-source stencils += srca.interpolate(expr=p + r) # Substitute spacing terms to reduce flops return Operator(stencils, subs=model.spacing_map, name='AdjointTTI', **kwargs)
def GradientOperator(model, source, receiver, time_order=2, space_order=4, **kwargs): """ Constructor method for the gradient operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp # Gradient symbol and wavefield symbols grad = DenseData(name='grad', shape=model.shape_domain, dtype=model.dtype) u = TimeData(name='u', shape=model.shape_domain, save=True, time_dim=source.nt, time_order=time_order, space_order=space_order, dtype=model.dtype) v = TimeData(name='v', shape=model.shape_domain, save=False, time_order=time_order, space_order=space_order, dtype=model.dtype) rec = Receiver(name='rec', ntime=receiver.nt, ndim=receiver.ndim, npoint=receiver.npoint) if time_order == 2: biharmonic = 0 dt = model.critical_dt gradient_update = Eq(grad, grad - u.dt2 * v) else: biharmonic = v.laplace2(1/m) biharmonicu = - u.laplace2(1/(m**2)) dt = 1.73 * model.critical_dt gradient_update = Eq(grad, grad - (u.dt2 - s**2 / 12.0 * biharmonicu) * v) # Derive stencil from symbolic equation stencil = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * v + (s * damp - 2.0 * m) * v.forward + 2.0 * s ** 2 * (v.laplace + s**2 / 12.0 * biharmonic)) eqn = Eq(v.backward, stencil) # Add expression for receiver injection ti = v.indices[0] receivers = rec.inject(field=v, u_t=ti - 1, offset=model.nbpml, expr=rec * dt * dt / m, p_t=time) return Operator([eqn] + [gradient_update] + receivers, subs={s: dt, h: model.get_spacing()}, time_axis=Backward, name='Gradient', **kwargs)
def AdjointOperator(model, geometry, space_order=4, kernel='OT2', **kwargs): """ Construct an adjoint modelling 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. """ m, damp = model.m, model.damp v = TimeFunction(name='v', grid=model.grid, save=None, time_order=2, space_order=space_order) srca = PointSource(name='srca', 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) s = model.grid.stepping_dim.spacing eqn = iso_stencil(v, m, s, damp, kernel, forward=False) # Construct expression to inject receiver values receivers = rec.inject(field=v.backward, expr=rec * s**2 / m) # Create interpolation expression for the adjoint-source source_a = srca.interpolate(expr=v) # Substitute spacing terms to reduce flops return Operator(eqn + receivers + source_a, subs=model.spacing_map, name='Adjoint', **kwargs)
def AdjointOperator(model, source, receiver, time_order=2, space_order=4, **kwargs): """ Constructor method for the adjoint modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp v = TimeData(name='v', shape=model.shape_domain, save=False, time_order=time_order, space_order=space_order, dtype=model.dtype) srca = PointSource(name='srca', ntime=source.nt, ndim=source.ndim, npoint=source.npoint) rec = Receiver(name='rec', ntime=receiver.nt, ndim=receiver.ndim, npoint=receiver.npoint) if time_order == 2: biharmonic = 0 dt = model.critical_dt else: biharmonic = v.laplace2(1/m) dt = 1.73 * model.critical_dt # Derive both stencils from symbolic equation stencil = 1 / (2 * m + s * damp) * ( 4 * m * v + (s * damp - 2 * m) * v.forward + 2 * s**2 * (v.laplace + s**2 / 12 * biharmonic)) eqn = Eq(v.backward, stencil) # Construct expression to inject receiver values ti = v.indices[0] receivers = rec.inject(field=v, u_t=ti - 1, offset=model.nbpml, expr=rec * dt**2 / m, p_t=time) # Create interpolation expression for the adjoint-source source_a = srca.interpolate(expr=v, u_t=ti, offset=model.nbpml) return Operator([eqn] + receivers + source_a, subs={s: dt, h: model.get_spacing()}, time_axis=Backward, name='Adjoint', **kwargs)
def BornOperator(model, geometry, space_order=4, kernel='OT2', **kwargs): """ Constructor method for the Linearized Born operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param source: :class:`PointData` object containing the source geometry :param receiver: :class:`PointData` object containing the acquisition geometry :param time_order: Time discretization order :param space_order: Space discretization order """ m, damp = model.m, model.damp # Create source and receiver symbols src = Receiver(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) # Create wavefields and a dm field u = TimeFunction(name="u", grid=model.grid, save=None, time_order=2, space_order=space_order) U = TimeFunction(name="U", grid=model.grid, save=None, time_order=2, space_order=space_order) dm = Function(name="dm", grid=model.grid, space_order=0) s = model.grid.stepping_dim.spacing eqn1 = iso_stencil(u, m, s, damp, kernel) eqn2 = iso_stencil(U, m, s, damp, kernel, q=-dm*u.dt2) # Add source term expression for u source = src.inject(field=u.forward, expr=src * s**2 / m) # Create receiver interpolation expression from U receivers = rec.interpolate(expr=U) # Substitute spacing terms to reduce flops return Operator(eqn1 + source + eqn2 + receivers, subs=model.spacing_map, name='Born', **kwargs)
def subsampled_gradient(factor=1, tn=2000.): t0 = 0. # Simulation starts a t=0 shape = (100, 100) origin = (0., 0.) spacing = (15., 15.) space_order = 4 vp = np.empty(shape, dtype=np.float64) vp[:, :51] = 1.5 vp[:, 51:] = 2.5 model = Model(vp=vp, origin=origin, shape=shape, spacing=spacing, space_order=space_order, nbl=10) dt = model.critical_dt # Time step from model grid spacing time_range = TimeAxis(start=t0, stop=tn, step=dt) nt = time_range.num # number of time steps f0 = 0.010 # Source peak frequency is 10Hz (0.010 kHz) src = RickerSource( name='src', grid=model.grid, f0=f0, time_range=time_range) src.coordinates.data[0, :] = np.array(model.domain_size) * .5 src.coordinates.data[0, -1] = 20. # Depth is 20m rec = Receiver( name='rec', grid=model.grid, npoint=101, time_range=time_range) # new rec.coordinates.data[:, 0] = np.linspace(0, model.domain_size[0], num=101) rec.coordinates.data[:, 1] = 20. # Depth is 20m save_elements = (nt + factor - 1) // factor print(save_elements) time_subsampled = ConditionalDimension( 't_sub', parent=model.grid.time_dim, factor=factor) usave = TimeFunction(name='usave', grid=model.grid, time_order=2, space_order=space_order, save=save_elements, time_dim=time_subsampled) u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=space_order) pde = model.m * u.dt2 - u.laplace + model.damp * u.dt stencil = Eq(u.forward, solve(pde, u.forward)) src_term = src.inject( field=u.forward, expr=src * dt**2 / model.m, offset=model.nbl) rec_term = rec.interpolate(expr=u, offset=model.nbl) fwd_op = Operator([stencil] + src_term + [Eq(usave, u)] + rec_term, subs=model.spacing_map) # operator with snapshots v = TimeFunction(name='v', grid=model.grid, save=None, time_order=2, space_order=space_order) grad = Function(name='grad', grid=model.grid) rev_pde = model.m * v.dt2 - v.laplace + model.damp * v.dt.T rev_stencil = Eq(v.backward, solve(rev_pde, v.backward)) gradient_update = Inc(grad, - usave.dt2 * v) s = model.grid.stepping_dim.spacing receivers = rec.inject(field=v.backward, expr=rec*s**2/model.m) rev_op = Operator([rev_stencil] + receivers + [gradient_update], subs=model.spacing_map) fwd_op(time=nt - 2, dt=model.critical_dt) rev_op(dt=model.critical_dt, time=nt-16) return grad.data
def fwi_gradient(vp_in): # AUTO grad = Function(name="grad", grid=model.grid) residual = Receiver(name='rec', grid=model.grid, time_range=geometry.time_axis, coordinates=geometry.rec_positions) objective = 0. u0 = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=4, save=geometry.nt) # MANUAL grad_manual = Function(name="grad", grid=model.grid) residual_man = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates) objective_manual = 0. u0_man = TimeFunction(name='u', grid=model.grid, time_order=2, space_order=4, save=nt) for i in range(9): # AUTO clear_cache() geometry.src_positions[0, :] = source_locations[i, :] true_d, _, _ = solver.forward(vp=model.vp) u0.data.fill(0.) smooth_d, _, _ = solver.forward(vp=vp_in, save=True, u=u0) residual.data[:] = smooth_d.data[:] - true_d.data[:] objective += .5 * np.linalg.norm(residual.data.flatten())**2 solver.gradient(rec=residual, u=u0, vp=vp_in, grad=grad) # MANUAL # source src_true = RickerSource(name='src', grid=model.grid, time_range=time_axis, coordinates=source_locations[i, :], npoint=1, f0=f0) src_term = src_true.inject( field=u.forward, expr=src_true * model.grid.stepping_dim.spacing**2 / model.m) # receiver rec_true = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates, npoint=nreceivers) rec_term = rec_true.interpolate(expr=u) # operator op_fwd = Operator(eqn + src_term + rec_term, subs=model.spacing_map, name='Forward') op_fwd.apply(src=src_true, rec=rec_true, u=u0_man, vp=model.vp, dt=model.critical_dt) u0_man.data.fill(0.) rec_smooth = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates, npoint=nreceivers) op_fwd.apply(src=src_true, rec=rec_smooth, u=u0_man, vp=vp_in, dt=model.critical_dt) # back-receiver rec_back = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates, npoint=nreceivers) rec_back_term = rec_back.inject( field=v.backward, expr=rec_back * model.grid.stepping_dim.spacing**2 / model.m) # gradient gradient_update = Inc(grad_manual, -u.dt2 * v) op_grad = Operator(eqn_back + rec_back_term + [gradient_update], subs=model.spacing_map, name='Gradient') residual_man.data[:] = rec_smooth.data[:] - rec_true.data[:] objective_manual += .5 * np.linalg.norm(residual_man.data.flatten())**2 op_grad.apply(rec=residual_man, u=u0_man, vp=vp_in, dt=model.critical_dt, grad=grad_manual) # sanity-check -> expect for 0! # plot_shotrecord(true_d.data[:] - rec_true.data[:], model, t0, tn) # plot_shotrecord(smooth_d.data[:] - rec_smooth.data[:], model, t0, tn) return objective, -grad.data, objective_manual, -grad_manual.data