def __init__(self, model, src, damp, data, time_order=2, spc_order=6, save=False, **kwargs): nrec, nt = data.shape dt = model.get_critical_dt() u = TimeData(name="u", shape=model.get_shape_comp(), time_dim=nt, time_order=time_order, space_order=spc_order, save=save, dtype=damp.dtype) m = DenseData(name="m", shape=model.get_shape_comp(), dtype=damp.dtype) m.data[:] = model.padm() u.pad_time = save rec = SourceLike(name="rec", npoint=nrec, nt=nt, dt=dt, h=model.get_spacing(), coordinates=data.receiver_coords, ndim=len(damp.shape), dtype=damp.dtype, nbpml=model.nbpml) # Derive stencil from symbolic equation eqn = m * u.dt2 - u.laplace + damp * u.dt stencil = solve(eqn, u.forward)[0] # Add substitutions for spacing (temporal and spatial) s, h = symbols('s h') subs = {s: dt, h: model.get_spacing()} super(ForwardOperator, self).__init__(nt, m.shape, stencils=Eq(u.forward, stencil), subs=subs, spc_border=spc_order / 2, time_order=time_order, forward=True, dtype=m.dtype, **kwargs) # Insert source and receiver terms post-hoc self.input_params += [src, src.coordinates, rec, rec.coordinates] self.output_params += [rec] self.propagator.time_loop_stencils_a = src.add(m, u) + rec.read(u) self.propagator.add_devito_param(src) self.propagator.add_devito_param(src.coordinates) self.propagator.add_devito_param(rec) self.propagator.add_devito_param(rec.coordinates)
def born(self, dmin, src=None, rec=None, u=None, U=None, m=None, **kwargs): """ Linearized Born modelling function that creates the necessary data objects for running an adjoint modelling operator. :param src: Symbol with time series data for the injected source term :param rec: Symbol to store interpolated receiver data :param u: (Optional) Symbol to store the computed wavefield :param U: (Optional) Symbol to store the computed wavefield :param m: (Optional) Symbol for the time-constant square slowness """ # Source term is read-only, so re-use the default if src is None: src = self.source # Create a new receiver object to store the result if rec is None: rec = rec or Receiver(name='rec', ntime=self.receiver.nt, coordinates=self.receiver.coordinates.data) # Create the forward wavefields u and U if not provided if u is None: u = TimeData(name='u', shape=self.model.shape_domain, save=False, time_order=self.time_order, space_order=self.space_order, dtype=self.model.dtype) if U is None: U = TimeData(name='U', shape=self.model.shape_domain, save=False, time_order=self.time_order, space_order=self.space_order, dtype=self.model.dtype) # Pick m from model unless explicitly provided if m is None: m = self.model.m # Execute operator and return wavefield and receiver data summary = self.op_born.apply(dm=dmin, u=u, U=U, src=src, rec=rec, m=m, **kwargs) return rec, u, U, summary
def __init__(self, m, rec, damp, srca, time_order=4, spc_order=12): assert(m.shape == damp.shape) input_params = [m, rec, damp, srca] v = TimeData("v", m.shape, rec.nt, time_order=time_order, save=True, dtype=m.dtype) output_params = [v] dim = len(m.shape) total_dim = self.total_dim(dim) space_dim = self.space_dim(dim) lhs = v.indexed[total_dim] stencil, subs = self._init_taylor(dim, time_order, spc_order)[1] stencil = self.smart_sympy_replace(dim, time_order, stencil, Function('p'), v, fw=False) main_stencil = Eq(lhs, stencil) stencil_args = [m.indexed[space_dim], rec.dt, rec.h, damp.indexed[space_dim]] stencils = [main_stencil] substitutions = [dict(zip(subs, stencil_args))] super(AdjointOperator, self).__init__(rec.nt, m.shape, stencils=stencils, subs=substitutions, spc_border=spc_order/2, time_order=time_order, forward=False, dtype=m.dtype, input_params=input_params, output_params=output_params) # Insert source and receiver terms post-hoc self.propagator.time_loop_stencils_a = rec.add(m, v) + srca.read(v)
def run_simulation(save=False, dx=0.01, dy=0.01, a=0.5, timesteps=100): nx, ny = int(1 / dx), int(1 / dy) dx2, dy2 = dx**2, dy**2 dt = dx2 * dy2 / (2 * a * (dx2 + dy2)) u = TimeData(name='u', shape=(nx, ny), time_dim=timesteps, initializer=initializer, time_order=1, space_order=2, save=save, pad_time=save) a, h, s = symbols('a h s') eqn = Eq(u.dt, a * (u.dx2 + u.dy2)) stencil = solve(eqn, u.forward)[0] op = Operator(stencils=Eq(u.forward, stencil), subs={ a: 0.5, h: dx, s: dt }, nt=timesteps, shape=(nx, ny), spc_border=1, time_order=1) op.apply() if save: return u.data[timesteps - 1, :] else: return u.data[timesteps % 2, :]
def __init__(self, dm, m, src, damp, rec, time_order=4, spc_order=12): assert(m.shape == damp.shape) input_params = [dm, m, src, damp, rec] u = TimeData("u", m.shape, src.nt, time_order=time_order, save=False, dtype=m.dtype) U = TimeData("U", m.shape, src.nt, time_order=time_order, save=False, dtype=m.dtype) output_params = [u, U] dim = len(m.shape) total_dim = self.total_dim(dim) space_dim = self.space_dim(dim) dt = src.dt h = src.h stencil, subs = self._init_taylor(dim, time_order, spc_order)[0] first_stencil = self.smart_sympy_replace(dim, time_order, stencil, Function('p'), u, fw=True) second_stencil = self.smart_sympy_replace(dim, time_order, stencil, Function('p'), U, fw=True) first_stencil_args = [m.indexed[space_dim], dt, h, damp.indexed[space_dim]] first_update = Eq(u.indexed[total_dim], u.indexed[total_dim]+first_stencil) src2 = (-(dt**-2)*(u.indexed[total_dim]-2*u.indexed[tuple((t - 1,) + space_dim)] + u.indexed[tuple((t - 2,) + space_dim)])*dm.indexed[space_dim]) second_stencil_args = [m.indexed[space_dim], dt, h, damp.indexed[space_dim]] second_update = Eq(U.indexed[total_dim], second_stencil) insert_second_source = Eq(U.indexed[total_dim], U.indexed[total_dim] + (dt*dt)/m.indexed[space_dim]*src2) reset_u = Eq(u.indexed[tuple((t - 2,) + space_dim)], 0) stencils = [first_update, second_update, insert_second_source, reset_u] substitutions = [dict(zip(subs, first_stencil_args)), dict(zip(subs, second_stencil_args)), {}, {}] super(BornOperator, self).__init__(src.nt, m.shape, stencils=stencils, subs=substitutions, spc_border=spc_order/2, time_order=time_order, forward=True, dtype=m.dtype, input_params=input_params, output_params=output_params) # Insert source and receiver terms post-hoc self.propagator.time_loop_stencils_b = src.add(m, u) self.propagator.time_loop_stencils_a = rec.read(U)
def forward(self, src=None, rec=None, u=None, m=None, save=False, **kwargs): """ Forward modelling function that creates the necessary data objects for running a forward modelling operator. :param src: Symbol with time series data for the injected source term :param rec: Symbol to store interpolated receiver data :param u: (Optional) Symbol to store the computed wavefield :param m: (Optional) Symbol for the time-constant square slowness :param save: Option to store the entire (unrolled) wavefield :returns: Receiver, wavefield and performance summary """ # Source term is read-only, so re-use the default if src is None: src = self.source # Create a new receiver object to store the result if rec is None: rec = Receiver(name='rec', ntime=self.receiver.nt, coordinates=self.receiver.coordinates.data) # Create the forward wavefield if not provided if u is None: u = TimeData(name='u', shape=self.model.shape_domain, save=save, time_dim=self.source.nt, time_order=self.time_order, space_order=self.space_order, dtype=self.model.dtype) # Pick m from model unless explicitly provided if m is None: m = m or self.model.m # Execute operator and return wavefield and receiver data if save: summary = self.op_fwd_save.apply(src=src, rec=rec, u=u, m=m, **kwargs) else: summary = self.op_fwd.apply(src=src, rec=rec, u=u, m=m, **kwargs) return rec, u, summary
def gradient(self, rec, u, v=None, grad=None, m=None, **kwargs): """ Gradient modelling function for computing the adjoint of the Linearized Born modelling function, ie. the action of the Jacobian adjoint on an input data. :param recin: Receiver data as a numpy array :param u: Symbol for full wavefield `u` (created with save=True) :param v: (Optional) Symbol to store the computed wavefield :param grad: (Optional) Symbol to store the gradient field :returns: Gradient field and performance summary """ # Gradient symbol if grad is None: grad = DenseData(name='grad', shape=self.model.shape_domain, dtype=self.model.dtype) # Create the forward wavefield if v is None: v = TimeData(name='v', shape=self.model.shape_domain, save=False, time_dim=self.source.nt, time_order=self.time_order, space_order=self.space_order, dtype=self.model.dtype) # Pick m from model unless explicitly provided if m is None: m = m or self.model.m summary = self.op_grad.apply(rec=rec, grad=grad, v=v, u=u, m=m, **kwargs) return grad, summary
def __init__(self, u, m, rec, damp, time_order=4, spc_order=12): assert(m.shape == damp.shape) input_params = [u, m, rec, damp] v = TimeData("v", m.shape, rec.nt, time_order=time_order, save=False, dtype=m.dtype) grad = DenseData("grad", m.shape, dtype=m.dtype) output_params = [grad, v] dim = len(m.shape) total_dim = self.total_dim(dim) space_dim = self.space_dim(dim) lhs = v.indexed[total_dim] stencil, subs = self._init_taylor(dim, time_order, spc_order)[1] stencil = self.smart_sympy_replace(dim, time_order, stencil, Function('p'), v, fw=False) stencil_args = [m.indexed[space_dim], rec.dt, rec.h, damp.indexed[space_dim]] main_stencil = Eq(lhs, lhs + stencil) gradient_update = Eq(grad.indexed[space_dim], grad.indexed[space_dim] - (v.indexed[total_dim] - 2 * v.indexed[tuple((t + 1,) + space_dim)] + v.indexed[tuple((t + 2,) + space_dim)]) * u.indexed[total_dim]) reset_v = Eq(v.indexed[tuple((t + 2,) + space_dim)], 0) stencils = [main_stencil, gradient_update, reset_v] substitutions = [dict(zip(subs, stencil_args)), {}, {}] super(GradientOperator, self).__init__(rec.nt, m.shape, stencils=stencils, subs=substitutions, spc_border=spc_order/2, time_order=time_order, forward=False, dtype=m.dtype, input_params=input_params, output_params=output_params) # Insert source and receiver terms post-hoc self.propagator.time_loop_stencils_b = rec.add(m, v)
def _new_operator2(shape, time_order, **kwargs): infield = TimeData(name='in', shape=shape, time_order=time_order, dtype=np.int32) infield.data[:] = np.arange(reduce(mul, shape), dtype=np.int32).reshape(shape) outfield = TimeData(name='out', shape=shape, time_order=time_order, dtype=np.int32) stencil = Eq(outfield.forward.indexify(), outfield.indexify() + infield.indexify() * 3.0) # Run the operator Operator(stencil, **kwargs)(infield, outfield, t=10) return outfield
def adjoint(self, rec, srca=None, v=None, m=None, **kwargs): """ Adjoint modelling function that creates the necessary data objects for running an adjoint modelling operator. :param rec: Symbol with stored receiver data. Please note that these act as the source term in the adjoint run. :param srca: Symbol to store the resulting data for the interpolated at the original source location. :param v: (Optional) Symbol to store the computed wavefield :param m: (Optional) Symbol for the time-constant square slowness :returns: Adjoint source, wavefield and performance summary """ # Create a new adjoint source and receiver symbol if srca is None: srca = PointSource(name='srca', ntime=self.source.nt, coordinates=self.source.coordinates.data) # Create the adjoint wavefield if not provided if v is None: v = TimeData(name='v', shape=self.model.shape_domain, save=False, time_order=self.time_order, space_order=self.space_order, dtype=self.model.dtype) # Pick m from model unless explicitly provided if m is None: m = self.model.m # Execute operator and return wavefield and receiver data summary = self.op_adj.apply(srca=srca, rec=rec, v=v, m=m, **kwargs) return srca, v, summary
def __init__(self, model, damp, data, recin, time_order=2, spc_order=6, **kwargs): nrec, nt = data.shape dt = model.get_critical_dt() v = TimeData(name="v", shape=model.get_shape_comp(), time_dim=nt, time_order=time_order, space_order=spc_order, save=False, dtype=damp.dtype) m = DenseData(name="m", shape=model.get_shape_comp(), dtype=damp.dtype) m.data[:] = model.padm() v.pad_time = False srca = SourceLike( name="srca", npoint=1, nt=nt, dt=dt, h=model.get_spacing(), coordinates=np.array(data.source_coords, dtype=damp.dtype)[np.newaxis, :], ndim=len(damp.shape), dtype=damp.dtype, nbpml=model.nbpml) rec = SourceLike(name="rec", npoint=nrec, nt=nt, dt=dt, h=model.get_spacing(), coordinates=data.receiver_coords, ndim=len(damp.shape), dtype=damp.dtype, nbpml=model.nbpml) rec.data[:] = recin[:] # Derive stencil from symbolic equation eqn = m * v.dt2 - v.laplace - damp * v.dt stencil = solve(eqn, v.backward)[0] # Add substitutions for spacing (temporal and spatial) s, h = symbols('s h') subs = {s: model.get_critical_dt(), h: model.get_spacing()} super(AdjointOperator, self).__init__(nt, m.shape, stencils=Eq(v.backward, stencil), subs=subs, spc_border=spc_order / 2, time_order=time_order, forward=False, dtype=m.dtype, **kwargs) # Insert source and receiver terms post-hoc self.input_params += [srca, srca.coordinates, rec, rec.coordinates] self.propagator.time_loop_stencils_a = rec.add(m, v) + srca.read(v) self.output_params = [srca] self.propagator.add_devito_param(srca) self.propagator.add_devito_param(srca.coordinates) self.propagator.add_devito_param(rec) self.propagator.add_devito_param(rec.coordinates)
def __init__(self, model, src, damp, data, dmin, time_order=2, spc_order=6, **kwargs): nrec, nt = data.shape dt = model.get_critical_dt() u = TimeData(name="u", shape=model.get_shape_comp(), time_dim=nt, time_order=time_order, space_order=spc_order, save=False, dtype=damp.dtype) U = TimeData(name="U", shape=model.get_shape_comp(), time_dim=nt, time_order=time_order, space_order=spc_order, save=False, dtype=damp.dtype) m = DenseData(name="m", shape=model.get_shape_comp(), dtype=damp.dtype) m.data[:] = model.padm() dm = DenseData(name="dm", shape=model.get_shape_comp(), dtype=damp.dtype) dm.data[:] = model.pad(dmin) rec = SourceLike(name="rec", npoint=nrec, nt=nt, dt=dt, h=model.get_spacing(), coordinates=data.receiver_coords, ndim=len(damp.shape), dtype=damp.dtype, nbpml=model.nbpml) # Derive stencils from symbolic equation first_eqn = m * u.dt2 - u.laplace - damp * u.dt first_stencil = solve(first_eqn, u.forward)[0] second_eqn = m * U.dt2 - U.laplace - damp * U.dt second_stencil = solve(second_eqn, U.forward)[0] # Add substitutions for spacing (temporal and spatial) s, h = symbols('s h') subs = {s: src.dt, h: src.h} # Add Born-specific updates and resets src2 = -(src.dt**-2) * (-2 * u + u.forward + u.backward) * dm insert_second_source = Eq(U, U + (src.dt * src.dt) / m * src2) stencils = [ Eq(u.forward, first_stencil), Eq(U.forward, second_stencil), insert_second_source ] super(BornOperator, self).__init__(src.nt, m.shape, stencils=stencils, subs=[subs, subs, {}, {}], spc_border=spc_order / 2, time_order=time_order, forward=True, dtype=m.dtype, **kwargs) # Insert source and receiver terms post-hoc self.input_params += [ dm, src, src.coordinates, rec, rec.coordinates, U ] self.output_params = [rec] self.propagator.time_loop_stencils_b = src.add(m, u, t - 1) self.propagator.time_loop_stencils_a = rec.read(U) self.propagator.add_devito_param(dm) self.propagator.add_devito_param(src) self.propagator.add_devito_param(src.coordinates) self.propagator.add_devito_param(rec) self.propagator.add_devito_param(rec.coordinates) self.propagator.add_devito_param(U)
def __init__(self, model, damp, data, recin, u, time_order=2, spc_order=6, **kwargs): nrec, nt = data.shape dt = model.get_critical_dt() v = TimeData(name="v", shape=model.get_shape_comp(), time_dim=nt, time_order=time_order, space_order=spc_order, save=False, dtype=damp.dtype) m = DenseData(name="m", shape=model.get_shape_comp(), dtype=damp.dtype) m.data[:] = model.padm() v.pad_time = False rec = SourceLike(name="rec", npoint=nrec, nt=nt, dt=dt, h=model.get_spacing(), coordinates=data.receiver_coords, ndim=len(damp.shape), dtype=damp.dtype, nbpml=model.nbpml) rec.data[:] = recin grad = DenseData(name="grad", shape=m.shape, dtype=m.dtype) # Derive stencil from symbolic equation eqn = m * v.dt2 - v.laplace - damp * v.dt stencil = solve(eqn, v.backward)[0] # Add substitutions for spacing (temporal and spatial) s, h = symbols('s h') subs = {s: model.get_critical_dt(), h: model.get_spacing()} # Add Gradient-specific updates. The dt2 is currently hacky # as it has to match the cyclic indices gradient_update = Eq( grad, grad - s**-2 * (v + v.forward - 2 * v.forward.forward) * u.forward) stencils = [gradient_update, Eq(v.backward, stencil)] super(GradientOperator, self).__init__(rec.nt - 1, m.shape, stencils=stencils, subs=[subs, subs, {}], spc_border=spc_order / 2, time_order=time_order, forward=False, dtype=m.dtype, input_params=[m, v, damp, u], **kwargs) # Insert receiver term post-hoc self.input_params += [grad, rec, rec.coordinates] self.output_params = [grad] self.propagator.time_loop_stencils_b = rec.add(m, v, t + 1) self.propagator.add_devito_param(rec) self.propagator.add_devito_param(rec.coordinates)
def ForwardOperator(model, u, src, rec, data, q, time_order=2, spc_order=6, save=False, tsave=4.0, free_surface=False, **kwargs): nt = data.shape[0] dt = model.critical_dt s = t.spacing m, damp, rho = model.m, model.damp, model.rho Lap, rho = acoustic_laplacian(u, rho) # Derive stencil from symbolic equation eqn = m / rho * u.dt2 - Lap + damp * u.dt + q # stencil = solve(eqn, u.forward)[0] stencil = solve(eqn, u.forward, rational=False)[0] # Add substitutions for spacing (temporal and spatial) subs = dict([(s, dt)] + [(i.spacing, model.get_spacing()[j]) for i, j in zip(u.indices[1:], range(len(model.shape)))]) stencils = [Eq(u.forward, stencil)] # Create stencil expressions for operator, source and receivers ti = u.indices[0] src_term = src.inject(field=u.forward, offset=model.nbpml, expr=rho * src * dt**2 / m) # Create interpolation expression for receivers rec_term = rec.interpolate(expr=u, offset=model.nbpml) stencils = stencils + src_term + rec_term if save: nsave = int(nt / (tsave / dt) + 1) rate = int(nt / nsave) + 1 usave = TimeData(name="usave", shape=model.shape_domain, time_dim=nt, time_order=2, space_order=spc_order, save=True, dtype=model.dtype) stencils += [ Eq(usave.subs(usave.indices[0], Function('INT')(time / rate)), u) ] if free_surface: fs = Dimension(name="fs", size=model.nbpml) stencils += [ Eq(u.forward.subs({u.indices[-1]: fs}), -u.forward.subs({u.indices[-1]: 2 * model.nbpml - fs})) ] dse = kwargs.get('dse', 'advanced') dle = kwargs.get('dle', 'advanced') op = Operator(stencils, subs=subs, dse=dse, dle=dle, time_axis=Forward, name="Forward%s" % randint(1e5), profiler=False, external=True) return op
def __init__(self, model, src, damp, data, time_order=2, spc_order=4, save=False, **kwargs): nrec, nt = data.shape dt = model.get_critical_dt() u = TimeData(name="u", shape=model.get_shape_comp(), time_dim=nt, time_order=time_order, space_order=spc_order, save=save, dtype=damp.dtype) v = TimeData(name="v", shape=model.get_shape_comp(), time_dim=nt, time_order=time_order, space_order=spc_order, save=save, dtype=damp.dtype) m = DenseData(name="m", shape=model.get_shape_comp(), dtype=damp.dtype) m.data[:] = model.padm() if model.epsilon is not None: epsilon = DenseData(name="epsilon", shape=model.get_shape_comp(), dtype=damp.dtype) epsilon.data[:] = model.pad(model.epsilon) else: epsilon = 1.0 if model.delta is not None: delta = DenseData(name="delta", shape=model.get_shape_comp(), dtype=damp.dtype) delta.data[:] = model.pad(model.delta) else: delta = 1.0 if model.theta is not None: theta = DenseData(name="theta", shape=model.get_shape_comp(), dtype=damp.dtype) theta.data[:] = model.pad(model.theta) else: theta = 0 if len(model.get_shape_comp()) == 3: if model.phi is not None: phi = DenseData(name="phi", shape=model.get_shape_comp(), dtype=damp.dtype) phi.data[:] = model.pad(model.phi) else: phi = 0 u.pad_time = save v.pad_time = save rec = SourceLike(name="rec", npoint=nrec, nt=nt, dt=dt, h=model.get_spacing(), coordinates=data.receiver_coords, ndim=len(damp.shape), dtype=damp.dtype, nbpml=model.nbpml) def Bhaskarasin(angle): if angle == 0: return 0 else: return (16.0 * angle * (3.1416 - abs(angle)) / (49.3483 - 4.0 * abs(angle) * (3.1416 - abs(angle)))) def Bhaskaracos(angle): if angle == 0: return 1.0 else: return Bhaskarasin(angle + 1.5708) Hp, Hzr = symbols('Hp Hzr') if len(m.shape) == 3: ang0 = Function('ang0')(x, y, z) ang1 = Function('ang1')(x, y, z) ang2 = Function('ang2')(x, y, z) ang3 = Function('ang3')(x, y, z) else: ang0 = Function('ang0')(x, y) ang1 = Function('ang1')(x, y) s, h = symbols('s h') ang0 = Bhaskaracos(theta) ang1 = Bhaskarasin(theta) spc_brd = spc_order / 2 # Derive stencil from symbolic equation if len(m.shape) == 3: ang2 = Bhaskaracos(phi) ang3 = Bhaskarasin(phi) Gy1p = (ang3 * u.dxl - ang2 * u.dyl) Gyy1 = (first_derivative(Gy1p, ang3, dim=x, side=right, order=spc_brd) - first_derivative(Gy1p, ang2, dim=y, side=right, order=spc_brd)) Gy2p = (ang3 * u.dxr - ang2 * u.dyr) Gyy2 = (first_derivative(Gy2p, ang3, dim=x, side=left, order=spc_brd) - first_derivative(Gy2p, ang2, dim=y, side=left, order=spc_brd)) Gx1p = (ang0 * ang2 * u.dxl + ang0 * ang3 * u.dyl - ang1 * u.dzl) Gz1r = (ang1 * ang2 * v.dxl + ang1 * ang3 * v.dyl + ang0 * v.dzl) Gxx1 = (first_derivative(Gx1p, ang0, ang2, dim=x, side=right, order=spc_brd) + first_derivative(Gx1p, ang0, ang3, dim=y, side=right, order=spc_brd) - first_derivative(Gx1p, ang1, dim=z, side=right, order=spc_brd)) Gzz1 = (first_derivative(Gz1r, ang1, ang2, dim=x, side=right, order=spc_brd) + first_derivative(Gz1r, ang1, ang3, dim=y, side=right, order=spc_brd) + first_derivative(Gz1r, ang0, dim=z, side=right, order=spc_brd)) Gx2p = (ang0 * ang2 * u.dxr + ang0 * ang3 * u.dyr - ang1 * u.dzr) Gz2r = (ang1 * ang2 * v.dxr + ang1 * ang3 * v.dyr + ang0 * v.dzr) Gxx2 = (first_derivative(Gx2p, ang0, ang2, dim=x, side=left, order=spc_brd) + first_derivative(Gx2p, ang0, ang3, dim=y, side=left, order=spc_brd) - first_derivative(Gx2p, ang1, dim=z, side=left, order=spc_brd)) Gzz2 = (first_derivative(Gz2r, ang1, ang2, dim=x, side=left, order=spc_brd) + first_derivative(Gz2r, ang1, ang3, dim=y, side=left, order=spc_brd) + first_derivative(Gz2r, ang0, dim=z, side=left, order=spc_brd)) parm = [m, damp, epsilon, delta, theta, phi, u, v] else: Gyy2 = 0 Gyy1 = 0 parm = [m, damp, epsilon, delta, theta, u, v] Gx1p = (ang0 * u.dxr - ang1 * u.dy) Gz1r = (ang1 * v.dxr + ang0 * v.dy) Gxx1 = (first_derivative(Gx1p * ang0, dim=x, side=left, order=spc_brd) - first_derivative(Gx1p * ang1, dim=y, side=centered, order=spc_brd)) Gzz1 = (first_derivative(Gz1r * ang1, dim=x, side=left, order=spc_brd) + first_derivative(Gz1r * ang0, dim=y, side=centered, order=spc_brd)) Gx2p = (ang0 * u.dx - ang1 * u.dyr) Gz2r = (ang1 * v.dx + ang0 * v.dyr) Gxx2 = (first_derivative(Gx2p * ang0, dim=x, side=centered, order=spc_brd) - first_derivative(Gx2p * ang1, dim=y, side=left, order=spc_brd)) Gzz2 = (first_derivative(Gz2r * ang1, dim=x, side=centered, order=spc_brd) + first_derivative(Gz2r * ang0, dim=y, side=left, order=spc_brd)) 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)) Hp_val = -(.5 * Gxx1 + .5 * Gxx2 + .5 * Gyy1 + .5 * Gyy2) Hzr_val = -(.5 * Gzz1 + .5 * Gzz2) factorized = {Hp: Hp_val, Hzr: Hzr_val} # Add substitutions for spacing (temporal and spatial) subs = [{s: src.dt, h: src.h}, {s: src.dt, h: src.h}] first_stencil = Eq(u.forward, stencilp.xreplace(factorized)) second_stencil = Eq(v.forward, stencilr.xreplace(factorized)) stencils = [first_stencil, second_stencil] super(ForwardOperator, self).__init__(src.nt, m.shape, stencils=stencils, subs=subs, spc_border=spc_order/2 + 2, time_order=time_order, forward=True, dtype=m.dtype, input_params=parm, **kwargs) # Insert source and receiver terms post-hoc self.input_params += [src, src.coordinates, rec, rec.coordinates] self.output_params += [v, rec] self.propagator.time_loop_stencils_a = (src.add(m, u) + src.add(m, v) + rec.read2(u, v)) self.propagator.add_devito_param(src) self.propagator.add_devito_param(src.coordinates) self.propagator.add_devito_param(rec) self.propagator.add_devito_param(rec.coordinates)