def symbol(name, dimensions, value=0., mode='function'):
    """Short-cut for symbol creation to test "function"
    and "indexed" API."""
    assert(mode in ['function', 'indexed'])
    s = DenseData(name=name, dimensions=dimensions)
    s.data[:] = value
    return s.indexify() if mode == 'indexed' else s
def test_symbol_cache_aliasing_reverse():
    """Test to assert that removing he original u[x, y] instance does
    not impede our alisaing cache or leaks memory.
    """

    # Ensure a clean cache to start with
    clear_cache()
    # FIXME: Currently not working, presumably due to our
    # failure to cache new instances?
    # assert(len(_SymbolCache) == 0)

    # Create first instance of u and fill its data
    u = DenseData(name='u', shape=(3, 4))
    u.data[:] = 6.
    u_ref = weakref.ref(u.data)

    # Create derivative and delete orignal u[x, y]
    dx = u.dx
    del u
    clear_cache()
    # We still have a references to u
    # FIXME: Unreliable cache sizes
    # assert len(_SymbolCache) == 1
    # Ensure u[x + h, y] still holds valid data
    assert np.allclose(dx.args[0].args[1].data, 6.)

    del dx
    clear_cache()
    # FIXME: Unreliable cache sizes
    # assert len(_SymbolCache) == 0  # We still have a reference to u_h
    assert u_ref() is None
Exemple #3
0
    def test_data_movement_1D(self):
        u = DenseData(name='yu1D', shape=(16,), dimensions=(x,), space_order=0)
        u.data
        assert type(u._data_object) == YaskGrid

        u.data[1] = 1.
        assert u.data[0] == 0.
        assert u.data[1] == 1.
        assert all(i == 0 for i in u.data[2:])
def test_cache_after_indexification():
    """Test to assert that the SymPy cache retrieves the right Devito data object
    after indexification.
    """
    u0 = DenseData(name='u', shape=(4, 4, 4), space_order=0)
    u1 = DenseData(name='u', shape=(4, 4, 4), space_order=1)
    u2 = DenseData(name='u', shape=(4, 4, 4), space_order=2)

    for i in [u0, u1, u2]:
        assert i.indexify().base.function.space_order ==\
            (i.indexify() + 1.).args[1].base.function.space_order
    def test_constant_time_dense(self):
        """Test arithmetic between different data objects, namely ConstantData
        and DenseData."""
        const = ConstantData(name='truc', value=2.)
        a = DenseData(name='a', shape=(20, 20))
        a.data[:] = 2.
        eqn = Eq(a, a + 2.*const)
        op = Operator(eqn)
        op.apply(a=a, truc=const)
        assert(np.allclose(a.data, 6.))

        # Applying a different constant still works
        op.apply(a=a, truc=ConstantData(name='truc2', value=3.))
        assert(np.allclose(a.data, 12.))
Exemple #6
0
def u(dims):
    u = DenseData(name='yu3D',
                  shape=(16, 16, 16),
                  dimensions=(x, y, z),
                  space_order=0)
    u.data  # Trigger initialization
    return u
Exemple #7
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
Exemple #8
0
def test_inject_from_field(shape, coords, result, npoints=19):
    """Test point injection from a second field along a line
    through the middle of the grid.
    """
    a = unit_box(shape=shape)
    spacing = a.data[tuple([1 for _ in shape])]
    a.data[:] = 0.
    b = DenseData(name='b', shape=a.data.shape)
    b.data[:] = 1.
    p = points(ranges=coords, npoints=npoints)

    expr = p.inject(field=a, expr=b)
    Operator(expr, subs={h: spacing})(a=a, b=b, t=1)

    indices = [slice(4, 6, 1) for _ in coords]
    indices[0] = slice(1, -1, 1)
    assert np.allclose(a.data[indices], result, rtol=1.e-5)
def test_fd_space(derivative, space_order):
    """
    This test compare the discrete finite-difference scheme against polynomials
    For a given order p, the fiunite difference scheme should
    be exact for polynomials of order p
    :param derivative: name of the derivative to be tested
    :param space_order: space order of the finite difference stencil
    """
    clear_cache()
    # dummy axis dimension
    nx = 100
    xx = np.linspace(-1, 1, nx)
    dx = xx[1] - xx[0]
    # Symbolic data
    u = DenseData(name="u",
                  shape=(nx, ),
                  space_order=space_order,
                  dtype=np.float32)
    du = DenseData(name="du",
                   shape=(nx, ),
                   space_order=space_order,
                   dtype=np.float32)
    # Define polynomial with exact fd
    h, y = symbols('h y')
    coeffs = np.ones((space_order, ), dtype=np.float32)
    polynome = sum([coeffs[i] * y**i for i in range(0, space_order)])
    polyvalues = np.array([polynome.subs(y, xi) for xi in xx], np.float32)
    # Fill original data with the polynomial values
    u.data[:] = polyvalues
    # True derivative of the polynome
    Dpolynome = diff(diff(polynome)) if derivative == 'dx2' else diff(polynome)
    Dpolyvalues = np.array([Dpolynome.subs(y, xi) for xi in xx], np.float32)
    # FD derivative, symbolic
    u_deriv = getattr(u, derivative)
    # Compute numerical FD
    stencil = Eq(du, u_deriv)
    op = Operator(stencil, subs={h: dx})
    op.apply()

    # Check exactness of the numerical derivative except inside space_brd
    space_border = space_order
    error = abs(du.data[space_border:-space_border] -
                Dpolyvalues[space_border:-space_border])
    assert np.isclose(np.mean(error), 0., atol=1e-3)
Exemple #10
0
def _new_operator1(shape, **kwargs):
    infield = DenseData(name='infield', shape=shape, dtype=np.int32)
    infield.data[:] = np.arange(reduce(mul, shape), dtype=np.int32).reshape(shape)

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

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

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

    return outfield, op
Exemple #11
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
    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)
def test_clear_cache(nx=1000, ny=1000):
    clear_cache()
    cache_size = len(_SymbolCache)

    for i in range(10):
        assert (len(_SymbolCache) == cache_size)

        DenseData(name='u', shape=(nx, ny), dtype=np.float64, space_order=2)

        assert (len(_SymbolCache) == cache_size + 1)

        clear_cache()
    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.))
def test_symbol_cache_aliasing():
    """Test to assert that our aiasing cache isn't defeated by sympys
    non-aliasing symbol cache.

    For further explanation consider the symbol u[x, y] and it's first
    derivative in x, which includes the symbols u[x, y] and u[x + h, y].
    The two functions are aliased in devito's caching mechanism to allow
    multiple stencil indices pointing at the same data object u, but
    SymPy treats these two instances as separate functions and thus is
    allowed to delete one or the other when the cache is cleared.

    The test below asserts that u[x + h, y] is deleted, the data on u
    is still intact through our own caching mechanism."""

    # Ensure a clean cache to start with
    clear_cache()
    # FIXME: Currently not working, presumably due to our
    # failure to cache new instances?
    # assert(len(_SymbolCache) == 0)

    # Create first instance of u and fill its data
    u = DenseData(name='u', shape=(3, 4))
    u.data[:] = 6.
    u_ref = weakref.ref(u.data)

    # Create u[x + h, y] and delete it again
    dx = u.dx  # Contains two u symbols: u[x, y] and u[x + h, y]
    del dx
    clear_cache()
    # FIXME: Unreliable cache sizes
    # assert len(_SymbolCache) == 1  # We still have a reference to u
    assert np.allclose(u.data, 6.)  # u.data is alive and well

    # Remove the final instance and ensure u.data got deallocated
    del u
    clear_cache()
    assert u_ref() is None
Exemple #16
0
def test_arithmetic_deep(expr, result):
    """Tests basic point-wise arithmetic on multi-dimensional data"""
    i = Dimension(name='i', size=3)
    j = Dimension(name='j', size=4)
    k = Dimension(name='k', size=5)
    l = Dimension(name='l', size=6)

    a = DenseData(name='a', dimensions=(i, j, k, l))
    a.data[:] = 2.
    ai = a.indexify()
    b = DenseData(name='b', dimensions=(j, k))
    b.data[:] = 3.
    bi = b.indexify()

    eqn = eval(expr)
    StencilKernel(eqn)(ai.base.function, bi.base.function)
    assert np.allclose(ai.base.function.data, result, rtol=1e-12)
    def test_indexed_open_loops(self, expr, result):
        """Test point-wise arithmetic with stencil offsets and open loop
        boundaries in indexed expression format"""
        i, j, l = dimify('i j l')
        pushed = [d.size for d in [j, l]]
        j.size = None
        l.size = None
        a = DenseData(name='a', dimensions=(i, j, l), shape=(3, 5, 6)).indexed
        fa = a.function
        fa.data[0, :, :] = 2.

        eqn = eval(expr)
        Operator(eqn)(a=fa)
        assert np.allclose(fa.data[1, 1:-1, 1:-1], result[1:-1, 1:-1], rtol=1e-12)
        j.size, l.size = pushed
Exemple #18
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)
 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)
Exemple #20
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
Exemple #21
0
    def __init__(self,
                 origin,
                 spacing,
                 shape,
                 vp,
                 nbpml=20,
                 dtype=np.float32,
                 epsilon=None,
                 delta=None,
                 theta=None,
                 phi=None):
        self.origin = origin
        self.spacing = spacing
        self.shape = shape
        self.nbpml = int(nbpml)
        self.dtype = dtype

        # Ensure same dimensions on all inpute parameters
        assert (len(origin) == len(spacing))
        assert (len(origin) == len(shape))

        # Create square slowness of the wave as symbol `m`
        if isinstance(vp, np.ndarray):
            self.m = DenseData(name="m",
                               shape=self.shape_domain,
                               dtype=self.dtype)
        else:
            self.m = ConstantData(name="m", value=1 / vp**2, dtype=self.dtype)

        # Set model velocity, which will also set `m`
        self.vp = vp

        # Create dampening field as symbol `damp`
        self.damp = DenseData(name="damp",
                              shape=self.shape_domain,
                              dtype=self.dtype)
        damp_boundary(self.damp.data, self.nbpml, spacing=self.get_spacing())

        # Additional parameter fields for TTI operators
        self.scale = 1.

        if epsilon is not None:
            if isinstance(epsilon, np.ndarray):
                self.epsilon = DenseData(name="epsilon",
                                         shape=self.shape_domain,
                                         dtype=self.dtype)
                self.epsilon.data[:] = self.pad(1 + 2 * epsilon)
                # Maximum velocity is scale*max(vp) if epsilon > 0
                if np.max(self.epsilon.data) > 0:
                    self.scale = np.sqrt(np.max(self.epsilon.data))
            else:
                self.epsilon = 1 + 2 * epsilon
                self.scale = epsilon
        else:
            self.epsilon = 1

        if delta is not None:
            if isinstance(delta, np.ndarray):
                self.delta = DenseData(name="delta",
                                       shape=self.shape_domain,
                                       dtype=self.dtype)
                self.delta.data[:] = self.pad(np.sqrt(1 + 2 * delta))
            else:
                self.delta = delta
        else:
            self.delta = 1

        if theta is not None:
            if isinstance(theta, np.ndarray):
                self.theta = DenseData(name="theta",
                                       shape=self.shape_domain,
                                       dtype=self.dtype)
                self.theta.data[:] = self.pad(theta)
            else:
                self.theta = theta
        else:
            self.theta = 0

        if phi is not None:
            if isinstance(phi, np.ndarray):
                self.phi = DenseData(name="phi",
                                     shape=self.shape_domain,
                                     dtype=self.dtype)
                self.phi.data[:] = self.pad(phi)
            else:
                self.phi = phi
        else:
            self.phi = 0
Exemple #22
0
def ai(x, y, name='a', value=2.):
    a = DenseData(name=name, dimensions=(x, y))
    a.data[:] = value
    return a.indexify()
Exemple #23
0
def densedata(name, shape, dimensions):
    return DenseData(name=name, shape=shape, dimensions=dimensions)
Exemple #24
0
def bi(x, y, name='b', value=3.):
    b = DenseData(name=name, dimensions=(x, y))
    b.data[:] = value
    return b.indexify()
Exemple #25
0
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 run(dimensions=(50, 50, 50),
        tn=750.0,
        time_order=2,
        space_order=4,
        nbpml=40,
        dse='noop',
        dle='noop'):
    ndim = len(dimensions)
    origin = tuple([0.] * ndim)
    spacing = tuple([15.] * ndim)
    f0 = .010
    t0 = 0.0
    # True velocity
    true_vp = np.ones(dimensions) + .5
    true_vp[..., int(dimensions[-1] / 2):] = 2.

    # Smooth velocity - we use this as our initial m
    initial_vp = smooth10(true_vp, dimensions)
    # Model perturbation
    model = Model(origin, spacing, true_vp.shape, true_vp, nbpml=nbpml)
    m0 = np.float32(model.pad(initial_vp**-2))
    dm = np.float32(model.m.data - m0)
    dt = model.critical_dt
    if time_order == 4:
        dt *= 1.73

    nt = int(1 + (tn - t0) / dt)

    # Source geometry
    time_series = np.zeros((nt, 1), dtype=np.float32)
    time_series[:, 0] = source(np.linspace(t0, tn, nt), f0)

    # Source location
    location = np.zeros((1, ndim), dtype=np.float32)
    location[0, :-1] = [
        origin[i] + dimensions[i] * spacing[i] * .5 for i in range(ndim - 1)
    ]
    location[0, -1] = origin[-1] + 2 * spacing[-1]
    # Receivers locations
    receiver_coords = np.zeros((dimensions[0], ndim), dtype=np.float32)
    receiver_coords[:, 0] = np.linspace(0,
                                        origin[0] +
                                        (dimensions[0] - 1) * spacing[0],
                                        num=dimensions[0])
    receiver_coords[:, 1:] = location[0, 1:]

    # Create source symbol
    src = PointSource(name="src", data=time_series, coordinates=location)

    # Receiver for true model
    rec_t = Receiver(name="rec", ntime=nt, coordinates=receiver_coords)
    # Receiver for smoothed model
    rec_s = Receiver(name="rec", ntime=nt, coordinates=receiver_coords)

    # Create the forward wavefield to use (only 3 timesteps)
    # Once checkpointing is in, this will be the only wavefield we need
    u_nosave = TimeData(name="u",
                        shape=model.shape_domain,
                        time_dim=nt,
                        time_order=time_order,
                        space_order=space_order,
                        save=False,
                        dtype=model.dtype)

    # Forward wavefield where all timesteps are stored
    # With checkpointing this should go away <----
    u_save = TimeData(name="u",
                      shape=model.shape_domain,
                      time_dim=nt,
                      time_order=time_order,
                      space_order=space_order,
                      save=True,
                      dtype=model.dtype)

    # Forward Operators - one with save = True and one with save = False
    fw = ForwardOperator(model,
                         src,
                         rec_t,
                         time_order=time_order,
                         spc_order=space_order,
                         save=True,
                         dse=dse,
                         dle=dle)

    fw_nosave = ForwardOperator(model,
                                src,
                                rec_t,
                                time_order=time_order,
                                spc_order=space_order,
                                save=False,
                                dse=dse,
                                dle=dle)

    # Calculate receiver data for true velocity
    fw_nosave.apply(u=u_nosave, rec=rec_t, src=src)

    # Smooth velocity
    # This is the pass that needs checkpointing <----
    fw.apply(u=u_save, rec=rec_s, m=m0, src=src)

    # Objective function value
    F0 = .5 * linalg.norm(rec_s.data - rec_t.data)**2
    # Receiver for Gradient
    # Confusing nomenclature because this is actually the source for the adjoint
    # mode
    rec_g = Receiver(name="rec",
                     coordinates=rec_s.coordinates.data,
                     data=rec_s.data - rec_t.data)
    # Gradient symbol
    grad = DenseData(name="grad", shape=model.shape_domain, dtype=model.dtype)
    # Reusing u_nosave from above as the adjoint wavefield since it is a temp var anyway
    gradop = GradientOperator(model,
                              src,
                              rec_g,
                              time_order=time_order,
                              spc_order=space_order,
                              dse=dse,
                              dle=dle)

    # Clear the wavefield variable to reuse it
    # This time it represents the adjoint field
    u_nosave.data.fill(0)
    # Apply the gradient operator to calculate the gradient
    # This is the pass that requires the checkpointed data
    gradop.apply(u=u_save, v=u_nosave, m=m0, rec=rec_g, grad=grad)
    # The result is in grad
    gradient = grad.data

    # <J^T \delta d, dm>
    G = np.dot(gradient.reshape(-1), dm.reshape(-1))
    # FWI Gradient test
    H = [0.5, 0.25, .125, 0.0625, 0.0312, 0.015625, 0.0078125]
    error1 = np.zeros(7)
    error2 = np.zeros(7)

    for i in range(0, 7):
        # Add the perturbation to the model
        mloc = m0 + H[i] * dm
        # Set field to zero (we're re-using it)
        u_nosave.data.fill(0)
        # Receiver data for the new model
        # Results will be in rec_s
        fw_nosave.apply(u=u_nosave, rec=rec_s, m=mloc, src=src)
        d = rec_s.data
        # First order error Phi(m0+dm) - Phi(m0)
        error1[i] = np.absolute(.5 * linalg.norm(d - rec_t.data)**2 - F0)
        # Second order term r Phi(m0+dm) - Phi(m0) - <J(m0)^T \delta d, dm>
        error2[i] = np.absolute(.5 * linalg.norm(d - rec_t.data)**2 - F0 -
                                H[i] * G)

    # Test slope of the  tests
    p1 = np.polyfit(np.log10(H), np.log10(error1), 1)
    p2 = np.polyfit(np.log10(H), np.log10(error2), 1)
    assert np.isclose(p1[0], 1.0, rtol=0.1)
    assert np.isclose(p2[0], 2.0, rtol=0.1)
Exemple #27
0
def a(shape=(11, 11)):
    x = np.linspace(0., 1., shape[0])
    y = np.linspace(0., 1., shape[1])
    a = DenseData(name='a', shape=shape)
    a.data[:] = np.meshgrid(x, y)[1]
    return a
Exemple #28
0
def unit_box(name='a', shape=(11, 11)):
    """Create a field with value 0. to 1. in each dimension"""
    a = DenseData(name=name, shape=shape)
    dims = tuple([np.linspace(0., 1., d) for d in shape])
    a.data[:] = np.meshgrid(*dims)[1]
    return a