예제 #1
0
 def test_codegen(self):
     input_grid = DenseData(name="input_grid", shape=(3, 2), dtype=np.float64)
     input_grid.data[:] = np.arange(6, dtype=np.float64).reshape((3, 2))
     output_grid = DenseData(name="output_grid", shape=input_grid.shape,
                             dtype=input_grid.dtype)
     eq = Eq(output_grid.indexed[t, x], input_grid.indexed[t, x] + 3)
     op = SimpleOperator(input_grid, output_grid, [eq])
     op.apply()
     assert(output_grid.data[2][1] == 8)
예제 #2
0
    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)
예제 #3
0
 def test_compare(self):
     input_grid = DenseData(name="input_grid", shape=(3, 2), dtype=np.float64)
     input_grid.data[:] = np.arange(6, dtype=np.float64).reshape((3, 2))
     output_grid_py = DenseData(name="output_grid_py", shape=input_grid.shape,
                                dtype=input_grid.dtype)
     output_grid_cg = DenseData(name="output_grid_cg", shape=input_grid.shape,
                                dtype=input_grid.dtype)
     eq_py = Eq(output_grid_py.indexed[t, x], input_grid.indexed[t, x] + 3)
     eq_cg = Eq(output_grid_cg.indexed[t, x], input_grid.indexed[t, x] + 3)
     op_cg = SimpleOperator(input_grid, output_grid_cg, [eq_cg])
     op_py = SimpleOperator(input_grid, output_grid_py, [eq_py])
     op_cg.apply()
     op_py.apply(debug=True)
     assert(np.equal(output_grid_cg.data, output_grid_py.data).all())
예제 #4
0
    def __init__(self, *args, **kwargs):
        if not self._cached():
            self.nt = kwargs.get('nt')
            self.npoint = kwargs.get('npoint')
            self.ndim = kwargs.get('ndim')
            kwargs['shape'] = (self.nt, self.npoint)
            super(PointData, self).__init__(self, *args, **kwargs)

            # Allocate and copy coordinate data
            self.coordinates = DenseData(name='%s_coords' % self.name,
                                         dimensions=[self.indices[1], d],
                                         shape=(self.npoint, self.ndim))
            self._children.append(self.coordinates)
            coordinates = kwargs.get('coordinates', None)
            if coordinates is not None:
                self.coordinates.data[:] = coordinates[:]
예제 #5
0
    def cache_blocking_test(self, shape, time_order, spc_border,
                            cache_blocking):
        symbols_combinations = [(t, ), (t, x), (t, x, z), (t, x, y, z)]
        indexes = symbols_combinations[len(shape) - 1]

        size = 1
        for element in shape:
            size *= element

        input_grid = DenseData(name="input_grid",
                               shape=shape,
                               dtype=np.float64)
        input_grid.data[:] = np.arange(size, dtype=np.float64).reshape(shape)

        output_grid_noblock = DenseData(name="output_grid",
                                        shape=shape,
                                        dtype=np.float64)
        eq_noblock = Eq(
            output_grid_noblock.indexed[indexes],
            output_grid_noblock.indexed[indexes] +
            input_grid.indexed[indexes] + 3)
        op_noblock = SimpleOperator(input_grid,
                                    output_grid_noblock, [eq_noblock],
                                    time_order=time_order,
                                    spc_border=spc_border)
        op_noblock.apply()

        output_grid_block = DenseData(name="output_grid",
                                      shape=shape,
                                      dtype=np.float64)
        eq_block = Eq(
            output_grid_block.indexed[indexes],
            output_grid_block.indexed[indexes] + input_grid.indexed[indexes] +
            3)
        op_block = SimpleOperator(input_grid,
                                  output_grid_block, [eq_block],
                                  cache_blocking=cache_blocking,
                                  time_order=time_order,
                                  spc_border=spc_border)
        op_block.apply()
        assert np.equal(output_grid_block.data, output_grid_noblock.data).all()
예제 #6
0
 def __init__(self,
              origin,
              spacing,
              dimensions,
              vp,
              rho=None,
              epsilon=None,
              delta=None,
              theta=None,
              phi=None,
              nbpml=40):
     self.vp = vp
     self.origin = origin
     self.spacing = spacing
     self.nbpml = nbpml
     self.shape = dimensions
     self.dtype = np.float32
     # 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 = 1 / vp**2
     # Create dampening field as symbol `damp`
     self.damp = DenseData(name="damp",
                           shape=self.shape_domain,
                           dtype=self.dtype)
     # Additional parameter fields for TTI operators
     if rho is not None:
         if isinstance(rho, np.ndarray):
             self.rho = DenseData(name="rho",
                                  shape=self.shape_domain,
                                  dtype=self.dtype)
         else:
             self.rho = rho
     else:
         self.rho = 1
예제 #7
0
    def auto_tuning_test_general(self, block_dims, tune_range,
                                 expected_result):
        shape = (50, 50, 50, 50)
        input_grid = DenseData(name="input_grid",
                               shape=shape,
                               dtype=np.float64)
        input_grid.data[:] = np.arange(6250000,
                                       dtype=np.float64).reshape(shape)
        output_grid = DenseData(name="output_grid",
                                shape=shape,
                                dtype=np.float64)
        indexes = (t, x, y, z)
        eq = Eq(output_grid.indexed[indexes],
                output_grid.indexed[indexes] + input_grid.indexed[indexes] + 3)

        op = SimpleOperator(input_grid,
                            output_grid, [eq],
                            time_order=2,
                            spc_border=2)

        auto_tuner = AutoTuner(op, block_dims, self.test_dir)
        auto_tuner.auto_tune_blocks(tune_range[0], tune_range[1])

        assert auto_tuner.block_size == expected_result
예제 #8
0
def _new_operator1(shape, **kwargs):
    infield = DenseData(name='in', shape=shape, dtype=np.int32)
    infield.data[:] = np.arange(reduce(mul, shape),
                                dtype=np.int32).reshape(shape)

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

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

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

    return outfield
예제 #9
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_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
예제 #10
0
    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)
예제 #11
0
    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)
예제 #12
0
    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)
예제 #13
0
    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)
예제 #14
0
    def __new__(cls, *args, **kwargs):
        nt = kwargs.get('nt')
        npoint = kwargs.get('npoint')
        kwargs['shape'] = (nt, npoint)

        return DenseData.__new__(cls, *args, **kwargs)
예제 #15
0
    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)
예제 #16
0
class PointData(CompositeData):
    """
    Data object for sparse point data that acts as a Function symbol

    :param name: Name of the resulting :class:`sympy.Function` symbol
    :param npoint: Number of points to sample
    :param nt: Size of the time dimension for point data
    :param ndim: Dimension of the coordinate data, eg. 2D or 3D
    :param coordinates: Optional coordinate data for the sparse points
    :param dtype: Data type of the buffered data
    """

    is_PointData = True

    def __init__(self, *args, **kwargs):
        if not self._cached():
            self.nt = kwargs.get('nt')
            self.npoint = kwargs.get('npoint')
            self.ndim = kwargs.get('ndim')
            kwargs['shape'] = (self.nt, self.npoint)
            super(PointData, self).__init__(self, *args, **kwargs)

            # Allocate and copy coordinate data
            self.coordinates = DenseData(name='%s_coords' % self.name,
                                         dimensions=[self.indices[1], d],
                                         shape=(self.npoint, self.ndim))
            self._children.append(self.coordinates)
            coordinates = kwargs.get('coordinates', None)
            if coordinates is not None:
                self.coordinates.data[:] = coordinates[:]

    def __new__(cls, *args, **kwargs):
        nt = kwargs.get('nt')
        npoint = kwargs.get('npoint')
        kwargs['shape'] = (nt, npoint)

        return DenseData.__new__(cls, *args, **kwargs)

    @classmethod
    def _indices(cls, **kwargs):
        """Return the default dimension indices for a given data shape

        :param shape: Shape of the spatial data
        :return: indices used for axis.
        """
        dimensions = kwargs.get('dimensions', None)
        return dimensions or [time, p]

    @property
    def coefficients(self):
        """Symbolic expression for the coefficients for sparse point
        interpolation according to:
        https://en.wikipedia.org/wiki/Bilinear_interpolation.

        :returns: List of coefficients, eg. [b_11, b_12, b_21, b_22]
        """
        # Grid indices corresponding to the corners of the cell
        x1, y1, z1, x2, y2, z2 = symbols('x1, y1, z1, x2, y2, z2')
        # Coordinate values of the sparse point
        px, py, pz = self.point_symbols
        if self.ndim == 2:
            A = Matrix([[1, x1, y1, x1 * y1], [1, x1, y2, x1 * y2],
                        [1, x2, y1, x2 * y1], [1, x2, y2, x2 * y2]])

            p = Matrix([[1], [px], [py], [px * py]])

        elif self.ndim == 3:
            A = Matrix(
                [[1, x1, y1, z1, x1 * y1, x1 * z1, y1 * z1, x1 * y1 * z1],
                 [1, x1, y2, z1, x1 * y2, x1 * z1, y2 * z1, x1 * y2 * z1],
                 [1, x2, y1, z1, x2 * y1, x2 * z1, y2 * z1, x2 * y1 * z1],
                 [1, x1, y1, z2, x1 * y1, x1 * z2, y1 * z2, x1 * y1 * z2],
                 [1, x2, y2, z1, x2 * y2, x2 * z1, y2 * z1, x2 * y2 * z1],
                 [1, x1, y2, z2, x1 * y2, x1 * z2, y2 * z2, x1 * y2 * z2],
                 [1, x2, y1, z2, x2 * y1, x2 * z2, y1 * z2, x2 * y1 * z2],
                 [1, x2, y2, z2, x2 * y2, x2 * z2, y2 * z2, x2 * y2 * z2]])

            p = Matrix([[1], [px], [py], [pz], [px * py], [px * pz], [py * pz],
                        [px * py * pz]])
        else:
            error('Point interpolation only supported for 2D and 3D')
            raise NotImplementedError('Interpolation coefficients not '
                                      'implemented for %d dimensions.' %
                                      self.ndim)

        # Map to reference cell
        reference_cell = {
            x1: 0,
            y1: 0,
            z1: 0,
            x2: x.spacing,
            y2: y.spacing,
            z2: z.spacing
        }
        A = A.subs(reference_cell)
        return A.inv().T.dot(p)

    @property
    def point_symbols(self):
        """Symbol for coordinate value in each dimension of the point"""
        return symbols('px, py, pz')

    @property
    def point_increments(self):
        """Index increments in each dimension for each point symbol"""
        if self.ndim == 2:
            return ((0, 0), (0, 1), (1, 0), (1, 1))
        elif self.ndim == 3:
            return ((0, 0, 0), (0, 1, 0), (1, 0, 0), (0, 0, 1), (1, 1, 0),
                    (0, 1, 1), (1, 0, 1), (1, 1, 1))
        else:
            error('Point interpolation only supported for 2D and 3D')
            raise NotImplementedError('Point increments not defined '
                                      'for %d dimensions.' % self.ndim)

    @property
    def coordinate_symbols(self):
        """Symbol representing the coordinate values in each dimension"""
        p_dim = self.indices[1]
        return tuple(
            [self.coordinates.indexify((p_dim, i)) for i in range(self.ndim)])

    @property
    def coordinate_indices(self):
        """Symbol for each grid index according to the coordinates"""
        indices = (x, y, z)
        return tuple([
            INT(Function('floor')(c / i.spacing))
            for c, i in zip(self.coordinate_symbols, indices[:self.ndim])
        ])

    @property
    def coordinate_bases(self):
        """Symbol for the base coordinates of the reference grid point"""
        indices = (x, y, z)
        return tuple([
            FLOAT(c - idx * i.spacing)
            for c, idx, i in zip(self.coordinate_symbols,
                                 self.coordinate_indices, indices[:self.ndim])
        ])

    def interpolate(self, expr, offset=0, **kwargs):
        """Creates a :class:`sympy.Eq` equation for the interpolation
        of an expression onto this sparse point collection.

        :param expr: The expression to interpolate.
        :param offset: Additional offset from the boundary for
                       absorbing boundary conditions.
        :param u_t: (Optional) time index to use for indexing into
                    field data in `expr`.
        :param p_t: (Optional) time index to use for indexing into
                    the sparse point data.
        """
        u_t = kwargs.get('u_t', None)
        p_t = kwargs.get('p_t', None)
        expr = indexify(expr)

        # Apply optional time symbol substitutions to expr
        if u_t is not None:
            expr = expr.subs(t, u_t).subs(time, u_t)

        variables = list(retrieve_indexed(expr))
        # List of indirection indices for all adjacent grid points
        index_matrix = [
            tuple(idx + ii + offset
                  for ii, idx in zip(inc, self.coordinate_indices))
            for inc in self.point_increments
        ]
        # Generate index substituions for all grid variables
        idx_subs = []
        for i, idx in enumerate(index_matrix):
            v_subs = [(v, v.base[v.indices[:-self.ndim] + idx])
                      for v in variables]
            idx_subs += [OrderedDict(v_subs)]
        # Substitute coordinate base symbols into the coefficients
        subs = OrderedDict(zip(self.point_symbols, self.coordinate_bases))
        rhs = sum([
            expr.subs(vsub) * b.subs(subs)
            for b, vsub in zip(self.coefficients, idx_subs)
        ])

        # Apply optional time symbol substitutions to lhs of assignment
        lhs = self if p_t is None else self.subs(self.indices[0], p_t)
        return [Eq(lhs, rhs)]

    def inject(self, field, expr, offset=0, **kwargs):
        """Symbol for injection of an expression onto a grid

        :param field: The grid field into which we inject.
        :param expr: The expression to inject.
        :param offset: Additional offset from the boundary for
                       absorbing boundary conditions.
        :param u_t: (Optional) time index to use for indexing into `field`.
        :param p_t: (Optional) time index to use for indexing into `expr`.
        """
        u_t = kwargs.get('u_t', None)
        p_t = kwargs.get('p_t', None)

        expr = indexify(expr)
        field = indexify(field)
        variables = list(retrieve_indexed(expr)) + [field]

        # Apply optional time symbol substitutions to field and expr
        if u_t is not None:
            field = field.subs(field.indices[0], u_t)
        if p_t is not None:
            expr = expr.subs(self.indices[0], p_t)

        # List of indirection indices for all adjacent grid points
        index_matrix = [
            tuple(idx + ii + offset
                  for ii, idx in zip(inc, self.coordinate_indices))
            for inc in self.point_increments
        ]

        # Generate index substituions for all grid variables except
        # the sparse `PointData` types
        idx_subs = []
        for i, idx in enumerate(index_matrix):
            v_subs = [(v, v.base[v.indices[:-self.ndim] + idx])
                      for v in variables if not v.base.function.is_PointData]
            idx_subs += [OrderedDict(v_subs)]

        # Substitute coordinate base symbols into the coefficients
        subs = OrderedDict(zip(self.point_symbols, self.coordinate_bases))
        return [
            Eq(field.subs(vsub),
               field.subs(vsub) + expr.subs(subs).subs(vsub) * b.subs(subs))
            for b, vsub in zip(self.coefficients, idx_subs)
        ]
예제 #17
0
def densedata(name, shape, dimensions):
    return DenseData(name=name, shape=shape, dimensions=dimensions)