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
def src_rec(vx, vy, vz, txx, tyy, tzz, 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=txx.forward, expr=src * s) src_zz = src.inject(field=tzz.forward, expr=src * s) src_expr = src_xx + src_zz if model.grid.dim == 3: src_yy = src.inject(field=tyy.forward, expr=src * s) src_expr += src_yy # Create interpolation expression for receivers rec_term1 = rec1.interpolate(expr=tzz) if model.grid.dim == 2: rec_expr = vx.dx + vz.dy else: rec_expr = vx.dx + vy.dy + vz.dz rec_term2 = rec2.interpolate(expr=rec_expr) return src_expr + rec_term1 + rec_term2
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 ForwardOperator(model, geometry, space_order=4, save=False, kernel='OT2', **kwargs): """ Constructor method for the forward 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 space_order: Space discretization order :param save: Saving flag, True saves all time steps, False only the three """ m, damp = model.m, model.damp # Create symbols for forward wavefield, source and receivers u = TimeFunction(name='u', grid=model.grid, save=geometry.nt if save else None, time_order=2, space_order=space_order) src = PointSource(name='src', grid=geometry.grid, time_range=geometry.time_axis, npoint=geometry.nsrc) rec = Receiver(name='rec', grid=geometry.grid, time_range=geometry.time_axis, npoint=geometry.nrec) s = model.grid.stepping_dim.spacing eqn = iso_stencil(u, m, s, damp, kernel) # Construct expression to inject source values src_term = src.inject(field=u.forward, expr=src * s**2 / m) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u) # Substitute spacing terms to reduce flops return Operator(eqn + src_term + rec_term, subs=model.spacing_map, name='Forward', **kwargs)
def ForwardOperator(model, source, receiver, space_order=4, save=False, kernel='OT2', **kwargs): """ Constructor method for the forward 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 space_order: Space discretization order :param save: Saving flag, True saves all time steps, False only the three """ m, damp = model.m, model.damp # Create symbols for forward wavefield, source and receivers u = TimeFunction(name='u', grid=model.grid, save=source.nt if save else None, time_order=2, space_order=space_order) src = PointSource(name='src', 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(u, m, s, damp, kernel) # Construct expression to inject source values src_term = src.inject(field=u.forward, expr=src * s**2 / m, offset=model.nbpml) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u, offset=model.nbpml) # Substitute spacing terms to reduce flops return Operator(eqn + src_term + rec_term, subs=model.spacing_map, name='Forward', **kwargs)
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 ForwardOperator(model, source, receiver, space_order=4, save=False, kernel='centered', **kwargs): """ Constructor method for the forward modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param src: None ot IShot() (not currently supported properly) :param data: IShot() object containing the acquisition geometry and field data :param: time_order: Time discretization order :param: spc_order: Space discretization order """ dt = model.grid.time_dim.spacing m = model.m time_order = 1 if kernel == 'staggered' else 2 # Create symbols for forward wavefield, source and receivers u = TimeFunction(name='u', grid=model.grid, save=source.nt if save else None, time_order=time_order, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, save=source.nt if save else None, time_order=time_order, space_order=space_order) src = PointSource(name='src', 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) # FD kernels of the PDE FD_kernel = kernels[(kernel, len(model.shape))] stencils = FD_kernel(model, u, v, space_order) # Source and receivers stencils += src.inject(field=u.forward, expr=src * dt**2 / m, offset=model.nbpml) stencils += src.inject(field=v.forward, expr=src * dt**2 / m, offset=model.nbpml) stencils += rec.interpolate(expr=u + v, offset=model.nbpml) # Substitute spacing terms to reduce flops return Operator(stencils, subs=model.spacing_map, name='ForwardTTI', **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 BornOperator(model, source, receiver, 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 = PointSource(name='src', 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) # 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, offset=model.nbpml) # Create receiver interpolation expression from U receivers = rec.interpolate(expr=U, offset=model.nbpml) # Substitute spacing terms to reduce flops return Operator(eqn1 + source + eqn2 + receivers, subs=model.spacing_map, name='Born', **kwargs)
def reference_shot(model, time_range, f0): """ Produce a reference shot gather with a level, conventional free-surface implementation. """ src = RickerSource(name='src', grid=model.grid, f0=f0, npoint=1, time_range=time_range) # First, position source centrally in all dimensions, then set depth src.coordinates.data[0, :] = np.array(model.domain_size) * .5 # Remember that 0, 0, 0 is top left corner # Depth is 100m from free-surface boundary src.coordinates.data[0, -1] = 600. # Create symbol for 101 receivers rec = Receiver(name='rec', grid=model.grid, npoint=101, time_range=time_range) # Prescribe even spacing for receivers along the x-axis rec.coordinates.data[:, 0] = np.linspace(0, model.domain_size[0], num=101) rec.coordinates.data[:, 1] = 500. # Centered on y axis rec.coordinates.data[:, 2] = 650. # Depth is 150m from free surface # Define the wavefield with the size of the model and the time dimension u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=4) # We can now write the PDE pde = model.m * u.dt2 - u.laplace + model.damp * u.dt stencil = Eq(u.forward, solve(pde, u.forward)) # Finally we define the source injection and receiver read function src_term = src.inject(field=u.forward, expr=src * model.critical_dt**2 / model.m) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u.forward) x, y, z = model.grid.dimensions time = u.grid.stepping_dim # Throw a free surface in here free_surface_0 = Eq(u[time + 1, x, y, 60], 0) free_surface_1 = Eq(u[time + 1, x, y, 59], -u[time + 1, x, y, 61]) free_surface_2 = Eq(u[time + 1, x, y, 58], -u[time + 1, x, y, 62]) free_surface = [free_surface_0, free_surface_1, free_surface_2] op = Operator([stencil] + src_term + rec_term + free_surface) op(time=time_range.num - 1, dt=model.critical_dt) return rec.data
def ForwardOperator(model, geometry, space_order=4, save=False, kernel='OT2', **kwargs): """ Construct a forward modelling operator in an acoustic 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. save : int or Buffer, optional Saving flag, True saves all time steps. False saves three timesteps. Defaults to False. kernel : str, optional Type of discretization, 'OT2' or 'OT4'. """ m = model.m # Create symbols for forward wavefield, source and receivers u = TimeFunction(name='u', grid=model.grid, save=geometry.nt if save else None, time_order=2, space_order=space_order) src = PointSource(name='src', grid=geometry.grid, time_range=geometry.time_axis, npoint=geometry.nsrc) rec = Receiver(name='rec', grid=geometry.grid, time_range=geometry.time_axis, npoint=geometry.nrec) s = model.grid.stepping_dim.spacing eqn = iso_stencil(u, model, kernel) # Construct expression to inject source values src_term = src.inject(field=u.forward, expr=src * s**2 / m) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u) # Substitute spacing terms to reduce flops return Operator(eqn + src_term + rec_term, subs=model.spacing_map, name='Forward', **kwargs)
def iso_acoustic(self, opt): shape = (101, 101) extent = (1000, 1000) origin = (0., 0.) v = np.empty(shape, dtype=np.float32) v[:, :51] = 1.5 v[:, 51:] = 2.5 grid = Grid(shape=shape, extent=extent, origin=origin) t0 = 0. tn = 1000. dt = 1.6 time_range = TimeAxis(start=t0, stop=tn, step=dt) f0 = 0.010 src = RickerSource(name='src', grid=grid, f0=f0, npoint=1, time_range=time_range) domain_size = np.array(extent) src.coordinates.data[0, :] = domain_size * .5 src.coordinates.data[0, -1] = 20. rec = Receiver(name='rec', grid=grid, npoint=101, time_range=time_range) rec.coordinates.data[:, 0] = np.linspace(0, domain_size[0], num=101) rec.coordinates.data[:, 1] = 20. u = TimeFunction(name="u", grid=grid, time_order=2, space_order=2) m = Function(name='m', grid=grid) m.data[:] = 1. / (v * v) pde = m * u.dt2 - u.laplace stencil = Eq(u.forward, solve(pde, u.forward)) src_term = src.inject(field=u.forward, expr=src * dt**2 / m) rec_term = rec.interpolate(expr=u.forward) op = Operator([stencil] + src_term + rec_term, opt=opt, language='openmp') # Make sure we've indeed generated OpenMP offloading code assert 'omp target' in str(op) op(time=time_range.num - 1, dt=dt) assert np.isclose(norm(rec), 490.55, atol=1e-2, rtol=0)
def src_rec(vx, vy, vz, qx, qy, qz, txx, tyy, tzz, p, model, geometry): """ Source injection and receiver interpolation """ dt = 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) M = model.M # The source injection term #src_xx = src.inject(field=txx.forward, expr=src * (1.0 - model.phi) * dt, offset=model.nbpml) #src_zz = src.inject(field=tzz.forward, expr=src * (1.0 - model.phi) * dt, offset=model.nbpml) #src_xx = src.inject(field=txx.forward, expr=src * dt) #src_zz = src.inject(field=tzz.forward, expr=src * dt) src_pp = src.inject(field=p.forward, expr=src * M) #src_expr = src_xx + src_zz + src_pp src_expr = src_pp if model.grid.dim == 3: src_yy = src.inject(field=tyy.forward, expr=src * (1.0 - model.phi) * dt, offset=model.nbpml) src_expr += src_yy # Create interpolation expression for receivers rec_term1 = rec1.interpolate(expr=p, offset=model.nbpml) if model.grid.dim == 2: rec_expr = vx.dx + vz.dy else: rec_expr = vx.dx + vy.dy + vz.dz rec_term2 = rec2.interpolate(expr=rec_expr, offset=model.nbpml) return src_expr + rec_term1 + rec_term2
def ForwardOperator(model, geometry, space_order=4, save=False, kernel='centered', **kwargs): """ Construct an forward 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. save : int or Buffer, optional Saving flag, True saves all time steps. False saves three timesteps. Defaults to False. kernel : str, optional Type of discretization, centered or shifted """ dt = model.grid.time_dim.spacing m = model.m time_order = 1 if kernel == 'staggered' else 2 if kernel == 'staggered': stagg_u = stagg_v = NODE else: stagg_u = stagg_v = None # Create symbols for forward wavefield, source and receivers u = TimeFunction(name='u', grid=model.grid, staggered=stagg_u, save=geometry.nt if save else None, time_order=time_order, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, staggered=stagg_v, save=geometry.nt if save else None, time_order=time_order, 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) # FD kernels of the PDE FD_kernel = kernels[(kernel, len(model.shape))] stencils = FD_kernel(model, u, v, space_order) # Source and receivers expr = src * dt / m if kernel == 'staggered' else src * dt**2 / m stencils += src.inject(field=u.forward, expr=expr) stencils += src.inject(field=v.forward, expr=expr) stencils += rec.interpolate(expr=u + v) # Substitute spacing terms to reduce flops return Operator(stencils, subs=model.spacing_map, name='ForwardTTI', **kwargs)
def ForwardOperator(model, geometry, space_order=4, save=False, kernel='centered', **kwargs): """ Construct an forward 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. data : ndarray IShot() object containing the acquisition geometry and field data. time_order : int Time discretization order. space_order : int Space discretization order. """ dt = model.grid.time_dim.spacing m = model.m time_order = 1 if kernel == 'staggered' else 2 if kernel == 'staggered': dims = model.space_dimensions stagg_u = (-dims[-1]) stagg_v = (-dims[0], -dims[1]) if model.grid.dim == 3 else (-dims[0]) else: stagg_u = stagg_v = None # Create symbols for forward wavefield, source and receivers u = TimeFunction(name='u', grid=model.grid, staggered=stagg_u, save=geometry.nt if save else None, time_order=time_order, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, staggered=stagg_v, save=geometry.nt if save else None, time_order=time_order, 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) # FD kernels of the PDE FD_kernel = kernels[(kernel, len(model.shape))] stencils = FD_kernel(model, u, v, space_order) # Source and receivers stencils += src.inject(field=u.forward, expr=src * dt**2 / m) stencils += src.inject(field=v.forward, expr=src * dt**2 / m) stencils += rec.interpolate(expr=u + v) # Substitute spacing terms to reduce flops return Operator(stencils, subs=model.spacing_map, name='ForwardTTI', **kwargs)
def ForwardOperator(model, source, receiver, time_order=2, space_order=4, save=False, **kwargs): """ Constructor method for the forward 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 :param save : Saving flag, True saves all time steps, False only the three """ m, damp = model.m, model.damp # Create symbols for forward wavefield, source and receivers u = TimeData(name='u', shape=model.shape_domain, time_dim=source.nt, time_order=time_order, space_order=space_order, save=save, dtype=model.dtype) src = PointSource(name='src', 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 = u.laplace2(1/m) dt = 1.73 * model.critical_dt # Derive both stencils from symbolic equation: # Create the stencil by hand instead of calling numpy solve for speed purposes # Simple linear solve of a u(t+dt) + b u(t) + c u(t-dt) = L for u(t+dt) stencil = 1 / (2 * m + s * damp) * ( 4 * m * u + (s * damp - 2 * m) * u.backward + 2 * s**2 * (u.laplace + s**2 / 12 * biharmonic)) eqn = [Eq(u.forward, stencil)] # Construct expression to inject source values # Note that src and field terms have differing time indices: # src[time, ...] - always accesses the "unrolled" time index # u[ti + 1, ...] - accesses the forward stencil value ti = u.indices[0] src_term = src.inject(field=u, u_t=ti + 1, offset=model.nbpml, expr=src * dt**2 / m, p_t=time) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u, u_t=ti, offset=model.nbpml) return Operator(eqn + src_term + rec_term, subs={s: dt, h: model.get_spacing()}, time_axis=Forward, name='Forward', **kwargs)
def ForwardOperator(model, geometry, space_order=4, save=False, kernel='centered', **kwargs): """ Constructor method for the forward modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param src: None ot IShot() (not currently supported properly) :param data: IShot() object containing the acquisition geometry and field data :param: time_order: Time discretization order :param: spc_order: Space discretization order """ dt = model.grid.time_dim.spacing m = model.m time_order = 1 if kernel == 'staggered' else 2 if kernel == 'staggered': dims = model.space_dimensions stagg_u = (-dims[-1]) stagg_v = (-dims[0], -dims[1]) if model.grid.dim == 3 else (-dims[0]) else: stagg_u = stagg_v = None # Create symbols for forward wavefield, source and receivers u = TimeFunction(name='u', grid=model.grid, staggered=stagg_u, save=geometry.nt if save else None, time_order=time_order, space_order=space_order) v = TimeFunction(name='v', grid=model.grid, staggered=stagg_v, save=geometry.nt if save else None, time_order=time_order, 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) # FD kernels of the PDE FD_kernel = kernels[(kernel, len(model.shape))] stencils = FD_kernel(model, u, v, space_order) # Source and receivers stencils += src.inject(field=u.forward, expr=src * dt**2 / m) stencils += src.inject(field=v.forward, expr=src * dt**2 / m) stencils += rec.interpolate(expr=u + v) # Substitute spacing terms to reduce flops return Operator(stencils, subs=model.spacing_map, name='ForwardTTI', **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 ForwardOperator(model, source, receiver, time_order=2, space_order=4, save=False, **kwargs): """ Constructor method for the forward modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param src: None ot IShot() (not currently supported properly) :param data: IShot() object containing the acquisition geometry and field data :param: time_order: Time discretization order :param: spc_order: Space discretization order :param: u_ini : wavefield at the three first time step for non-zero initial condition """ dt = model.critical_dt m, damp, epsilon, delta, theta, phi = (model.m, model.damp, model.epsilon, model.delta, model.theta, model.phi) # Create symbols for forward wavefield, source and receivers u = TimeData(name='u', shape=model.shape_domain, time_dim=source.nt, time_order=time_order, space_order=space_order, save=save, dtype=model.dtype) v = TimeData(name='v', shape=model.shape_domain, time_dim=source.nt, time_order=time_order, space_order=space_order, save=save, dtype=model.dtype) src = PointSource(name='src', ntime=source.nt, ndim=source.ndim, npoint=source.npoint) rec = Receiver(name='rec', ntime=receiver.nt, ndim=receiver.ndim, npoint=receiver.npoint) ang0 = cos(theta) ang1 = sin(theta) if len(model.shape) == 3: ang2 = cos(phi) ang3 = sin(phi) # Derive stencil from symbolic equation Gyp = (ang3 * u.dx - ang2 * u.dyr) Gyy = (first_derivative(Gyp * ang3, dim=x, side=centered, order=space_order, matvec=transpose) - first_derivative(Gyp * ang2, dim=y, side=right, order=space_order, matvec=transpose)) Gyp2 = (ang3 * u.dxr - ang2 * u.dy) Gyy2 = (first_derivative(Gyp2 * ang3, dim=x, side=right, order=space_order, matvec=transpose) - first_derivative(Gyp2 * ang2, dim=y, side=centered, order=space_order, matvec=transpose)) Gxp = (ang0 * ang2 * u.dx + ang0 * ang3 * u.dyr - ang1 * u.dzr) Gzr = (ang1 * ang2 * v.dx + ang1 * ang3 * v.dyr + ang0 * v.dzr) Gxx = (first_derivative(Gxp * ang0 * ang2, dim=x, side=centered, order=space_order, matvec=transpose) + first_derivative(Gxp * ang0 * ang3, dim=y, side=right, order=space_order, matvec=transpose) - first_derivative(Gxp * ang1, dim=z, side=right, order=space_order, matvec=transpose)) Gzz = (first_derivative(Gzr * ang1 * ang2, dim=x, side=centered, order=space_order, matvec=transpose) + first_derivative(Gzr * ang1 * ang3, dim=y, side=right, order=space_order, matvec=transpose) + first_derivative(Gzr * ang0, dim=z, side=right, order=space_order, matvec=transpose)) Gxp2 = (ang0 * ang2 * u.dxr + ang0 * ang3 * u.dy - ang1 * u.dz) Gzr2 = (ang1 * ang2 * v.dxr + ang1 * ang3 * v.dy + ang0 * v.dz) Gxx2 = (first_derivative(Gxp2 * ang0 * ang2, dim=x, side=right, order=space_order, matvec=transpose) + first_derivative(Gxp2 * ang0 * ang3, dim=y, side=centered, order=space_order, matvec=transpose) - first_derivative(Gxp2 * ang1, dim=z, side=centered, order=space_order, matvec=transpose)) Gzz2 = (first_derivative(Gzr2 * ang1 * ang2, dim=x, side=right, order=space_order, matvec=transpose) + first_derivative(Gzr2 * ang1 * ang3, dim=y, side=centered, order=space_order, matvec=transpose) + first_derivative(Gzr2 * ang0, dim=z, side=centered, order=space_order, matvec=transpose)) Hp = -(.5 * Gxx + .5 * Gxx2 + .5 * Gyy + .5 * Gyy2) Hzr = -(.5 * Gzz + .5 * Gzz2) else: Gx1p = (ang0 * u.dxr - ang1 * u.dy) Gz1r = (ang1 * v.dxr + ang0 * v.dy) Gxx1 = (first_derivative(Gx1p * ang0, dim=x, side=right, order=space_order, matvec=transpose) - first_derivative(Gx1p * ang1, dim=y, side=centered, order=space_order, matvec=transpose)) Gzz1 = (first_derivative(Gz1r * ang1, dim=x, side=right, order=space_order, matvec=transpose) + first_derivative(Gz1r * ang0, dim=y, side=centered, order=space_order, matvec=transpose)) Gx2p = (ang0 * u.dx - ang1 * u.dyr) Gz2r = (ang1 * v.dx + ang0 * v.dyr) Gxx2 = (first_derivative(Gx2p * ang0, dim=x, side=centered, order=space_order, matvec=transpose) - first_derivative(Gx2p * ang1, dim=y, side=right, order=space_order, matvec=transpose)) Gzz2 = (first_derivative(Gz2r * ang1, dim=x, side=centered, order=space_order, matvec=transpose) + first_derivative(Gz2r * ang0, dim=y, side=right, order=space_order, matvec=transpose)) Hp = -(.5 * Gxx1 + .5 * Gxx2) Hzr = -(.5 * Gzz1 + .5 * Gzz2) stencilp = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * u + (s * damp - 2.0 * m) * u.backward + 2.0 * s**2 * (epsilon * Hp + delta * Hzr)) stencilr = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * v + (s * damp - 2.0 * m) * v.backward + 2.0 * s**2 * (delta * Hp + Hzr)) # Add substitutions for spacing (temporal and spatial) subs = {s: dt, h: model.get_spacing()} first_stencil = Eq(u.forward, stencilp) second_stencil = Eq(v.forward, stencilr) stencils = [first_stencil, second_stencil] ti = u.indices[0] stencils += src.inject(field=u, u_t=ti + 1, expr=src * dt * dt / m, offset=model.nbpml) stencils += src.inject(field=v, u_t=ti + 1, expr=src * dt * dt / m, offset=model.nbpml) stencils += rec.interpolate(expr=u, u_t=ti, offset=model.nbpml) stencils += rec.interpolate(expr=v, u_t=ti, offset=model.nbpml) return Operator(stencils, subs=subs, name='ForwardTTI', **kwargs)
def ForwardOperator(model, source, receiver, space_order=4, save=False, kernel='centered', **kwargs): """ Constructor method for the forward modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param src: None ot IShot() (not currently supported properly) :param data: IShot() object containing the acquisition geometry and field data :param: time_order: Time discretization order :param: spc_order: Space discretization order """ dt = model.grid.time_dim.spacing m, damp, epsilon, delta, theta, phi = (model.m, model.damp, model.epsilon, model.delta, model.theta, model.phi) # Create symbols for forward wavefield, source and receivers 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=save, time_dim=source.nt if save else None, time_order=2, space_order=space_order) src = PointSource(name='src', grid=model.grid, ntime=source.nt, npoint=source.npoint) rec = Receiver(name='rec', grid=model.grid, ntime=receiver.nt, npoint=receiver.npoint) # Tilt and azymuth setup ang0 = cos(theta) ang1 = sin(theta) ang2 = 0 ang3 = 0 if len(model.shape) == 3: ang2 = cos(phi) ang3 = sin(phi) FD_kernel = kernels[(kernel, len(model.shape))] H0, Hz = FD_kernel(u, v, ang0, ang1, ang2, ang3, space_order) # Stencils s = model.grid.stepping_dim.spacing stencilp = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * u + (s * damp - 2.0 * m) * u.backward + 2.0 * s ** 2 * (epsilon * H0 + delta * Hz)) stencilr = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * v + (s * damp - 2.0 * m) * v.backward + 2.0 * s ** 2 * (delta * H0 + Hz)) first_stencil = Eq(u.forward, stencilp) second_stencil = Eq(v.forward, stencilr) stencils = [first_stencil, second_stencil] # Source and receivers stencils += src.inject(field=u.forward, expr=src * dt * dt / m, offset=model.nbpml) stencils += src.inject(field=v.forward, expr=src * dt * dt / m, offset=model.nbpml) stencils += rec.interpolate(expr=u + v, offset=model.nbpml) # Substitute spacing terms to reduce flops return Operator(stencils, subs=model.spacing_map, name='ForwardTTI', **kwargs)
#============================================================================== # Construção Receivers Homogeneo #============================================================================== rec0 = Receiver(name='rec0', grid=model0.grid,npoint=nrec,time_range=time_range0) rec0.coordinates.data[:,0] = nxrecpos rec0.coordinates.data[:,1] = nzrecpos #============================================================================== #============================================================================== # Construção dos Campos Modelo Homogêneo #============================================================================== u0 = TimeFunction(name="u0",grid=model0.grid,time_order=tou,space_order=sou) pde0 = model0.m * u0.dt2 - u0.laplace + model0.damp * u0.dt stencil0 = Eq(u0.forward, solve(pde0, u0.forward)) src_term0 = src0.inject(field=u0.forward, expr=src0* dt0**2 / model0.m) rec_term0 = rec0.interpolate(expr=u0) #============================================================================== #============================================================================== # Construção do Operador do Modelo Homogeneo #============================================================================== op0 = Operator([stencil0] + src_term0 + rec_term0, subs=model0.spacing_map) #============================================================================== #============================================================================== # For para o Número de Fontes #============================================================================== for k in range(0,number_xfontpos): #============================================================================== print("Homogen Source:", k) #==============================================================================
def BornOperator(model, source, receiver, time_order=2, space_order=4, **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 = PointSource(name='src', ntime=source.nt, ndim=source.ndim, npoint=source.npoint) rec = Receiver(name='rec', ntime=receiver.nt, ndim=receiver.ndim, npoint=receiver.npoint) # Create wavefields and a dm field u = TimeData(name="u", shape=model.shape_domain, save=False, time_order=time_order, space_order=space_order, dtype=model.dtype) U = TimeData(name="U", shape=model.shape_domain, save=False, time_order=time_order, space_order=space_order, dtype=model.dtype) dm = DenseData(name="dm", shape=model.shape_domain, dtype=model.dtype) if time_order == 2: biharmonicu = 0 biharmonicU = 0 dt = model.critical_dt else: biharmonicu = u.laplace2(1/m) biharmonicU = U.laplace2(1/m) dt = 1.73 * model.critical_dt # Derive both stencils from symbolic equation # first_eqn = m * u.dt2 - u.laplace + damp * u.dt # second_eqn = m * U.dt2 - U.laplace - dm* u.dt2 + damp * U.dt stencil1 = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * u + (s * damp - 2.0 * m) * u.backward + 2.0 * s ** 2 * (u.laplace + s**2 / 12 * biharmonicu)) stencil2 = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * U + (s * damp - 2.0 * m) * U.backward + 2.0 * s ** 2 * (U.laplace + s**2 / 12 * biharmonicU - dm * u.dt2)) eqn1 = Eq(u.forward, stencil1) eqn2 = Eq(U.forward, stencil2) # Add source term expression for u ti = u.indices[0] source = src.inject(field=u, u_t=ti + 1, offset=model.nbpml, expr=src * dt * dt / m, p_t=time) # Create receiver interpolation expression from U receivers = rec.interpolate(expr=U, u_t=ti, offset=model.nbpml) return Operator([eqn1] + source + [eqn2] + receivers, subs={s: dt, h: model.get_spacing()}, time_axis=Forward, 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
# space-varying field (m, Function) from devito import TimeFunction, Buffer # Define the wavefield with the size of the model and the time dimension u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=2, save=Buffer(time_range.num + 1)) # We can now write the PDE pde = model.m * u.dt2 - u.laplace + model.damp * u.dt # The PDE representation is as on paper from devito import Eq, solve stencil = Eq(u.forward, solve(pde, u.forward)) # Finally we define the source injection and receiver read function to generate the corresponding code src_term = src.inject(field=u.forward, expr=src * dt**2 / model.m) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u.forward) from devito import Operator op = Operator([stencil] + src_term + rec_term, subs=model.spacing_map) op(time=time_range.num - 1, dt=model.critical_dt)
def ForwardOperator(model, source, receiver, space_order=4, save=False, **kwargs): """ Constructor method for the forward modelling operator in an elastic 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 space_order: Space discretization order :param save: Saving flag, True saves all time steps, False only the three buffered indices (last three time steps) """ vp, vs, rho, damp = model.vp, model.vs, model.rho, model.damp s = model.grid.stepping_dim.spacing x, z = model.grid.dimensions cp2 = vp * vp cs2 = vs * vs ro = 1 / rho mu = cs2 * rho l = rho * (cp2 - 2 * cs2) # Create symbols for forward wavefield, source and receivers vx = TimeFunction(name='vx', grid=model.grid, staggered=(0, 1, 0), save=source.nt if save else None, time_order=2, space_order=space_order) vz = TimeFunction(name='vz', grid=model.grid, staggered=(0, 0, 1), save=source.nt if save else None, time_order=2, space_order=space_order) txx = TimeFunction(name='txx', grid=model.grid, save=source.nt if save else None, time_order=2, space_order=space_order) tzz = TimeFunction(name='tzz', grid=model.grid, save=source.nt if save else None, time_order=2, space_order=space_order) txz = TimeFunction(name='txz', grid=model.grid, staggered=(0, 1, 1), save=source.nt if save else None, time_order=2, space_order=space_order) # Source symbol with input wavelet src = PointSource(name='src', grid=model.grid, time_range=source.time_range, npoint=source.npoint) rec1 = Receiver(name='rec1', grid=model.grid, time_range=receiver.time_range, npoint=receiver.npoint) rec2 = Receiver(name='rec2', grid=model.grid, time_range=receiver.time_range, npoint=receiver.npoint) # Stencils fd_vx = (staggered_diff(txx, dim=x, order=space_order, stagger=left) + staggered_diff(txz, dim=z, order=space_order, stagger=right)) u_vx = Eq(vx.forward, damp * vx - damp * s * ro * fd_vx) fd_vz = (staggered_diff(txz, dim=x, order=space_order, stagger=right) + staggered_diff(tzz, dim=z, order=space_order, stagger=left)) u_vz = Eq(vz.forward, damp * vz - damp * ro * s * fd_vz) vxdx = staggered_diff(vx.forward, dim=x, order=space_order, stagger=right) vzdz = staggered_diff(vz.forward, dim=z, order=space_order, stagger=right) u_txx = Eq( txx.forward, damp * txx - damp * (l + 2 * mu) * s * vxdx - damp * l * s * vzdz) u_tzz = Eq( tzz.forward, damp * tzz - damp * (l + 2 * mu) * s * vzdz - damp * l * s * vxdx) vxdz = staggered_diff(vx.forward, dim=z, order=space_order, stagger=left) vzdx = staggered_diff(vz.forward, dim=x, order=space_order, stagger=left) u_txz = Eq(txz.forward, damp * txz - damp * mu * s * (vxdz + vzdx)) # The source injection term src_xx = src.inject(field=txx.forward, expr=src * s, offset=model.nbpml) src_zz = src.inject(field=tzz.forward, expr=src * s, offset=model.nbpml) # Create interpolation expression for receivers rec_term1 = rec1.interpolate(expr=txx, offset=model.nbpml) rec_term2 = rec2.interpolate(expr=tzz, offset=model.nbpml) # Substitute spacing terms to reduce flops return Operator([u_vx, u_vz, u_txx, u_tzz, u_txz] + src_xx + src_zz + rec_term1 + rec_term2, subs=model.spacing_map, name='Forward', **kwargs)
def tilted_shot(model, time_range, f0, tilt, qc=False, toggle_normals=False): """ Produce a shot for the same setup, but tilted with immersed free surface """ src = RickerSource(name='src', grid=model.grid, f0=f0, npoint=1, time_range=time_range) # First, position source, then set depth src.coordinates.data[0, 0] = 500. - 100. * np.sin(np.radians(tilt)) src.coordinates.data[0, 1] = 500. # Remember that 0, 0, 0 is top left corner # Depth is 100m from free-surface boundary src.coordinates.data[0, 2] = 500. + 100. * np.cos(np.radians(tilt)) # Create symbol for 101 receivers rec = Receiver(name='rec', grid=model.grid, npoint=101, time_range=time_range) # Prescribe even spacing for receivers along the x-axis rec_center_x = 500. - 150. * np.sin(np.radians(tilt)) rec_center_z = 500. + 150. * np.cos(np.radians(tilt)) rec_top_x = rec_center_x - 500. * np.cos(np.radians(tilt)) rec_bottom_x = rec_center_x + 500. * np.cos(np.radians(tilt)) rec_top_z = rec_center_z - 500. * np.sin(np.radians(tilt)) rec_bottom_z = rec_center_z + 500. * np.sin(np.radians(tilt)) rec.coordinates.data[:, 0] = np.linspace(rec_top_x, rec_bottom_x, num=101) rec.coordinates.data[:, 1] = 500. # Centered on y axis rec.coordinates.data[:, 2] = np.linspace(rec_top_z, rec_bottom_z, num=101) # Define the wavefield with the size of the model and the time dimension u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=4, coefficients='symbolic') infile = 'tests/trial_surfaces/angled_surface_' + str(tilt) + '.ply' # Zero even derivatives on the boundary spec = {2 * i: 0 for i in range(u.space_order)} bcs_u = BoundaryConditions(spec, u.space_order) functions = pd.DataFrame({ 'function': [u], 'bcs': [bcs_u] }, columns=['function', 'bcs']) # Create the immersed boundary surface surface = ImmersedBoundary('topography', infile, functions, interior_point=tuple(src.coordinates.data[0]), qc=qc, toggle_normals=toggle_normals) # Configure derivative needed derivs = pd.DataFrame( { 'function': [u], 'derivative': [2], 'eval_offset': [(0., 0., 0.)] }, columns=['function', 'derivative', 'eval_offset']) coeffs = surface.subs(derivs) # We can now write the PDE pde = model.m * u.dt2 - u.laplace + model.damp * u.dt stencil = Eq(u.forward, solve(pde, u.forward), coefficients=coeffs) # Finally we define the source injection and receiver read function src_term = src.inject(field=u.forward, expr=src * model.critical_dt**2 / model.m) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u.forward) op = Operator([stencil] + src_term + rec_term) op(time=time_range.num - 1, dt=model.critical_dt) return rec.data
def ForwardOperator(model, source, receiver, time_order=2, space_order=4, save=False, kernel='centered', **kwargs): """ Constructor method for the forward modelling operator in an acoustic media :param model: :class:`Model` object containing the physical parameters :param src: None ot IShot() (not currently supported properly) :param data: IShot() object containing the acquisition geometry and field data :param: time_order: Time discretization order :param: spc_order: Space discretization order """ dt = model.critical_dt m, damp, epsilon, delta, theta, phi = (model.m, model.damp, model.epsilon, model.delta, model.theta, model.phi) # Create symbols for forward wavefield, source and receivers u = TimeData(name='u', shape=model.shape_domain, dtype=model.dtype, save=save, time_dim=source.nt if save else None, time_order=time_order, space_order=space_order) v = TimeData(name='v', shape=model.shape_domain, dtype=model.dtype, save=save, time_dim=source.nt if save else None, time_order=time_order, space_order=space_order) src = PointSource(name='src', ntime=source.nt, ndim=source.ndim, npoint=source.npoint) rec = Receiver(name='rec', ntime=receiver.nt, ndim=receiver.ndim, npoint=receiver.npoint) # Tilt and azymuth setup ang0 = cos(theta) ang1 = sin(theta) ang2 = 0 ang3 = 0 if len(model.shape) == 3: ang2 = cos(phi) ang3 = sin(phi) FD_kernel = kernels[(kernel, len(model.shape))] H0, Hz = FD_kernel(u, v, ang0, ang1, ang2, ang3, space_order) s = t.spacing # Stencils stencilp = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * u + (s * damp - 2.0 * m) * u.backward + 2.0 * s ** 2 * (epsilon * H0 + delta * Hz)) stencilr = 1.0 / (2.0 * m + s * damp) * \ (4.0 * m * v + (s * damp - 2.0 * m) * v.backward + 2.0 * s ** 2 * (delta * H0 + Hz)) first_stencil = Eq(u.forward, stencilp) second_stencil = Eq(v.forward, stencilr) stencils = [first_stencil, second_stencil] # Source and receivers stencils += src.inject(field=u.forward, expr=src * dt * dt / m, offset=model.nbpml) stencils += src.inject(field=v.forward, expr=src * dt * dt / m, offset=model.nbpml) stencils += rec.interpolate(expr=u + v, offset=model.nbpml) # Add substitutions for spacing (temporal and spatial) subs = dict([(t.spacing, dt)] + [(time.spacing, dt)] + [(i.spacing, model.get_spacing()[j]) for i, j in zip(u.indices[1:], range(len(model.shape)))]) # Operator return Operator(stencils, subs=subs, name='ForwardTTI', **kwargs)
def ForwardOperator(model, source, receiver, time_order=2, space_order=4, save=False, **kwargs): """ Constructor method for the forward 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 :param save: Saving flag, True saves all time steps, False only the three """ m, damp = model.m, model.damp # Create symbols for forward wavefield, source and receivers u = TimeData(name='u', shape=model.shape_domain, dtype=model.dtype, save=save, time_dim=source.nt if save else None, time_order=time_order, space_order=space_order) src = PointSource(name='src', 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 = u.laplace2(1 / m) dt = 1.73 * model.critical_dt # Derive both stencils from symbolic equation: # Create the stencil by hand instead of calling numpy solve for speed purposes # Simple linear solve of a u(t+dt) + b u(t) + c u(t-dt) = L for u(t+dt) s = t.spacing stencil = 1.0 / (2.0 * m + s * damp) * ( 4.0 * m * u + (s * damp - 2.0 * m) * u.backward + 2.0 * s**2 * (u.laplace + s**2 / 12.0 * biharmonic)) eqn = [Eq(u.forward, stencil)] # Construct expression to inject source values src_term = src.inject(field=u.forward, expr=src * dt**2 / m, offset=model.nbpml) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u, offset=model.nbpml) subs = dict([(t.spacing, dt)] + [(time.spacing, dt)] + [(i.spacing, model.get_spacing()[j]) for i, j in zip(u.indices[1:], range(len(model.shape)))]) return Operator(eqn + src_term + rec_term, subs=subs, time_axis=Forward, name='Forward', **kwargs)
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
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)
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 receiver = Receiver(name='rec', grid=model.grid, time_range=time_axis, coordinates=rec_coordinates, npoint=nreceivers) rec_term = receiver.interpolate(expr=u) receivers.append(receiver) # operator op_fwd = Operator(eqn + src_term + rec_term, subs=model.spacing_map, name='Forward') op_fwd.apply(src=src_true, rec=receiver, u=u0_man, vp=model.vp, dt=model.critical_dt) def fwi_gradient(vp_in):
# Set symbolics for the wavefield object `u`, setting save on all time steps # (which can occupy a lot of memory), to later collect snapshots (naive method): u = TimeFunction(name="u", grid=model.grid, time_order=2, space_order=2, save=time_range.num) # Set symbolics of the operator, source and receivers: 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.nbpml) rec_term = rec.interpolate(expr=u, offset=model.nbpml) op = Operator([stencil] + src_term + rec_term, subs=model.spacing_map) # Run the operator for `(nt-2)` time steps: op(time=nt - 2, dt=model.critical_dt) ######################################################################################################### #NBVAL_IGNORE_OUTPUT from devito import ConditionalDimension nsnaps = 100 # desired number of equally spaced snaps factor = round(nt / nsnaps) # subsequent calculated factor print(f"factor is {factor}")
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