Exemplo n.º 1
0
 def test_default_rules(self, order):
     """
     Test that the default replacement rules return the same
     as standard FD.
     """
     grid = Grid(shape=(20, 20))
     u0 = TimeFunction(name='u', grid=grid, time_order=order, space_order=order)
     u1 = TimeFunction(name='u', grid=grid, time_order=order, space_order=order,
                       coefficients='symbolic')
     eq0 = Eq(-u0.dx+u0.dt)
     eq1 = Eq(u1.dt-u1.dx)
     assert(eq0.evalf(_PRECISION).__repr__() == eq1.evalf(_PRECISION).__repr__())
Exemplo n.º 2
0
    def test_dynamic_nthreads(self):
        grid = Grid(shape=(16, 16, 16))
        f = TimeFunction(name='f', grid=grid)

        op = Operator(Eq(f.forward, f + 1.), dle='openmp')

        # Check num_threads appears in the generated code
        # Not very elegant, but it does the trick
        assert 'num_threads(nthreads)' in str(op)

        # Check `op` accepts the `nthreads` kwarg
        op.apply(time=0)
        op.apply(time_m=1, time_M=1, nthreads=4)
        assert np.all(f.data[0] == 2.)

        # Check the actual value assumed by `nthreads`
        assert op.arguments(time=0)['nthreads'] == NThreads.default_value()
        assert op.arguments(time=0,
                            nthreads=123)['nthreads'] == 123  # user supplied
Exemplo n.º 3
0
    def test_precomputed2(self):
        shape = (101, 101)
        grid = Grid(shape=shape)
        x, y = grid.dimensions
        r = 2  # Constant for linear interpolation
        #  because we interpolate across 2 neighbouring points in each dimension

        nt = 10

        m = TimeFunction(name="m",
                         grid=grid,
                         space_order=0,
                         save=None,
                         time_order=1)

        m.data[:] = 0.0
        m.data[:, 40, 40] = 1.0

        matrix = scipy.sparse.eye(1, dtype=np.float32)
        sf = MatrixSparseTimeFunction(name="s",
                                      grid=grid,
                                      r=r,
                                      matrix=matrix,
                                      nt=nt)

        # Lookup the exact point
        sf.gridpoints.data[0, 0] = 40
        sf.gridpoints.data[0, 1] = 40
        sf.interpolation_coefficients[x].data[0, 0] = 1.0
        sf.interpolation_coefficients[x].data[0, 1] = 2.0
        sf.interpolation_coefficients[y].data[0, 0] = 1.0
        sf.interpolation_coefficients[y].data[0, 1] = 2.0
        sf.data[:] = 0.0

        step = [Eq(m.forward, m)]
        interp = sf.interpolate(m)
        op = Operator(step + interp)

        sf.manual_scatter()
        op(time_m=0, time_M=0)
        sf.manual_gather()

        assert sf.data[0, 0] == 1.0
Exemplo n.º 4
0
    def setup(self):
        grid = Grid(shape=(5, 5, 5))

        funcs = [Function(name='f%d' % n, grid=grid) for n in range(30)]
        tfuncs = [TimeFunction(name='u%d' % n, grid=grid) for n in range(30)]
        stfuncs = [
            SparseTimeFunction(name='su%d' % n, grid=grid, npoint=1, nt=100)
            for n in range(30)
        ]
        v = TimeFunction(name='v', grid=grid, space_order=2)

        eq = Eq(v.forward,
                v.laplace + sum(funcs) + sum(tfuncs) + sum(stfuncs),
                subdomain=grid.interior)

        self.op = Operator(eq, opt='noop')

        # Allocate data, populate cached properties, etc.
        self.op.arguments(time_M=98)
Exemplo n.º 5
0
def test_discarding_runs():
    grid = Grid(shape=(64, 64, 64))
    f = TimeFunction(name='f', grid=grid)

    op = Operator(Eq(f.forward, f + 1.), dle=('advanced', {'openmp': True}))
    op.apply(time=100, nthreads=4, autotune='aggressive')

    assert op._state['autotuning'][0]['runs'] == 18
    assert op._state['autotuning'][0]['tpr'] == options['squeezer'] + 1
    assert len(op._state['autotuning'][0]['tuned']) == 3
    assert op._state['autotuning'][0]['tuned']['nthreads'] == 4

    # With 1 < 4 threads, the AT eventually tries many more combinations
    op.apply(time=100, nthreads=1, autotune='aggressive')

    assert op._state['autotuning'][1]['runs'] == 25
    assert op._state['autotuning'][1]['tpr'] == options['squeezer'] + 1
    assert len(op._state['autotuning'][1]['tuned']) == 3
    assert op._state['autotuning'][1]['tuned']['nthreads'] == 1
Exemplo n.º 6
0
 def test_explicit_run(self):
     time_dim = 6
     grid = Grid(shape=(11, 11))
     a = TimeFunction(name='a',
                      grid=grid,
                      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))
Exemplo n.º 7
0
def td_born_forward_op(model, geometry, time_order, space_order):

    nt = geometry.nt

    # Define the wavefields with the size of the model and the time dimension
    u0 = TimeFunction(
        name='u0',
        grid=model.grid,
        time_order=time_order,
        space_order=space_order,
        save=nt
    )
    u = TimeFunction(
        name='u',
        grid=model.grid,
        time_order=time_order,
        space_order=space_order,
        save=nt
    )
    dm = TimeFunction(
        name='dm',
        grid=model.grid,
        time_order=time_order,
        space_order=space_order,
        save=nt
    )

    # Define the wave equation
    pde = model.m * u.dt2 - u.laplace + model.damp * u.dt - dm * u0

    # Use `solve` to rearrange the equation into a stencil expression
    stencil = Eq(u.forward, solve(pde, u.forward), subdomain=model.grid.subdomains['physdomain'])

    # Sample at receivers
    born_data_rec = PointSource(
        name='born_data_rec',
        grid=model.grid,
        time_range=geometry.time_axis,
        coordinates=geometry.rec_positions
    )
    rec_term = born_data_rec.interpolate(expr=u)

    return Operator([stencil] + rec_term, subs=model.spacing_map)
Exemplo n.º 8
0
    def test_interior(self):
        """
        Tests application of an Operator consisting of a single equation
        over the ``INTERIOR`` region.
        """
        grid = Grid(shape=(4, 4, 4))
        x, y, z = grid.dimensions

        u = TimeFunction(name='u', grid=grid)

        eqn = [Eq(u.forward, u + 2, region=INTERIOR)]

        op = Operator(eqn, dle='noop')
        op.apply(time_M=2)
        assert np.all(u.data[1, 1:-1, 1:-1, 1:-1] == 6.)
        assert np.all(u.data[1, :, 0] == 0.)
        assert np.all(u.data[1, :, -1] == 0.)
        assert np.all(u.data[1, :, :, 0] == 0.)
        assert np.all(u.data[1, :, :, -1] == 0.)
Exemplo n.º 9
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.
     """
     grid = Grid(shape=(8, 8, 8))
     u = TimeFunction(name='yu4D', grid=grid, space_order=0)
     v = TimeFunction(name='yv4D', grid=grid, space_order=1)
     u.data_with_halo[:] = 1.
     v.data_with_halo[:] = 2.
     op = Operator(Eq(v.forward, u + v))
     op(yu4D=u, yv4D=v, t=0)
     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)
Exemplo n.º 10
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
        configuration['develop-mode'] = nosimd

        grid = Grid(shape=(16, 16, 16))
        u = TimeFunction(name='yu4D', grid=grid, space_order=space_order)
        u.data_with_halo[:] = 0.
        op = Operator(Eq(u.forward, u + 1.))
        op(yu4D=u, time=0)
        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(u._size_halo.left[1]))
        assert all(np.all(u.data_with_halo[1, :, i, :] == 0)
                   for i in range(u._size_halo.left[2]))
        assert all(np.all(u.data_with_halo[1, :, :, i] == 0)
                   for i in range(u._size_halo.left[3]))
Exemplo n.º 11
0
 def test_default_rules_vs_string(self, so, expected):
     """
     Test that default_rules generates correct symbolic expressions when used
     with staggered grids.
     """
     grid = Grid(shape=(11, ), extent=(10., ))
     x = grid.dimensions[0]
     f = Function(name='f',
                  grid=grid,
                  space_order=so,
                  staggered=NODE,
                  coefficients='symbolic')
     g = Function(name='g',
                  grid=grid,
                  space_order=so,
                  staggered=x,
                  coefficients='symbolic')
     eq = Eq(g, f.dx)
     assert str(eq.evaluate.rhs) == expected
Exemplo n.º 12
0
def test_conddim_w_shifting():
    nt = 50
    grid = Grid(shape=(5, 5))
    time = grid.time_dim

    factor = Constant(name='factor', value=5, dtype=np.int32)
    t_sub = ConditionalDimension('t_sub', parent=time, factor=factor)
    save_shift = Constant(name='save_shift', dtype=np.int32)

    u = TimeFunction(name='u', grid=grid, time_order=0)
    u1 = TimeFunction(name='u', grid=grid, time_order=0)
    usave = TimeFunction(name='usave',
                         grid=grid,
                         time_order=0,
                         save=(int(nt // factor.data)),
                         time_dim=t_sub)

    for i in range(usave.save):
        usave.data[i, :] = i

    eqns = Eq(u.forward, u + usave.subs(t_sub, t_sub - save_shift))

    op0 = Operator(eqns, opt='noop')
    op1 = Operator(eqns, opt='buffering')

    # Check generated code
    assert len(retrieve_iteration_tree(op1)) == 3
    buffers = [i for i in FindSymbols().visit(op1) if i.is_Array]
    assert len(buffers) == 1

    # From time_m=15 to time_M=35 with a factor=5 -- it means that, thanks
    # to t_sub, we enter the Eq exactly (35-15)/5 + 1 = 5 times. We set
    # save_shift=1 so instead of accessing the range usave[15/5:35/5+1],
    # we rather access the range usave[15/5-1:35:5], which means accessing
    # the usave values 2, 3, 4, 5, 6.
    op0.apply(time_m=15, time_M=35, save_shift=1)
    op1.apply(time_m=15, time_M=35, save_shift=1, u=u1)
    assert np.allclose(u.data, 20)
    assert np.all(u.data == u1.data)

    # Again, but with a different shift
    op1.apply(time_m=15, time_M=35, save_shift=-2, u=u1)
    assert np.allclose(u1.data, 20 + 35)
Exemplo n.º 13
0
    def test_misc_dims(self):
        """
        Test MPI in presence of Functions with mixed distributed/replicated
        Dimensions, with only a strict subset of the Grid dimensions used.
        """
        dx = Dimension(name='dx')
        grid = Grid(shape=(4, 4))
        x, y = grid.dimensions
        glb_pos_map = grid.distributor.glb_pos_map
        time = grid.time_dim

        u = TimeFunction(name='u',
                         grid=grid,
                         time_order=1,
                         space_order=2,
                         save=4)
        c = Function(name='c', grid=grid, dimensions=(x, dx), shape=(4, 5))

        step = Eq(u.forward,
                  (u[time, x - 2, y] * c[x, 0] + u[time, x - 1, y] * c[x, 1] +
                   u[time, x, y] * c[x, 2] + u[time, x + 1, y] * c[x, 3] +
                   u[time, x + 2, y] * c[x, 4]))

        for i in range(4):
            c.data[i, 0] = 1.0 + i
            c.data[i, 1] = 1.0 + i
            c.data[i, 2] = 3.0 + i
            c.data[i, 3] = 6.0 + i
            c.data[i, 4] = 5.0 + i

        u.data[:] = 0.0
        u.data[0, 2, :] = 2.0

        op = Operator(step)

        op(time_m=0, time_M=0)

        if LEFT in glb_pos_map[x]:
            assert (np.all(u.data[1, 0, :] == 10.0))
            assert (np.all(u.data[1, 1, :] == 14.0))
        else:
            assert (np.all(u.data[1, 2, :] == 10.0))
            assert (np.all(u.data[1, 3, :] == 8.0))
Exemplo n.º 14
0
def test_hierarchical_blocking():
    grid = Grid(shape=(64, 64, 64))

    u = TimeFunction(name='u', grid=grid, space_order=2)

    op = Operator(Eq(u.forward, u + 1), dle=('blocking', {'openmp': False,
                                                          'blocklevels': 2}))

    # 'basic' mode
    op.apply(time_M=0, autotune='basic')
    assert op._state['autotuning'][0]['runs'] == 10
    assert op._state['autotuning'][0]['tpr'] == options['squeezer'] + 1
    assert len(op._state['autotuning'][0]['tuned']) == 4

    # 'aggressive' mode
    op.apply(time_M=0, autotune='aggressive')
    assert op._state['autotuning'][1]['runs'] == 38
    assert op._state['autotuning'][1]['tpr'] == options['squeezer'] + 1
    assert len(op._state['autotuning'][1]['tuned']) == 4
Exemplo n.º 15
0
def test_at_is_actually_working(shape, expected):
    """
    Check that autotuning is actually running when switched on,
    in both 2D and 3D operators.
    """
    grid = Grid(shape=shape)
    infield = Function(name='infield', grid=grid)
    infield.data[:] = np.arange(reduce(mul, shape),
                                dtype=np.int32).reshape(shape)
    outfield = Function(name='outfield', grid=grid)

    stencil = Eq(outfield.indexify(),
                 outfield.indexify() + infield.indexify() * 3.0)
    op = Operator(stencil,
                  dle=('blocking', {
                      'openmp': False,
                      'blockinner': True,
                      'blockalways': True
                  }))

    # Run with whatever `configuration` says (by default, basic+preemptive)
    op(infield=infield, outfield=outfield, autotune=True)
    assert op._state['autotuning'][-1]['runs'] == 4
    assert op._state['autotuning'][-1]['tpr'] == 1

    # Now try `aggressive` autotuning
    configuration['autotuning'] = 'aggressive'
    op(infield=infield, outfield=outfield, autotune=True)
    assert op._state['autotuning'][-1]['runs'] == expected
    assert op._state['autotuning'][-1]['tpr'] == 1
    configuration['autotuning'] = configuration._defaults['autotuning']

    # Try again, but using the Operator API directly
    op(infield=infield, outfield=outfield, autotune='aggressive')
    assert op._state['autotuning'][-1]['runs'] == expected
    assert op._state['autotuning'][-1]['tpr'] == 1

    # Similar to above
    op(infield=infield,
       outfield=outfield,
       autotune=('aggressive', 'preemptive'))
    assert op._state['autotuning'][-1]['runs'] == expected
    assert op._state['autotuning'][-1]['tpr'] == 1
Exemplo n.º 16
0
    def test_collapsing(self):
        grid = Grid(shape=(3, 3, 3))

        u = TimeFunction(name='u', grid=grid)

        op = Operator(Eq(u.forward, u + 1), opt=('blocking', 'openmp'))

        # Does it compile? Honoring the OpenMP specification isn't trivial
        assert op.cfunction

        # Does it produce the right result
        op.apply(t_M=9)
        assert np.all(u.data[0] == 10)

        iterations = FindNodes(Iteration).visit(op._func_table['bf0'])
        assert iterations[0].pragmas[0].value == 'omp for collapse(2) schedule(dynamic,1)'
        assert iterations[2].pragmas[0].value == ('omp parallel for collapse(2) '
                                                  'schedule(dynamic,1) '
                                                  'num_threads(nthreads_nested)')
Exemplo n.º 17
0
def _new_operator3(shape, blockshape0=None, blockshape1=None, opt=None):
    blockshape0 = as_tuple(blockshape0)
    blockshape1 = as_tuple(blockshape1)

    grid = Grid(shape=shape, extent=shape, dtype=np.float64)

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

    # Derive the stencil according to devito conventions
    op = Operator(Eq(u.forward, 0.5 * u.laplace + u), opt=opt)

    blocksizes0 = get_blocksizes(op, opt, grid, blockshape0, 0)
    blocksizes1 = get_blocksizes(op, opt, grid, blockshape1, 1)
    op.apply(u=u, t=10, **blocksizes0, **blocksizes1)

    return u.data[1, :], op
Exemplo n.º 18
0
    def test_arguments_subrange(self):
        """
        Test op.apply when a subrange is specified for a distributed dimension.
        """
        grid = Grid(shape=(16, ))
        x = grid.dimensions[0]

        f = TimeFunction(name='f', grid=grid)

        op = Operator(Eq(f.forward, f + 1.))
        op.apply(time=0, x_m=4, x_M=11)

        glb_pos_map = f.grid.distributor.glb_pos_map
        if LEFT in glb_pos_map[x]:
            assert np.all(f.data_ro_domain[1, :4] == 0.)
            assert np.all(f.data_ro_domain[1, 4:] == 1.)
        else:
            assert np.all(f.data_ro_domain[1, :-4] == 1.)
            assert np.all(f.data_ro_domain[1, -4:] == 0.)
Exemplo n.º 19
0
    def test_trivial_eq_1d_save(self):
        grid = Grid(shape=(32, ))
        x = grid.dimensions[0]
        time = grid.time_dim

        f = TimeFunction(name='f', grid=grid, save=5)
        f.data_with_halo[:] = 1.

        op = Operator(Eq(f.forward, f[time, x - 1] + f[time, x + 1] + 1))
        op.apply()

        time_M = op.prepare_arguments()['time_M']

        assert np.all(f.data_ro_domain[1] == 3.)
        glb_pos_map = f.grid.distributor.glb_pos_map
        if LEFT in glb_pos_map[x]:
            assert np.all(f.data_ro_domain[-1, time_M:] == 31.)
        else:
            assert np.all(f.data_ro_domain[-1, :-time_M] == 31.)
Exemplo n.º 20
0
def test_mpi():
    grid = Grid(shape=(4, 4))

    u = TimeFunction(name='u', grid=grid, space_order=2)
    u1 = TimeFunction(name='u', grid=grid, space_order=2)

    eqn = Eq(u.forward, u.dx2 + 1.)

    op0 = Operator(eqn)
    op1 = Operator(eqn, opt=('advanced', {'linearize': True}))

    # Check generated code
    assert 'uL0' not in str(op0)
    assert 'uL0' in str(op1)

    op0.apply(time_M=10)
    op1.apply(time_M=10, u=u1)

    assert np.all(u.data == u1.data)
Exemplo n.º 21
0
def test_at_is_actually_working(shape, expected):
    """
    Check that autotuning is actually running when switched on,
    in both 2D and 3D operators.
    """
    grid = Grid(shape=shape)

    buffer = StringIO()
    temporary_handler = logging.StreamHandler(buffer)
    logger.addHandler(temporary_handler)

    infield = Function(name='infield', grid=grid)
    infield.data[:] = np.arange(reduce(mul, shape),
                                dtype=np.int32).reshape(shape)
    outfield = Function(name='outfield', grid=grid)
    stencil = Eq(outfield.indexify(),
                 outfield.indexify() + infield.indexify() * 3.0)
    op = Operator(stencil,
                  dle=('blocking', {
                      'blockinner': True,
                      'blockalways': True
                  }))

    # Expected 3 AT attempts for the given shape
    op(infield=infield, outfield=outfield, autotune=True)
    out = [i for i in buffer.getvalue().split('\n') if 'AutoTuner:' in i]
    assert len(out) == 4

    # Now try the same with aggressive autotuning, which tries 9 more cases
    configuration.core['autotuning'] = 'aggressive'
    op(infield=infield, outfield=outfield, autotune=True)
    out = [i for i in buffer.getvalue().split('\n') if 'AutoTuner:' in i]
    assert len(out) == expected
    configuration.core['autotuning'] = configuration.core._defaults[
        'autotuning']

    logger.removeHandler(temporary_handler)

    temporary_handler.flush()
    temporary_handler.close()
    buffer.flush()
    buffer.close()
Exemplo n.º 22
0
    def test_multiple_subnests_v1(self):
        """
        Unlike ``test_multiple_subnestes_v0``, now we use the ``cire-rotate=True``
        option, which trades some of the inner parallelism for a smaller working set.
        """
        grid = Grid(shape=(3, 3, 3))
        x, y, z = grid.dimensions
        t = grid.stepping_dim

        f = Function(name='f', grid=grid)
        u = TimeFunction(name='u', grid=grid, space_order=3)

        eqn = Eq(
            u.forward,
            ((u[t, x, y, z] + u[t, x + 1, y + 1, z + 1]) * 3 * f +
             (u[t, x + 2, y + 2, z + 2] + u[t, x + 3, y + 3, z + 3]) * 3 * f +
             1))
        op = Operator(eqn,
                      opt=('advanced', {
                          'openmp': True,
                          'cire-mincost-sops': 1,
                          'cire-rotate': True,
                          'par-nested': 0,
                          'par-collapse-ncores': 1,
                          'par-dynamic-work': 0
                      }))

        trees = retrieve_iteration_tree(op._func_table['bf0'].root)
        assert len(trees) == 2

        assert trees[0][0] is trees[1][0]
        assert trees[0][0].pragmas[0].value ==\
            'omp for collapse(2) schedule(dynamic,1)'
        assert not trees[0][2].pragmas
        assert not trees[0][3].pragmas
        assert trees[0][4].pragmas[0].value == ('omp parallel for collapse(1) '
                                                'schedule(dynamic,1) '
                                                'num_threads(nthreads_nested)')
        assert not trees[1][2].pragmas
        assert trees[1][3].pragmas[0].value == ('omp parallel for collapse(1) '
                                                'schedule(dynamic,1) '
                                                'num_threads(nthreads_nested)')
Exemplo n.º 23
0
    def test_collapsing_v2(self):
        """
        MFE from issue #1478.
        """
        n = 8
        m = 8
        nx, ny, nchi, ncho = 12, 12, 1, 1
        x, y = SpaceDimension("x"), SpaceDimension("y")
        ci, co = Dimension("ci"), Dimension("co")
        i, j = Dimension("i"), Dimension("j")
        grid = Grid((nx, ny), dtype=np.float32, dimensions=(x, y))

        X = Function(name="xin",
                     dimensions=(ci, x, y),
                     shape=(nchi, nx, ny),
                     grid=grid,
                     space_order=n // 2)
        dy = Function(name="dy",
                      dimensions=(co, x, y),
                      shape=(ncho, nx, ny),
                      grid=grid,
                      space_order=n // 2)
        dW = Function(name="dW",
                      dimensions=(co, ci, i, j),
                      shape=(ncho, nchi, n, m),
                      grid=grid)

        eq = [
            Eq(
                dW[co, ci, i, j], dW[co, ci, i, j] +
                dy[co, x, y] * X[ci, x + i - n // 2, y + j - m // 2])
            for i in range(n) for j in range(m)
        ]

        op = Operator(eq, opt=('advanced', {'openmp': True}))

        iterations = FindNodes(Iteration).visit(op)
        assert len(iterations) == 4
        assert iterations[0].ncollapse == 1
        assert iterations[1].is_Vectorized
        assert iterations[2].is_Sequential
        assert iterations[3].is_Sequential
Exemplo n.º 24
0
def test_at_w_mpi():
    """Make sure autotuning works in presence of MPI. MPI ranks work
    in isolation to determine the best block size, locally."""
    grid = Grid(shape=(8, 8))
    t = grid.stepping_dim
    x, y = grid.dimensions

    f = TimeFunction(name='f', grid=grid, time_order=1)
    f.data_with_halo[:] = 1.

    eq = Eq(f.forward, f[t, x-1, y] + f[t, x+1, y])
    op = Operator(eq, dle=('advanced', {'openmp': False, 'blockinner': True}))

    op.apply(time=-1, autotune=('basic', 'runtime'))
    # Nothing really happened, as not enough timesteps
    assert np.all(f.data_ro_domain[0] == 1.)
    assert np.all(f.data_ro_domain[1] == 1.)

    # The 'destructive' mode writes directly to `f` for whatever timesteps required
    # to perform the autotuning. Eventually, the result is complete garbage; note
    # also that this autotuning mode disables the halo exchanges
    op.apply(time=-1, autotune=('basic', 'destructive'))
    assert np.all(f._data_ro_with_inhalo.sum() == 904)

    # Check the halo hasn't been touched during AT
    glb_pos_map = grid.distributor.glb_pos_map
    if LEFT in glb_pos_map[x]:
        assert np.all(f._data_ro_with_inhalo[:, -1] == 1)
    else:
        assert np.all(f._data_ro_with_inhalo[:, 0] == 1)

    # Finally, try running w/o AT, just to be sure nothing was broken
    f.data_with_halo[:] = 1.
    op.apply(time=2)
    if LEFT in glb_pos_map[x]:
        assert np.all(f.data_ro_domain[1, 0] == 5.)
        assert np.all(f.data_ro_domain[1, 1] == 7.)
        assert np.all(f.data_ro_domain[1, 2:4] == 8.)
    else:
        assert np.all(f.data_ro_domain[1, 4:6] == 8)
        assert np.all(f.data_ro_domain[1, 6] == 7)
        assert np.all(f.data_ro_domain[1, 7] == 5)
Exemplo n.º 25
0
    def test_misc_dims(self):
        """
        Tests grid-independent :class:`Function`s, which require YASK's "misc"
        dimensions.
        """
        dx = Dimension(name='dx')
        grid = Grid(shape=(10, 10))
        x, y = grid.dimensions
        time = grid.time_dim

        u = TimeFunction(name='u',
                         grid=grid,
                         time_order=1,
                         space_order=4,
                         save=4)
        c = Function(name='c', dimensions=(x, dx), shape=(10, 5))

        step = Eq(u.forward,
                  (u[time, x - 2, y] * c[x, 0] + u[time, x - 1, y] * c[x, 1] +
                   u[time, x, y] * c[x, 2] + u[time, x + 1, y] * c[x, 3] +
                   u[time, x + 2, y] * c[x, 4]))

        for i in range(10):
            c.data[i, 0] = 1.0 + i
            c.data[i, 1] = 1.0 + i
            c.data[i, 2] = 3.0 + i
            c.data[i, 3] = 6.0 + i
            c.data[i, 4] = 5.0 + i

        u.data[:] = 0.0
        u.data[0, 2, :] = 2.0

        op = Operator(step)
        assert 'run_solution' in str(op)

        op(time_m=0, time_M=0)
        assert (np.all(u.data[1, 0, :] == 10.0))
        assert (np.all(u.data[1, 1, :] == 14.0))
        assert (np.all(u.data[1, 2, :] == 10.0))
        assert (np.all(u.data[1, 3, :] == 8.0))
        assert (np.all(u.data[1, 4, :] == 10.0))
        assert (np.all(u.data[1, 5:10, :] == 0.0))
Exemplo n.º 26
0
    def test_full_shape_with_subdims(self):
        """
        Like `test_full_alias_shape_after_blocking`, but SubDomains (and therefore
        SubDimensions) are used. Nevertheless, the temporary shape should still be
        dictated by the root Dimensions.
        """
        grid = Grid(shape=(3, 3, 3))
        x, y, z = grid.dimensions  # noqa
        t = grid.stepping_dim

        f = Function(name='f', grid=grid)
        f.data_with_halo[:] = 1.
        u = TimeFunction(name='u', grid=grid, space_order=3)
        u.data_with_halo[:] = 0.

        # Leads to 3D aliases
        eqn = Eq(u.forward, ((u[t, x, y, z] + u[t, x+1, y+1, z+1])*3*f +
                             (u[t, x+2, y+2, z+2] + u[t, x+3, y+3, z+3])*3*f + 1),
                 subdomain=grid.interior)
        op0 = Operator(eqn, dse='noop', dle=('advanced', {'openmp': True}))
        op1 = Operator(eqn, dse='aggressive', dle=('advanced', {'openmp': True}))

        xi0_blk_size = op1.parameters[-3]
        yi0_blk_size = op1.parameters[-2]
        z_size = op1.parameters[4]

        # Check Array shape
        arrays = [i for i in FindSymbols().visit(op1._func_table['bf0'].root)
                  if i.is_Array]
        assert len(arrays) == 1
        a = arrays[0]
        assert len(a.dimensions) == 3
        assert a.halo == ((1, 1), (1, 1), (1, 1))
        assert Add(*a.symbolic_shape[0].args) == xi0_blk_size + 2
        assert Add(*a.symbolic_shape[1].args) == yi0_blk_size + 2
        assert Add(*a.symbolic_shape[2].args) == z_size + 2
        # Check numerical output
        op0(time_M=1)
        exp = np.copy(u.data[:])
        u.data_with_halo[:] = 0.
        op1(time_M=1)
        assert np.all(u.data == exp)
Exemplo n.º 27
0
def conv(nx, ny, nchi, ncho, n, m):

    # Image size
    dt = np.float32
    x, y, ci, co = (SpaceDimension("x"), SpaceDimension("y"), Dimension("ci"),
                    Dimension("co"))
    grid = Grid((nchi, ncho, nx, ny), dtype=dt, dimensions=(ci, co, x, y))

    # Image
    im_in = Function(name="imi", dimensions=(ci, x, y),
                     shape=(nchi, nx, ny), grid=grid, space_order=n//2)

    # Output
    im_out = Function(name="imo", dimensions=(co, x, y),
                      shape=(ncho, nx, ny), grid=grid, space_order=n//2)

    # Weights
    i, j = Dimension("i"), Dimension("j")
    W = Function(name="W", dimensions=(co, ci, i, j), shape=(ncho, nchi, n, m),
                 grid=grid)

    # Popuate weights with deterministic values
    for i in range(ncho):
        for j in range(nchi):
            W.data[i, j, :, :] = np.linspace(i+j, i+j+(n*m), n*m).reshape(n, m)

    # Convlution
    conv = [Eq(im_out, im_out
               + sum([W[co, ci, i2, i1] * im_in[ci, x+i1-n//2, y+i2-m//2]
                      for i1 in range(n) for i2 in range(m)]))]

    op = Operator(conv)
    op.cfunction

    # Initialize the input/output
    input_data = np.linspace(-1, 1, nx*ny*nchi).reshape(nchi, nx, ny)
    im_in.data[:] = input_data.astype(np.float32)
    im_out.data

    op()

    return im_out.data, im_in.data
Exemplo n.º 28
0
    def test_subdimleft_parallel(self):
        """
        Tests application of an Operator consisting of a subdimension
        defined over different sub-regions, explicitly created through the
        use of :class:`SubDimension`s.

        This tests that flow direction is not being automatically inferred
        from whether the subdimension is on the left or right boundary.
        """
        grid = Grid(shape=(20, 20))
        x, y = grid.dimensions
        t = grid.stepping_dim
        thickness = 4

        u = TimeFunction(name='u',
                         save=None,
                         grid=grid,
                         space_order=0,
                         time_order=1)

        xl = SubDimension.left(name='xl', parent=x, thickness=thickness)

        yi = SubDimension.middle(name='yi',
                                 parent=y,
                                 thickness_left=thickness,
                                 thickness_right=thickness)

        # Can be done in parallel
        eq = Eq(u[t + 1, xl, yi], u[t, xl, yi] + 1)

        op = Operator([eq])

        iterations = FindNodes(Iteration).visit(op)
        assert all(i.is_Affine and i.is_Parallel for i in iterations
                   if i.dim in [xl, yi])

        op.apply(time_m=0, time_M=0)

        assert np.all(u.data[1, 0:thickness, 0:thickness] == 0)
        assert np.all(u.data[1, 0:thickness, -thickness:] == 0)
        assert np.all(u.data[1, 0:thickness, thickness:-thickness] == 1)
        assert np.all(u.data[1, thickness + 1:, :] == 0)
Exemplo n.º 29
0
def test_cache_blocking_imperfect_nest_v2(blockinner):
    """
    Test that a non-perfect Iteration nest is blocked correctly. This
    is slightly different than ``test_cache_blocking_imperfect_nest``
    as here only one Iteration gets blocked.
    """
    shape = (16, 16, 16)
    grid = Grid(shape=shape, dtype=np.float64)

    u = TimeFunction(name='u', grid=grid, space_order=2)
    u.data[:] = np.linspace(0, 1, reduce(mul, shape), dtype=np.float64).reshape(shape)

    eq = Eq(u.forward, 0.01*u.dy.dy)

    op0 = Operator(eq, opt='noop')
    op1 = Operator(eq, opt=('cire-sops', {'blockinner': blockinner}))
    op2 = Operator(eq, opt=('advanced-fsg', {'blockinner': blockinner}))

    # First, check the generated code
    trees = retrieve_iteration_tree(op2._func_table['bf0'].root)
    assert len(trees) == 2
    assert len(trees[0]) == len(trees[1])
    assert all(i is j for i, j in zip(trees[0][:2], trees[1][:2]))
    assert trees[0][2] is not trees[1][2]
    assert trees[0].root.dim.is_Incr
    assert trees[1].root.dim.is_Incr
    assert op2.parameters[6] is trees[0].root.step

    op0(time_M=0)

    u1 = TimeFunction(name='u1', grid=grid, space_order=2)
    u1.data[:] = np.linspace(0, 1, reduce(mul, shape), dtype=np.float64).reshape(shape)

    op1(time_M=0, u=u1)

    u2 = TimeFunction(name='u2', grid=grid, space_order=2)
    u2.data[:] = np.linspace(0, 1, reduce(mul, shape), dtype=np.float64).reshape(shape)

    op2(time_M=0, u=u2)

    assert np.allclose(u.data, u1.data, rtol=1e-07)
    assert np.allclose(u.data, u2.data, rtol=1e-07)
Exemplo n.º 30
0
    def test_argument_from_index_constant(self):
        nx, ny = 30, 30
        grid = Grid(shape=(nx, ny))
        x, y = grid.dimensions

        arbdim = Dimension('arb')
        u = TimeFunction(name='u', grid=grid, save=None, time_order=2, space_order=0)
        snap = Function(name='snap', dimensions=(arbdim, x, y), shape=(5, nx, ny),
                        space_order=0)

        save_t = Constant(name='save_t', dtype=np.int32)
        save_slot = Constant(name='save_slot', dtype=np.int32)

        expr = Eq(snap.subs(arbdim, save_slot), u.subs(grid.stepping_dim, save_t))
        op = Operator(expr)
        u.data[:] = 0.0
        snap.data[:] = 0.0
        u.data[0, 10, 10] = 1.0
        op.apply(save_t=0, save_slot=1)
        assert snap.data[1, 10, 10] == 1.0
Exemplo n.º 31
0
    def test_default_functions(self):
        """
        Test the default argument derivation for functions.
        """
        grid = Grid(shape=(5, 6, 7))
        f = TimeFunction(name='f', grid=grid)
        g = Function(name='g', grid=grid)
        op = Operator(Eq(g, g + f))

        expected = {
            'x_size': 5, 'x_m': 0, 'x_M': 4,
            'y_size': 6, 'y_m': 0, 'y_M': 5,
            'z_size': 7, 'z_m': 0, 'z_M': 6,
            'f': f.data_allocated, 'g': g.data_allocated,
        }
        self.verify_arguments(op.arguments(time=4), expected)
        exp_parameters = ['f', 'g', 'x_m', 'x_M', 'x_size', 'y_m',
                          'y_M', 'y_size', 'z_m', 'z_M', 'z_size',
                          'time_m', 'time_M']
        self.verify_parameters(op.parameters, exp_parameters)