Esempio n. 1
0
    def test_irregular_write(self):
        """
        Compute a simple stencil S w/o offloading it to YASK because of the presence
        of indirect write accesses (e.g. A[B[i]] = ...); YASK grid functions are however
        used in the generated code to access the data at the right location. This
        test checks that the numerical output is correct after this transformation.

        Initially, the input array (a YASK grid, under the hood), at t=0 is (2D view):

            0 1 2 3
            0 1 2 3
            0 1 2 3
            0 1 2 3

        Then, the Operator "flips" its content, and at timestep t=1 we get (2D view):

            3 2 1 0
            3 2 1 0
            3 2 1 0
            3 2 1 0
        """
        p = PointData(name='points', nt=1, npoint=4)
        u = TimeData(name='yu4D', shape=(4, 4, 4), dimensions=(x, y, z), space_order=0)
        for i in range(4):
            for j in range(4):
                for k in range(4):
                    u.data[0, i, j, k] = k
        ind = lambda i: p.indexed[0, i]
        eqs = [Eq(p.indexed[0, 0], 3.), Eq(p.indexed[0, 1], 2.),
               Eq(p.indexed[0, 2], 1.), Eq(p.indexed[0, 3], 0.),
               Eq(u.indexed[t + 1, ind(x), ind(y), ind(z)], u.indexed[t, x, y, z])]
        op = Operator(eqs, subs={t.spacing: 1})
        op(yu4D=u, t=1)
        assert 'run_solution' not in str(op)
        assert all(np.all(u.data[1, :, :, i] == 3 - i) for i in range(4))
Esempio n. 2
0
def execute_devito(ui, spacing=0.01, a=0.5, timesteps=500):
    """Execute diffusion stencil using the devito Operator API."""
    nx, ny = ui.shape
    dx2, dy2 = spacing**2, spacing**2
    dt = dx2 * dy2 / (2 * a * (dx2 + dy2))
    # Allocate the grid and set initial condition
    # Note: This should be made simpler through the use of defaults
    u = TimeData(name='u', shape=(nx, ny), time_order=1, space_order=2)
    u.data[0, :] = ui[:]

    # Derive the stencil according to devito conventions
    eqn = Eq(u.dt, a * (u.dx2 + u.dy2))
    stencil = solve(eqn, u.forward)[0]
    op = Operator(stencils=Eq(u.forward, stencil),
                  subs={
                      h: spacing,
                      s: dt
                  },
                  nt=timesteps,
                  shape=(nx, ny),
                  spc_border=1,
                  time_order=1)
    # Execute the generated Devito stencil operator
    tstart = time.time()
    op.apply()
    runtime = time.time() - tstart
    log("Devito: Diffusion with dx=%0.4f, dy=%0.4f, executed %d timesteps in %f seconds"
        % (spacing, spacing, timesteps, runtime))
    return u.data[1, :], runtime
Esempio n. 3
0
    def test_multiple_loop_nests(self):
        """
        Compute a simple stencil S, preceded by an "initialization loop" I and
        followed by a "random loop" R.

            * S is the trivial equation ``u[t+1,x,y,z] = u[t,x,y,z] + 1``;
            * I initializes ``u`` to 0;
            * R adds 2 to another field ``v`` along the ``z`` dimension but only
                over the planes ``[x=0, y=2]`` and ``[x=0, y=5]``.

        Out of these three loop nests, only S should be "offloaded" to YASK; indeed,
        I is outside the time loop, while R does not loop over space dimensions.
        This test checks that S is the only loop nest "offloaded" to YASK, and
        that the numerical output is correct.
        """
        u = TimeData(name='yu4D', shape=(12, 12, 12), dimensions=(x, y, z),
                     space_order=0)
        v = TimeData(name='yv4D', shape=(12, 12, 12), dimensions=(x, y, z),
                     space_order=0)
        v.data[:] = 0.
        eqs = [Eq(u.indexed[0, x, y, z], 0),
               Eq(u.indexed[1, x, y, z], 0),
               Eq(u.forward, u + 1.),
               Eq(v.indexed[t + 1, 0, 2, z], v.indexed[t + 1, 0, 2, z] + 2.),
               Eq(v.indexed[t + 1, 0, 5, z], v.indexed[t + 1, 0, 5, z] + 2.)]
        op = Operator(eqs, subs={t.spacing: 1})
        op(yu4D=u, yv4D=v, t=1)
        assert 'run_solution' in str(op)
        assert len(retrieve_iteration_tree(op)) == 3
        assert np.all(u.data[0] == 0.)
        assert np.all(u.data[1] == 1.)
        assert np.all(v.data[0] == 0.)
        assert np.all(v.data[1, 0, 2] == 2.)
        assert np.all(v.data[1, 0, 5] == 2.)
Esempio n. 4
0
    def Born(self,
             save=False,
             cache_blocking=None,
             auto_tuning=False,
             dse='advanced',
             dle='advanced',
             compiler=None,
             free_surface=False):
        """Linearized modelling of one or multiple point source from
        an input model perturbation.
        """
        nt, nrec = self.data.shape
        nsrc = self.source.shape[1]
        ndim = len(self.model.shape)
        h = self.model.get_spacing()
        dtype = self.model.dtype
        nbpml = self.model.nbpml

        # Create source symbol
        src = PointSource(name='src',
                          ntime=self.source.nt,
                          coordinates=self.source.receiver_coords)
        # Create receiver symbol
        Linrec = Receiver(name='Lrec',
                          ntime=self.data.nt,
                          coordinates=self.data.receiver_coords)

        # Create the forward wavefield
        u = TimeData(name="u",
                     shape=self.model.shape_domain,
                     time_dim=nt,
                     time_order=2,
                     space_order=self.s_order,
                     dtype=self.model.dtype)
        du = TimeData(name="du",
                      shape=self.model.shape_domain,
                      time_dim=nt,
                      time_order=2,
                      space_order=self.s_order,
                      dtype=self.model.dtype)

        dm = DenseData(name="dm",
                       shape=self.model.shape_domain,
                       dtype=self.model.dtype)
        # Execute operator and return wavefield and receiver data
        born = BornOperator(self.model,
                            u,
                            du,
                            src,
                            Linrec,
                            dm,
                            self.data,
                            time_order=self.t_order,
                            spc_order=self.s_order,
                            cache_blocking=cache_blocking,
                            dse=dse,
                            dle=dle,
                            free_surface=free_surface)
        return born
Esempio n. 5
0
    def Forward(self,
                save=False,
                dse='advanced',
                dle='advanced',
                q=False,
                free_surface=False):

        nt, nrec = self.data.shape
        nsrc = self.source.shape[1]
        ndim = len(self.model.shape)
        h = self.model.get_spacing()
        dtype = self.model.dtype
        nbpml = self.model.nbpml
        # Create source symbol
        src = PointSource(name='src',
                          ntime=self.source.nt,
                          coordinates=self.source.receiver_coords)
        # Create receiver symbol
        rec = Receiver(name='rec',
                       ntime=self.data.nt,
                       coordinates=self.data.receiver_coords)
        # Create the forward wavefield
        u = TimeData(name="u",
                     shape=self.model.shape_domain,
                     time_dim=nt,
                     time_order=2,
                     space_order=self.s_order,
                     save=False,
                     dtype=self.model.dtype)

        if q:
            qfull = TimeData(name="qfull",
                             shape=self.model.shape_domain,
                             time_dim=nt,
                             time_order=2,
                             space_order=self.s_order,
                             save=True,
                             dtype=self.model.dtype)
        else:
            qfull = 0
        # Execute operator and return wavefield and receiver data
        fw = ForwardOperator(self.model,
                             u,
                             src,
                             rec,
                             self.data,
                             qfull,
                             time_order=self.t_order,
                             spc_order=self.s_order,
                             save=save,
                             dse=dse,
                             dle=dle,
                             tsave=self.tsave,
                             free_surface=free_surface)

        return fw
Esempio n. 6
0
def test_second_derivatives_space(derivative, dimension, order):
    """Test second derivative expressions against native sympy"""
    u = TimeData(name='u', shape=(20, 20, 20), time_order=2, space_order=order)
    expr = getattr(u, derivative)
    # Establish native sympy derivative expression
    width = int(order / 2)
    indices = [(dimension + i * h) for i in range(-width, width + 1)]
    s_expr = as_finite_diff(u.diff(dimension, dimension), indices)
    assert (simplify(expr - s_expr) == 0)  # Symbolic equality
    assert (expr == s_expr)  # Exact equailty
Esempio n. 7
0
    def Gradient(self,
                 cache_blocking=None,
                 auto_tuning=False,
                 dle='advanced',
                 dse='advanced',
                 compiler=None,
                 free_surface=False):
        """FWI gradient from back-propagation of a shot record
        and input forward wavefield
        """
        nt, nrec = self.data.shape
        ndim = len(self.model.shape)
        h = self.model.get_spacing()
        dtype = self.model.dtype
        nbpml = self.model.nbpml

        # Create receiver symbol
        rec = Receiver(name='rec',
                       ntime=self.data.nt,
                       coordinates=self.data.receiver_coords)
        # Gradient symbol
        grad = DenseData(name="grad",
                         shape=self.model.shape_domain,
                         dtype=self.model.dtype)

        # Create the forward wavefield
        v = TimeData(name="v",
                     shape=self.model.shape_domain,
                     time_dim=nt,
                     time_order=2,
                     space_order=self.s_order,
                     dtype=self.model.dtype)
        u = TimeData(name="u",
                     shape=self.model.shape_domain,
                     time_dim=nt,
                     time_order=2,
                     space_order=self.s_order,
                     dtype=self.model.dtype,
                     save=True)
        # Execute operator and return wavefield and receiver data
        gradop = GradientOperator(self.model,
                                  v,
                                  grad,
                                  rec,
                                  u,
                                  self.data,
                                  time_order=self.t_order,
                                  spc_order=self.s_order,
                                  cache_blocking=cache_blocking,
                                  dse=dse,
                                  dle=dle,
                                  tsave=self.tsave,
                                  free_surface=free_surface)
        return gradop
Esempio n. 8
0
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)
Esempio n. 9
0
    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
Esempio n. 10
0
    def test_dimension_size_override(self, nt=100):
        """Test explicit overrides for the leading time dimension"""
        i, j, k = dimify('i j k')
        a = TimeData(name='a', dimensions=(i, j, k))
        one = symbol(name='one', dimensions=(i, j, k), value=1.)
        op = Operator(Eq(a.forward, a + one))

        # Test dimension override via the buffered dimenions
        a.data[0] = 0.
        op(a=a, t=6)
        assert(np.allclose(a.data[1], 5.))

        # Test dimension override via the parent dimenions
        a.data[0] = 0.
        op(a=a, time=5)
        assert(np.allclose(a.data[0], 4.))
Esempio n. 11
0
    def test_fixed_halo_w_ofs(self, space_order):
        """
        Compute an N-point stencil sum, where N is the number of points sorrounding
        an inner (i.e., non-border) grid point.
        For example (in 2D view):

            1 1 1 ... 1 1
            1 4 4 ... 4 1
            1 4 4 ... 4 1
            1 4 4 ... 4 1
            1 1 1 ... 1 1
        """
        v = TimeData(name='yv4D', shape=(16, 16, 16), dimensions=(x, y, z),
                     space_order=space_order)
        v.data.with_halo[:] = 1.
        op = Operator(Eq(v.forward, v.laplace + 6*v),
                      subs={t.spacing: 1, x.spacing: 1, y.spacing: 1, z.spacing: 1})
        op(yv4D=v, t=1)
        assert 'run_solution' in str(op)
        # Chech that the domain size has actually been written to
        assert np.all(v.data[1] == 6.)
        # Check that the halo planes are untouched
        assert all(np.all(v.data.with_halo[1, i, :, :] == 1) for i in range(space_order))
        assert all(np.all(v.data.with_halo[1, :, i, :] == 1) for i in range(space_order))
        assert all(np.all(v.data.with_halo[1, :, :, i] == 1) for i in range(space_order))
Esempio n. 12
0
    def test_equations_mixed_densedata_timedata(self, shape, dimensions):
        """
        Test that equations using a mixture of DenseData and TimeData objects
        are embedded within the same time loop.
        """
        a = TimeData(name='a', shape=shape, time_order=2, dimensions=dimensions,
                     space_order=2, time_dim=6, save=False)
        p_aux = Dimension(name='p_aux', size=10)
        b = DenseData(name='b', shape=shape + (10,), dimensions=dimensions + (p_aux,),
                      space_order=2)
        b.data[:] = 1.0
        b2 = DenseData(name='b2', shape=(10,) + shape, dimensions=(p_aux,) + dimensions,
                       space_order=2)
        b2.data[:] = 1.0
        eqns = [Eq(a.forward, a.laplace + 1.),
                Eq(b, time*b*a + b)]
        eqns2 = [Eq(a.forward, a.laplace + 1.),
                 Eq(b2, time*b2*a + b2)]
        subs = {x.spacing: 2.5, y.spacing: 1.5, z.spacing: 2.0}
        op = Operator(eqns, subs=subs, dle='noop')
        trees = retrieve_iteration_tree(op)
        assert len(trees) == 2
        assert all(trees[0][i] is trees[1][i] for i in range(3))

        op2 = Operator(eqns2, subs=subs, dle='noop')
        trees = retrieve_iteration_tree(op2)
        assert len(trees) == 2
        assert all(trees[0][i] is trees[1][i] for i in range(3))

        # Verify both operators produce the same result
        op()
        op2()

        assert(np.allclose(b2.data[2, ...].reshape(-1) -
                           b.data[..., 2].reshape(-1), 0.))
Esempio n. 13
0
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)

    a, h, s = symbols('a h s')
    eqn = Eq(u.dt, a * (u.dx2 + u.dy2))
    stencil = solve(eqn, u.forward)[0]
    op = Operator(Eq(u.forward, stencil),
                  subs={
                      a: 0.5,
                      h: dx,
                      s: dt
                  },
                  time_axis=Forward)
    op.apply(time=timesteps)

    if save:
        return u.data[timesteps - 1, :]
    else:
        return u.data[(timesteps + 1) % 2, :]
Esempio n. 14
0
    def test_override_composite_data(self):
        original_coords = (1., 1.)
        new_coords = (2., 2.)
        p_dim = Dimension('p_src')
        ndim = len(original_coords)
        u = TimeData(name='u', time_order=2, space_order=2, shape=(10, 10))
        src1 = PointData(name='src1',
                         dimensions=[time, p_dim],
                         npoint=1,
                         nt=10,
                         ndim=ndim,
                         coordinates=original_coords)
        src2 = PointData(name='src1',
                         dimensions=[time, p_dim],
                         npoint=1,
                         nt=10,
                         ndim=ndim,
                         coordinates=new_coords)
        op = Operator(src1.inject(u, src1))

        # Move the source from the location where the setup put it so we can test
        # whether the override picks up the original coordinates or the changed ones

        # Operator.arguments() returns a tuple of (data, dimension_sizes)
        args = op.arguments(src1=src2)[0]
        arg_name = src1.name + "_coords"
        assert (np.array_equal(args[arg_name], np.asarray((new_coords, ))))
Esempio n. 15
0
def c(shape=(11, 11)):
    """Forward time data object, buffered (save=False)"""
    return TimeData(name='c',
                    shape=shape,
                    time_order=1,
                    save=False,
                    time_axis=Forward)
Esempio n. 16
0
 def u(self, model):
     space_order = 4
     time_order = 2
     return TimeData(name='u',
                     shape=model.shape_domain,
                     dimensions=(x, y, z),
                     space_order=space_order,
                     time_order=time_order)
Esempio n. 17
0
 def test_mixed_space_order(self):
     """
     Make sure that no matter whether data objects have different space order,
     as long as they have same domain, the Operator will be executed correctly.
     """
     u = TimeData(name='yu4D', shape=(8, 8, 8), dimensions=(x, y, z), space_order=0)
     v = TimeData(name='yv4D', shape=(8, 8, 8), dimensions=(x, y, z), space_order=1)
     u.data.with_halo[:] = 1.
     v.data.with_halo[:] = 2.
     op = Operator(Eq(v.forward, u + v), subs={t.spacing: 1})
     op(yu4D=u, yv4D=v, t=1)
     assert 'run_solution' in str(op)
     # Chech that the domain size has actually been written to
     assert np.all(v.data[1] == 3.)
     # Check that the halo planes are untouched
     assert np.all(v.data.with_halo[1, 0, :, :] == 2)
     assert np.all(v.data.with_halo[1, :, 0, :] == 2)
     assert np.all(v.data.with_halo[1, :, :, 0] == 2)
Esempio n. 18
0
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)
Esempio n. 19
0
 def test_code(self):
     shape = (11, 11)
     a = TimeData(name='a',
                  shape=shape,
                  time_order=1,
                  time_dim=6,
                  save=True)
     eqn = Eq(a.forward, a + 1.)
     b = TimeData(name='a',
                  shape=shape,
                  time_order=1,
                  time_dim=6,
                  save=True)
     eqn2 = Eq(b.forward, b + 1.)
     op = Operator(eqn)
     op()
     op2 = Operator(eqn2, external=True)
     arg, _ = op.arguments(a=b)
     op2.cfunction(*list(arg.values()))
     assert (np.allclose(a.data[:], b.data[:]))
Esempio n. 20
0
    def test_dimension_size_infer(self, nt=100):
        """Test that the dimension sizes are being inferred correctly"""
        i, j, k = dimify('i j k')
        shape = tuple([d.size for d in [i, j, k]])
        a = DenseData(name='a', shape=shape).indexed
        b = TimeData(name='b', shape=shape, save=True, time_dim=nt).indexed
        eqn = Eq(b[time, x, y, z], a[x, y, z])
        op = Operator(eqn)

        _, op_dim_sizes = op.arguments()
        assert(op_dim_sizes[time.name] == nt)
Esempio n. 21
0
    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 if save else None,
                         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
Esempio n. 22
0
def _new_operator3(shape, time_order, **kwargs):
    spacing = 0.1
    a = 0.5
    c = 0.5
    dx2, dy2 = spacing**2, spacing**2
    dt = dx2 * dy2 / (2 * a * (dx2 + dy2))

    # Allocate the grid and set initial condition
    # Note: This should be made simpler through the use of defaults
    u = TimeData(name='u', shape=shape, time_order=1, space_order=2)
    u.data[0, :] = np.arange(reduce(mul, shape), dtype=np.int32).reshape(shape)

    # Derive the stencil according to devito conventions
    eqn = Eq(u.dt, a * (u.dx2 + u.dy2) - c * (u.dxl + u.dyl))
    stencil = solve(eqn, u.forward, rational=False)[0]
    op = Operator(Eq(u.forward, stencil), subs={x.spacing: spacing,
                                                y.spacing: spacing,
                                                t.spacing: dt}, **kwargs)

    # Execute the generated Devito stencil operator
    op.apply(u=u, t=10)
    return u.data[1, :], op
Esempio n. 23
0
 def test_increasing_multi_steps(self):
     """
     Apply the trivial equation ``u[t+1,x,y,z] = u[t,x,y,z] + 1`` for 11
     timesteps and check that all grid domain values are equal to 11 within
     ``u[1]`` and equal to 10 within ``u[0]``.
     """
     u = TimeData(name='yu4D', shape=(8, 8, 8), dimensions=(x, y, z), space_order=0)
     u.data.with_halo[:] = 0.
     op = Operator(Eq(u.forward, u + 1.), subs={t.spacing: 1})
     op(yu4D=u, t=12)
     assert 'run_solution' in str(op)
     assert np.all(u.data[0] == 10.)
     assert np.all(u.data[1] == 11.)
Esempio n. 24
0
    def Adjoint(self,
                cache_blocking=None,
                auto_tuning=False,
                profile=False,
                save=False,
                dse='advanced',
                dle='advanced',
                compiler=None,
                free_surface=False):
        """Adjoint modelling of a shot record.
        """
        nt, nrec = self.data.shape
        nsrc = self.source.shape[1]
        ndim = len(self.model.shape)
        h = self.model.get_spacing()
        dtype = self.model.dtype
        nbpml = self.model.nbpml

        # Create source symbol
        srca = PointSource(name='srca',
                           ntime=self.source.nt,
                           coordinates=self.source.receiver_coords)

        # Create receiver symbol
        rec = Receiver(name='rec',
                       ntime=self.data.nt,
                       coordinates=self.data.receiver_coords)
        # Create the forward wavefield
        v = TimeData(name="v",
                     shape=self.model.shape_domain,
                     time_dim=nt,
                     time_order=2,
                     space_order=self.s_order,
                     save=save,
                     dtype=self.model.dtype)

        # Execute operator and return wavefield and receiver data
        adj = AdjointOperator(self.model,
                              v,
                              srca,
                              rec,
                              self.data,
                              time_order=self.t_order,
                              spc_order=self.s_order,
                              cache_blocking=cache_blocking,
                              dse=dse,
                              dle=dle,
                              free_surface=free_surface)
        return adj
Esempio n. 25
0
 def test_explicit_run(self):
     time_dim = 6
     a = TimeData(name='a', shape=(11, 11), time_order=1,
                  time_dim=time_dim, save=True)
     eqn = Eq(a.forward, a + 1.)
     op = Operator(eqn)
     assert isinstance(op, OperatorForeign)
     args = OrderedDict(op.arguments())
     assert args['a'] is None
     # Emulate data feeding from outside
     array = np.ndarray(shape=a.shape, dtype=np.float32)
     array.fill(0.0)
     args['a'] = array
     op.cfunction(*list(args.values()))
     assert all(np.allclose(args['a'][i], i) for i in range(time_dim))
Esempio n. 26
0
    def test_increasing_halo_wo_ofs(self, space_order, nosimd):
        """
        Apply the trivial equation ``u[t+1,x,y,z] = u[t,x,y,z] + 1`` and check
        that increasing space orders lead to proportionately larger halo regions,
        which are *not* written by the Operator.
        For example, with ``space_order = 0``, produce (in 2D view):

            1 1 1 ... 1 1
            1 1 1 ... 1 1
            1 1 1 ... 1 1
            1 1 1 ... 1 1
            1 1 1 ... 1 1

        With ``space_order = 1``, produce:

            0 0 0 0 0 0 0 0 0
            0 1 1 1 ... 1 1 0
            0 1 1 1 ... 1 1 0
            0 1 1 1 ... 1 1 0
            0 1 1 1 ... 1 1 0
            0 1 1 1 ... 1 1 0
            0 0 0 0 0 0 0 0 0

        And so on and so forth.
        """
        # SIMD on/off
        yask_configuration['develop-mode'] = nosimd

        u = TimeData(name='yu4D',
                     shape=(16, 16, 16),
                     dimensions=(x, y, z),
                     space_order=space_order)
        u.data.with_halo[:] = 0.
        op = Operator(Eq(u.forward, u + 1.), subs={t.spacing: 1})
        op(yu4D=u, t=1)
        assert 'run_solution' in str(op)
        # Chech that the domain size has actually been written to
        assert np.all(u.data[1] == 1.)
        # Check that the halo planes are still 0
        assert all(
            np.all(u.data.with_halo[1, i, :, :] == 0)
            for i in range(space_order))
        assert all(
            np.all(u.data.with_halo[1, :, i, :] == 0)
            for i in range(space_order))
        assert all(
            np.all(u.data.with_halo[1, :, :, i] == 0)
            for i in range(space_order))
Esempio n. 27
0
 def test_equations_emulate_bc(self, t0):
     """
     Test that bc-like equations get inserted into the same loop nest
     as the "main" equations.
     """
     shape = (3, 3, 3)
     a = DenseData(name='a', shape=shape).indexed
     b = TimeData(name='b', shape=shape, save=True, time_dim=6).indexed
     main = Eq(b[time + 1, x, y, z], b[time - 1, x, y, z] + a[x, y, z] + 3.*t0)
     bcs = [Eq(b[time, 0, y, z], 0.),
            Eq(b[time, x, 0, z], 0.),
            Eq(b[time, x, y, 0], 0.)]
     op = Operator([main] + bcs, dse='noop', dle='noop')
     trees = retrieve_iteration_tree(op)
     assert len(trees) == 4
     assert all(id(trees[0][0]) == id(i[0]) for i in trees)
Esempio n. 28
0
def _new_operator2(shape, time_order, **kwargs):
    infield = TimeData(name='infield', shape=shape, time_order=time_order, dtype=np.int32)
    infield.data[:] = np.arange(reduce(mul, shape), dtype=np.int32).reshape(shape)

    outfield = TimeData(name='outfield', shape=shape, time_order=time_order,
                        dtype=np.int32)

    stencil = Eq(outfield.forward.indexify(),
                 outfield.indexify() + infield.indexify()*3.0)

    # Run the operator
    op = Operator(stencil, **kwargs)
    op(infield=infield, outfield=outfield, t=10)

    return outfield, op
Esempio n. 29
0
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)
Esempio n. 30
0
    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_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