def test_no_index(self): """Test behaviour when the ConditionalDimension is used as a symbol in an expression.""" nt = 19 grid = Grid(shape=(11, 11)) time = grid.time_dim u = TimeFunction(name='u', grid=grid) assert(grid.stepping_dim in u.indices) v = Function(name='v', grid=grid) factor = 4 time_subsampled = ConditionalDimension('t_sub', parent=time, factor=factor) eqns = [Eq(u.forward, u + 1), Eq(v, v + u*u*time_subsampled)] op = Operator(eqns) op.apply(t_M=nt-2) assert np.all(np.allclose(u.data[(nt-1) % 3], nt-1)) # expected result is 1024 # v = u[0]**2 * 0 + u[4]**2 * 1 + u[8]**2 * 2 + u[12]**2 * 3 + u[16]**2 * 4 # with u[t] = t # v = 16 * 1 + 64 * 2 + 144 * 3 + 256 * 4 = 1600 assert np.all(np.allclose(v.data, 1600))
def test_halo_indexing(self): """ Tests packing/unpacking data in :class:`Function` objects when some halo region is present. """ domain_shape = (16, 16, 16) grid = Grid(shape=domain_shape) u = Function(name='yu3D', grid=grid, space_order=2) assert u.shape == u.data.shape == domain_shape assert u._shape_with_inhalo == u.data_with_halo.shape == (20, 20, 20) assert u.shape_with_halo == u._shape_with_inhalo # W/o MPI, these two coincide # Test simple insertion and extraction u.data_with_halo[0, 0, 0] = 1. u.data[0, 0, 0] = 2. assert u.data_with_halo[0, 0, 0] == 1. assert u.data[0, 0, 0] == 2. assert u.data_with_halo[2, 2, 2] == 2. # Test negative indices u.data_with_halo[-1, -1, -1] = 3. assert u.data[-1, -1, -1] == 0. assert u.data_with_halo[-1, -1, -1] == 3.
def test_function_wo(self): grid = Grid(shape=(3, 3, 3)) i = Dimension(name='i') f = Function(name='f', shape=(1, ), dimensions=(i, ), grid=grid) u = TimeFunction(name='u', grid=grid) eqns = [Eq(u.forward, u + 1), Eq(f[0], u[0, 0, 0, 0])] op = Operator(eqns, opt='noop') assert len(op.body[1].header) == 2 assert len(op.body[1].footer) == 2 assert op.body[1].header[0].value ==\ ('omp target enter data map(to: u[0:u_vec->size[0]]' '[0:u_vec->size[1]][0:u_vec->size[2]][0:u_vec->size[3]])') assert str(op.body[1].header[1]) == '' assert str(op.body[1].footer[0]) == '' assert op.body[1].footer[1].contents[0].value ==\ ('omp target update from(u[0:u_vec->size[0]]' '[0:u_vec->size[1]][0:u_vec->size[2]][0:u_vec->size[3]])') assert op.body[1].footer[1].contents[1].value ==\ ('omp target exit data map(release: u[0:u_vec->size[0]]' '[0:u_vec->size[1]][0:u_vec->size[2]][0:u_vec->size[3]])')
def test_subdimleft_notparallel(self): """ Tests application of an Operator consisting of a subdimension defined over different sub-regions, explicitly created through the use of SubDimensions. 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=1, time_order=0) xl = SubDimension.left(name='xl', parent=x, thickness=thickness) yi = SubDimension.middle(name='yi', parent=y, thickness_left=thickness, thickness_right=thickness) # Flows inward (i.e. forward) rather than outward eq = Eq(u[t+1, xl, yi], u[t+1, xl-1, yi] + 1) op = Operator([eq]) iterations = FindNodes(Iteration).visit(op) assert all(i.is_Affine and i.is_Sequential for i in iterations if i.dim == xl) assert all(i.is_Affine and i.is_Parallel for i in iterations if i.dim == yi) op.apply(time_m=1, time_M=1) assert all(np.all(u.data[0, :thickness, thickness+i] == [1, 2, 3, 4]) for i in range(12)) assert np.all(u.data[0, thickness:] == 0) assert np.all(u.data[0, :, thickness+12:] == 0)
def test_empty_arrays(self): """ MFE for issue #1641. """ grid = Grid(shape=(4, 4), extent=(3.0, 3.0)) f = TimeFunction(name='f', grid=grid, space_order=0) f.data[:] = 1. sf1 = SparseTimeFunction(name='sf1', grid=grid, npoint=0, nt=10) sf2 = SparseTimeFunction(name='sf2', grid=grid, npoint=0, nt=10) assert sf1.size == 0 assert sf2.size == 0 eqns = sf1.inject(field=f, expr=sf1 + sf2 + 1.) op = Operator(eqns) op.apply() assert np.all(f.data == 1.) # Again, but with a MatrixSparseTimeFunction mat = scipy.sparse.coo_matrix((0, 0), dtype=np.float32) sf = MatrixSparseTimeFunction(name="s", grid=grid, r=2, matrix=mat, nt=10) assert sf.size == 0 eqns = sf.interpolate(f) op = Operator(eqns) sf.manual_scatter() op(time_m=0, time_M=9) sf.manual_gather() assert np.all(f.data == 1.)
def test_precomputed_interpolation(): """ Test interpolation with PrecomputedSparseFunction which accepts precomputed values for coefficients """ shape = (101, 101) points = [(.05, .9), (.01, .8), (0.07, 0.84)] origin = (0, 0) grid = Grid(shape=shape, origin=origin) r = 2 # Constant for linear interpolation # because we interpolate across 2 neighbouring points in each dimension def init(data): for i in range(data.shape[0]): for j in range(data.shape[1]): data[i, j] = sin(grid.spacing[0] * i) + sin(grid.spacing[1] * j) return data m = Function(name='m', grid=grid, initializer=init, space_order=0) gridpoints, coefficients = precompute_linear_interpolation( points, grid, origin) sf = PrecomputedSparseFunction(name='s', grid=grid, r=r, npoint=len(points), gridpoints=gridpoints, coefficients=coefficients) eqn = sf.interpolate(m) op = Operator(eqn) op() expected_values = [sin(point[0]) + sin(point[1]) for point in points] assert (all(np.isclose(sf.data, expected_values, rtol=1e-6)))
def test_simple_indexing(self): """Test data packing/unpacking via basic indexing.""" grid = Grid(shape=(16, 16, 16)) u = Function(name='yu3D', grid=grid, space_order=0) # Test simple insertion and extraction u.data[0, 1, 1] = 1. assert u.data[0, 0, 0] == 0. assert u.data[0, 1, 1] == 1. assert np.all(u.data == u.data[:, :, :]) assert 1. in u.data[0] assert 1. in u.data[0, 1] # Test negative indices assert u.data[0, -15, -15] == 1. u.data[6, 0, 0] = 1. assert u.data[-10, :, :].sum() == 1. # Test setting whole array to given value u.data[:] = 3. assert np.all(u.data == 3.) # Test insertion of single value into block u.data[5, :, 5] = 5. assert np.all(u.data[5, :, 5] == 5.) # Test extraction of block with negative indices sliced = u.data[-11, :, -11] assert sliced.shape == (16, ) assert np.all(sliced == 5.) # Test insertion of block into block block = np.ndarray(shape=(1, 16, 1), dtype=np.float32) block.fill(4.) u.data[4:5, :, 4:5] = block assert np.all(u.data[4, :, 4] == block)
def __init__(self, origin, spacing, shape, space_order, nbpml=20, dtype=np.float32): self.shape = shape self.nbpml = int(nbpml) self.origin = tuple([dtype(o) for o in origin]) # Origin of the computational domain with PML to inject/interpolate # at the correct index origin_pml = tuple( [dtype(o - s * nbpml) for o, s in zip(origin, spacing)]) phydomain = PhysicalDomain(self.nbpml) shape_pml = np.array(shape) + 2 * self.nbpml # Physical extent is calculated per cell, so shape - 1 extent = tuple(np.array(spacing) * (shape_pml - 1)) self.grid = Grid(extent=extent, shape=shape_pml, origin=origin_pml, dtype=dtype, subdomains=phydomain)
def test_tasking_fused(self): nt = 10 bundle0 = Bundle() grid = Grid(shape=(10, 10, 10), subdomains=bundle0) tmp = Function(name='tmp', grid=grid) u = TimeFunction(name='u', grid=grid, save=nt) v = TimeFunction(name='v', grid=grid, save=nt) w = TimeFunction(name='w', grid=grid) eqns = [Eq(w.forward, w + 1), Eq(tmp, w.forward), Eq(u.forward, tmp, subdomain=bundle0), Eq(v.forward, tmp, subdomain=bundle0)] op = Operator(eqns, opt=('tasking', 'fuse', 'orchestrate')) # Check generated code assert len(retrieve_iteration_tree(op)) == 5 locks = [i for i in FindSymbols().visit(op) if isinstance(i, Lock)] assert len(locks) == 1 # Only 1 because it's only `tmp` that needs protection assert len(op._func_table) == 2 exprs = FindNodes(Expression).visit(op._func_table['copy_device_to_host0'].root) assert len(exprs) == 19 assert str(exprs[12]) == 'int id = sdata0->id;' assert str(exprs[13]) == 'const int time = sdata0->time;' assert str(exprs[14]) == 'lock0[0] = 1;' assert exprs[15].write is u assert exprs[16].write is v assert str(exprs[17]) == 'lock0[0] = 2;' assert str(exprs[18]) == 'sdata0->flag = 1;' op.apply(time_M=nt-2) assert np.all(u.data[nt-1] == 9) assert np.all(v.data[nt-1] == 9)
def test_subdimensions(self): nt = 10 grid = Grid(shape=(10, 10, 10)) x, y, z = grid.dimensions xi = SubDimension.middle(name='xi', parent=x, thickness_left=2, thickness_right=2) yi = SubDimension.middle(name='yi', parent=y, thickness_left=2, thickness_right=2) zi = SubDimension.middle(name='zi', parent=z, thickness_left=2, thickness_right=2) u = TimeFunction(name='u', grid=grid, save=nt) u1 = TimeFunction(name='u', grid=grid, save=nt) eqn = Eq(u.forward, u + 1).xreplace({x: xi, y: yi, z: zi}) op0 = Operator(eqn, opt='noop') op1 = Operator(eqn, opt='buffering') # Check generated code assert len(retrieve_iteration_tree(op1)) == 2 assert len([i for i in FindSymbols().visit(op1) if i.is_Array]) == 1 op0.apply(time_M=nt-2) op1.apply(time_M=nt-2, u=u1) assert np.all(u.data == u1.data)
def test_composite_full(self): nt = 10 grid = Grid(shape=(4, 4)) u = TimeFunction(name='u', grid=grid, save=nt) v = TimeFunction(name='v', grid=grid, save=nt) u1 = TimeFunction(name='u', grid=grid, save=nt) v1 = TimeFunction(name='v', grid=grid, save=nt) eqns = [Eq(u.forward, u + v + 1), Eq(v.forward, u + v + v.backward)] op0 = Operator(eqns, opt=('noop', {'gpu-fit': (u, v)})) op1 = Operator(eqns, opt=('buffering', 'tasking', 'streaming', 'orchestrate')) # Check generated code assert len(retrieve_iteration_tree(op1)) == 9 assert len([i for i in FindSymbols().visit(op1) if isinstance(i, Lock)]) == 2 op0.apply(time_M=nt-2) op1.apply(time_M=nt-2, u=u1, v=v1) assert np.all(u.data == u1.data) assert np.all(v.data == v1.data)
def test_streaming_postponed_deletion(self): nt = 10 grid = Grid(shape=(10, 10, 10)) u = TimeFunction(name='u', grid=grid) v = TimeFunction(name='v', grid=grid) usave = TimeFunction(name='usave', grid=grid, save=nt) u1 = TimeFunction(name='u', grid=grid) v1 = TimeFunction(name='v', grid=grid) for i in range(nt): usave.data[i, :] = i eqns = [Eq(u.forward, u + usave), Eq(v.forward, v + u.forward.dx + usave)] op0 = Operator(eqns, opt=('noop', {'gpu-fit': usave})) op1 = Operator(eqns, opt=('streaming', 'orchestrate')) op0.apply(time_M=nt-1) op1.apply(time_M=nt-1, u=u1, v=v1) assert np.all(u.data == u1.data) assert np.all(v.data == v1.data)
def test_shape(self): class sd0(SubDomain): name = 'd0' def define(self, dimensions): x, y = dimensions return {x: ('middle', 1, 6), y: ('middle', 1, 1)} s_d0 = sd0() class sd1(SubDomain): name = 'd1' def define(self, dimensions): x, y = dimensions return {x: ('right', 4), y: ('left', 2)} s_d1 = sd1() class sd2(SubDomain): name = 'd2' def define(self, dimensions): x, y = dimensions return {x: ('left', 3), y: ('middle', 1, 2)} s_d2 = sd2() grid = Grid(shape=(10, 10), subdomains=(s_d0, s_d1, s_d2)) assert grid.subdomains['domain'].shape == (10, 10) assert grid.subdomains['interior'].shape == (8, 8) assert grid.subdomains['d0'].shape == (3, 8) assert grid.subdomains['d1'].shape == (4, 2) assert grid.subdomains['d2'].shape == (3, 7)
def test_basic(self): grid = Grid(shape=(3, 3, 3)) u = TimeFunction(name='u', grid=grid) op = Operator(Eq(u.forward, u + 1), platform='nvidiaX', language='openacc') trees = retrieve_iteration_tree(op) assert len(trees) == 1 assert trees[0][1].pragmas[0].value ==\ 'acc parallel loop collapse(3)' assert op.body[1].header[0].value ==\ ('acc enter data copyin(u[0:u_vec->size[0]]' '[0:u_vec->size[1]][0:u_vec->size[2]][0:u_vec->size[3]])') assert str(op.body[1].footer[0]) == '' assert op.body[1].footer[1].contents[0].value ==\ ('acc exit data copyout(u[0:u_vec->size[0]]' '[0:u_vec->size[1]][0:u_vec->size[2]][0:u_vec->size[3]])') assert op.body[1].footer[1].contents[1].value ==\ ('acc exit data delete(u[0:u_vec->size[0]]' '[0:u_vec->size[1]][0:u_vec->size[2]][0:u_vec->size[3]])')
def __init__(self, origin, spacing, shape, space_order, nbl=20, dtype=np.float32, subdomains=(), damp_mask=False): self.shape = shape self.nbl = int(nbl) self.origin = tuple([dtype(o) for o in origin]) # Origin of the computational domain with boundary to inject/interpolate # at the correct index origin_pml = tuple( [dtype(o - s * nbl) for o, s in zip(origin, spacing)]) phydomain = PhysicalDomain(self.nbl) subdomains = subdomains + (phydomain, ) shape_pml = np.array(shape) + 2 * self.nbl # Physical extent is calculated per cell, so shape - 1 extent = tuple(np.array(spacing) * (shape_pml - 1)) self.grid = Grid(extent=extent, shape=shape_pml, origin=origin_pml, dtype=dtype, subdomains=subdomains) if self.nbl != 0: # Create dampening field as symbol `damp` self.damp = Function(name="damp", grid=self.grid) initialize_damp(self.damp, self.nbl, self.spacing, mask=damp_mask) self._physical_parameters = ['damp'] else: self.damp = 1 if damp_mask else 0 self._physical_parameters = []
def test_dimension_sort(self, expr, expected): """ Tests that ``dimension_sort()`` provides meaningful Dimension orderings. """ grid = Grid(shape=(10, 10)) p = Dimension('p') r = Dimension('r') d = Dimension('d') time = grid.time_dim # noqa x, y = grid.dimensions a = Function(name='a', dimensions=(time, p), shape=(10, 1)) # noqa b = Function(name='b', dimensions=(time, x, y), shape=(10, 10, 10)) # noqa c = Function( name='c', shape=(1, 2), # noqa dimensions=(p, d), dtype=np.int32) f = Function(name='f', dimensions=(p, r), shape=(1, 1)) # noqa expr = eval(expr) assert list(dimension_sort(expr)) == eval(expected)
def test_iteration_parallelism_3d(self, exprs, atomic, parallel): """Tests detection of PARALLEL_* properties.""" grid = Grid(shape=(10, 10, 10)) time = grid.time_dim # noqa t = grid.stepping_dim # noqa x, y, z = grid.dimensions # noqa p = Dimension(name='p') d = Dimension(name='d') rx = Dimension(name='rx') ry = Dimension(name='ry') rz = Dimension(name='rz') u = Function(name='u', grid=grid) # noqa v = TimeFunction(name='v', grid=grid, save=None) # noqa cx = Function(name='coeff_x', dimensions=(p, rx), shape=(1, 2)) # noqa cy = Function(name='coeff_y', dimensions=(p, ry), shape=(1, 2)) # noqa cz = Function(name='coeff_z', dimensions=(p, rz), shape=(1, 2)) # noqa gp = Function(name='gridpoints', dimensions=(p, d), shape=(1, 3)) # noqa src = Function(name='src', dimensions=(p,), shape=(1,)) # noqa rcv = Function(name='rcv', dimensions=(time, p), shape=(100, 1), space_order=0) # noqa # List comprehension would need explicit locals/globals mappings to eval for i, e in enumerate(list(exprs)): exprs[i] = eval(e) # Use 'openmp' here instead of 'advanced' to disable loop blocking op = Operator(exprs, dle='openmp') iters = FindNodes(Iteration).visit(op) assert all([i.is_ParallelAtomic for i in iters if i.dim.name in atomic]) assert all([not i.is_ParallelAtomic for i in iters if i.dim.name not in atomic]) assert all([i.is_Parallel for i in iters if i.dim.name in parallel]) assert all([not i.is_Parallel for i in iters if i.dim.name not in parallel])
def test_shifted(self): nt = 19 grid = Grid(shape=(11, 11)) time = grid.time_dim u = TimeFunction(name='u', grid=grid) assert (grid.stepping_dim in u.indices) u2 = TimeFunction(name='u2', grid=grid, save=nt) assert (time in u2.indices) factor = 4 time_subsampled = ConditionalDimension('t_sub', parent=time, factor=factor) usave = TimeFunction(name='usave', grid=grid, save=2, time_dim=time_subsampled) assert (time_subsampled in usave.indices) t_sub_shift = Constant(name='t_sub_shift', dtype=np.int32) eqns = [ Eq(u.forward, u + 1.), Eq(u2.forward, u2 + 1.), Eq(usave.subs(time_subsampled, time_subsampled - t_sub_shift), u) ] op = Operator(eqns) # Starting at time_m=10, so time_subsampled - t_sub_shift is in range op.apply(time_m=10, time_M=nt - 2, t_sub_shift=3) assert np.all(np.allclose(u.data[0], 8)) assert np.all([np.allclose(u2.data[i], i - 10) for i in range(10, nt)]) assert np.all( [np.allclose(usave.data[i], 2 + i * factor) for i in range(2)])
def test_array_reduction(self, so, dim): """ Test generation of OpenMP reduction clauses involving Function's. """ grid = Grid(shape=(3, 3, 3)) d = grid.dimensions[dim] f = Function(name='f', shape=(3,), dimensions=(d,), grid=grid, space_order=so) u = TimeFunction(name='u', grid=grid) op = Operator(Inc(f, u + 1), opt=('openmp', {'par-collapse-ncores': 1})) iterations = FindNodes(Iteration).visit(op) assert "reduction(+:f[0:f_vec->size[0]])" in iterations[1].pragmas[0].value try: op(time_M=1) except: # Older gcc <6.1 don't support reductions on array info("Un-supported older gcc version for array reduction") assert True return assert np.allclose(f.data, 18)
def test_streaming_two_buffers(self, opt, ntmps, nfuncs): nt = 10 grid = Grid(shape=(4, 4)) u = TimeFunction(name='u', grid=grid) usave = TimeFunction(name='usave', grid=grid, save=nt) vsave = TimeFunction(name='vsave', grid=grid, save=nt) for i in range(nt): usave.data[i, :] = i vsave.data[i, :] = i eqn = Eq(u.forward, u + usave + vsave) op = Operator(eqn, opt=opt) # Check generated code assert len(op._func_table) == nfuncs assert len([i for i in FindSymbols().visit(op) if i.is_Array]) == ntmps op.apply(time_M=nt - 2) assert np.all(u.data[0] == 56) assert np.all(u.data[1] == 72)
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)')
def test_injection_wodup_wtime(self): """ Just like ``test_injection_wodup``, but using a SparseTimeFunction instead of a SparseFunction. Hence, the data scattering/gathering now has to correctly pack/unpack multidimensional arrays. """ grid = Grid(shape=(4, 4), extent=(3.0, 3.0)) save = 3 f = TimeFunction(name='f', grid=grid, save=save, space_order=0) f.data[:] = 0. coords = np.array([(0.5, 0.5), (0.5, 2.5), (2.5, 0.5), (2.5, 2.5)]) sf = SparseTimeFunction(name='sf', grid=grid, nt=save, npoint=len(coords), coordinates=coords) sf.data[0, :] = 4. sf.data[1, :] = 8. sf.data[2, :] = 12. op = Operator(sf.inject(field=f, expr=sf + 1)) op.apply() assert np.all(f.data[0] == 1.25) assert np.all(f.data[1] == 2.25) assert np.all(f.data[2] == 3.25)
def test_operator_leakage_function(): """ Test to ensure that Operator creation does not cause memory leaks for (Time)Functions. """ grid = Grid(shape=(5, 6)) f = Function(name='f', grid=grid) g = TimeFunction(name='g', grid=grid) # Take weakrefs to test whether symbols are dead or alive w_f = weakref.ref(f) w_g = weakref.ref(g) # Create operator and delete everything again op = Operator(Eq(f, 2 * g)) w_op = weakref.ref(op) del op del f del g clear_cache() # Test whether things are still hanging around assert w_f() is None assert w_g() is None assert w_op() is None
def test_bcs(self): """ Tests application of an Operator consisting of multiple equations defined over different sub-regions, explicitly created through the use of SubDimensions. """ 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) xleft = SubDimension.left(name='xleft', parent=x, thickness=thickness) xi = SubDimension.middle(name='xi', parent=x, thickness_left=thickness, thickness_right=thickness) xright = SubDimension.right(name='xright', parent=x, thickness=thickness) yi = SubDimension.middle(name='yi', parent=y, thickness_left=thickness, thickness_right=thickness) t_in_centre = Eq(u[t+1, xi, yi], 1) leftbc = Eq(u[t+1, xleft, yi], u[t+1, xleft+1, yi] + 1) rightbc = Eq(u[t+1, xright, yi], u[t+1, xright-1, yi] + 1) op = Operator([t_in_centre, leftbc, rightbc]) op.apply(time_m=1, time_M=1) assert np.all(u.data[0, :, 0:thickness] == 0.) assert np.all(u.data[0, :, -thickness:] == 0.) assert all(np.all(u.data[0, i, thickness:-thickness] == (thickness+1-i)) for i in range(thickness)) assert all(np.all(u.data[0, -i, thickness:-thickness] == (thickness+2-i)) for i in range(1, thickness + 1)) assert np.all(u.data[0, thickness:-thickness, thickness:-thickness] == 1.)
def test_symbolic_factor(self): """ Test ConditionalDimension with symbolic factor (provided as a Constant). """ g = Grid(shape=(4, 4, 4)) u = TimeFunction(name='u', grid=g, time_order=0) fact = Constant(name='fact', dtype=np.int32, value=4) tsub = ConditionalDimension(name='tsub', parent=g.time_dim, factor=fact) usave = TimeFunction(name='usave', grid=g, time_dim=tsub, save=4) op = Operator([Eq(u, u + 1), Eq(usave, u)]) op.apply(time=7) # Use `fact`'s default value, 4 assert np.all(usave.data[0] == 1) assert np.all(usave.data[1] == 5) u.data[:] = 0. op.apply(time=7, fact=2) assert np.all(usave.data[0] == 1) assert np.all(usave.data[1] == 3) assert np.all(usave.data[2] == 5) assert np.all(usave.data[3] == 7)
def test_basic(self): nt = 19 grid = Grid(shape=(11, 11)) time = grid.time_dim u = TimeFunction(name='u', grid=grid) assert(grid.stepping_dim in u.indices) u2 = TimeFunction(name='u2', grid=grid, save=nt) assert(time in u2.indices) factor = 4 time_subsampled = ConditionalDimension('t_sub', parent=time, factor=factor) usave = TimeFunction(name='usave', grid=grid, save=(nt+factor-1)//factor, time_dim=time_subsampled) assert(time_subsampled in usave.indices) eqns = [Eq(u.forward, u + 1.), Eq(u2.forward, u2 + 1.), Eq(usave, u)] op = Operator(eqns) op.apply(t_M=nt-2) assert np.all(np.allclose(u.data[(nt-1) % 3], nt-1)) assert np.all([np.allclose(u2.data[i], i) for i in range(nt)]) assert np.all([np.allclose(usave.data[i], i*factor) for i in range((nt+factor-1)//factor)])
def test_subdim_middle(self): """ Tests that instantiating SubDimensions using the classmethod constructors works correctly. """ grid = Grid(shape=(4, 4, 4)) x, y, z = grid.dimensions t = grid.stepping_dim # noqa u = TimeFunction(name='u', grid=grid) # noqa xi = SubDimension.middle(name='xi', parent=x, thickness_left=1, thickness_right=1) eqs = [Eq(u.forward, u + 1)] eqs = [e.subs(x, xi) for e in eqs] op = Operator(eqs) u.data[:] = 1.0 op.apply(time_M=1) assert np.all(u.data[1, 0, :, :] == 1) assert np.all(u.data[1, -1, :, :] == 1) assert np.all(u.data[1, 1:3, :, :] == 2)
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
return skipper(True, "mpi4py/MPI not installed") continue # Skip if an unsupported backend if i == configuration['backend']: return skipper(True, "`%s` backend unsupported" % i) try: _, noi = i.split('no') if noi != configuration['backend']: return skipper(True, "`%s` backend unsupported" % i) except ValueError: pass return skipper(False, "") # Testing dimensions for space and time grid = Grid(shape=(3, 3, 3)) time = grid.time_dim t = grid.stepping_dim x, y, z = grid.dimensions def scalar(name): return Scalar(name=name) def array(name, shape, dimensions, scope='heap'): return Array(name=name, shape=shape, dimensions=dimensions, scope=scope) def constant(name): return Constant(name=name)
p[0, :] = 0 p[nx-1, :] = 0 p[:, 0] = 0 p[:, ny-1] = 0 plot_field(p, xmax=xmax, ymax=ymax, view=(30, 225)) from devito import Grid, Function, TimeFunction, Operator, configuration, Eq, solve # Silence the runtime performance logging configuration['log_level'] = 'ERROR' # Now with Devito we will turn `p` into `TimeFunction` object # to make all the buffer switching implicit grid = Grid(shape=(nx, ny), extent=(1., 2.)) p = Function(name='p', grid=grid, space_order=2) pd = Function(name='pd', grid=grid, space_order=2) p.data[:] = 0. pd.data[:] = 0. # Initialise the source term `b` b = Function(name='b', grid=grid) b.data[:] = 0. b.data[int(nx / 4), int(ny / 4)] = 100 b.data[int(3 * nx / 4), int(3 * ny / 4)] = -100 # Create Laplace equation base on `pd` eq = Eq(pd.laplace, b, subdomain=grid.interior) # Let SymPy solve for the central stencil point stencil = solve(eq, pd)