def test_sum_nodes_to_edges(self): """Creates a 1D grid with edge values numbered consecutively. Iterates over edges, summing the node values.""" nedges = nnodes - 1 nodes = op2.Set(nnodes, "nodes") edges = op2.Set(nedges, "edges") node_vals = op2.Dat(nodes, numpy.array(range(nnodes), dtype=numpy.uint32), numpy.uint32, "node_vals") edge_vals = op2.Dat(edges, numpy.array([0] * nedges, dtype=numpy.uint32), numpy.uint32, "edge_vals") e_map = numpy.array([(i, i + 1) for i in range(nedges)], dtype=numpy.uint32) edge2node = op2.Map(edges, nodes, 2, e_map, "edge2node") kernel_sum = """ static void sum(unsigned int* edge, unsigned int *nodes) { *edge = nodes[0] + nodes[1]; } """ op2.par_loop(op2.Kernel(kernel_sum, "sum"), edges, edge_vals(op2.WRITE), node_vals(op2.READ, edge2node)) expected = numpy.asarray(range(1, nedges * 2 + 1, 2)) assert all(expected == edge_vals.data)
def test_sum_nodes_to_edges(self): """Creates a 1D grid with edge values numbered consecutively. Iterates over edges, summing the node values.""" nedges = nnodes - 1 nodes = op2.Set(nnodes, "nodes") edges = op2.Set(nedges, "edges") node_vals = op2.Dat(nodes, numpy.arange(nnodes, dtype=numpy.uint32), numpy.uint32, "node_vals") edge_vals = op2.Dat(edges, numpy.zeros(nedges, dtype=numpy.uint32), numpy.uint32, "edge_vals") e_map = numpy.array([(i, i + 1) for i in range(nedges)], dtype=numpy.uint32) edge2node = op2.Map(edges, nodes, 2, e_map, "edge2node") kernel_sum = FunDecl( "void", "kernel_sum", [ Decl("int*", c_sym("nodes"), qualifiers=["unsigned"]), Decl("int*", c_sym("edge"), qualifiers=["unsigned"]) ], c_for("i", 2, Incr(c_sym("*edge"), Symbol("nodes", ("i", ))))) op2.par_loop(op2.Kernel(kernel_sum, "kernel_sum"), edges, node_vals(op2.READ, edge2node[op2.i[0]]), edge_vals(op2.INC)) expected = numpy.arange(1, nedges * 2 + 1, 2) assert all(expected == edge_vals.data)
def time_sparsity(n): nodes = op2.Set(n) cells = op2.Set(n - 1) m = op2.Map(cells, nodes, 2, np.concatenate((np.arange(n - 1), np.arange(1, n)))) t = clock() s = op2.Sparsity((m, m), 1) return clock() - t
def preprocess(vertices=V, edges=E): """ Initial step to create PyOP2 Sets and Maps with correct dimensions to create indirection for the graph problem: 1) poses is a Set of all poses (parameter blocks) 2) constraints is a Set of all measurements (edges between pose blocks) 3) constraints_to_poses maps a constraint to 2 poses 4) constraints_to_constraints maps a constraint to the right number of data based on dimension of constraints_to_poses 5) poses_to_poses maps poses to data based on dimension of poses """ global NUM_POSES, NUM_CONSTRAINTS, POSES_DIM, CONSTRAINT_DIM, POSES_PER_CONSTRAINT if (not vertices is None) and (not edges is None): NUM_CONSTRAINTS = len(edges) NUM_POSES = len(vertices) poses = op2.Set(NUM_POSES, 'poses') constraints = op2.Set(NUM_CONSTRAINTS, 'constraints') if _VERBOSE: print '2D BA: %d poses and %d constraints between them' \ % (NUM_POSES, NUM_CONSTRAINTS) print '2D BA: pose dimension %d and constraint dimensions %d' \ % (POSES_DIM, CONSTRAINT_DIM) edgemappings = edges[['from_v', 'to_v']].values.reshape(POSES_PER_CONSTRAINT * NUM_CONSTRAINTS) if _DEBUG: print 'ba edges:', edgemappings, edgemappings.dtype, edgemappings.shape constraints_to_poses = op2.Map(constraints, poses, POSES_PER_CONSTRAINT, edgemappings, 'constraints_to_poses') constraints_to_constraints = op2.Map(constraints, constraints, CONSTRAINT_DIM, balib.identity_map(NUM_CONSTRAINTS, CONSTRAINT_DIM), 'constraints_to_constraints') poses_to_poses = op2.Map(poses, poses, POSES_DIM, balib.identity_map(NUM_POSES, POSES_DIM), 'poses_to_poses') # this is needed to update hessian initial condition values initial = op2.Set(1, 'initial') initial_to_poses = op2.Map(initial, poses, 1, [0], 'initial_to_poses') # initial_to_constraints = op2.Set( initial) return (poses, constraints, initial, constraints_to_poses, constraints_to_constraints, poses_to_poses, initial_to_poses)
def test_build_sparsity(self): """Building a sparsity from a pair of maps should give the expected rowptr and colidx.""" elements = op2.Set(4) nodes = op2.Set(5) elem_node = op2.Map(elements, nodes, 3, [0, 4, 3, 0, 1, 4, 1, 2, 4, 2, 3, 4]) sparsity = op2.Sparsity((nodes, nodes), (elem_node, elem_node)) assert all(sparsity._rowptr == [0, 4, 8, 12, 16, 21]) assert all(sparsity._colidx == [0, 1, 3, 4, 0, 1, 2, 4, 1, 2, 3, 4, 0, 2, 3, 4, 0, 1, 2, 3, 4])
def test_sparsity_has_diagonal_space(self): # A sparsity should have space for diagonal entries if rmap==cmap s = op2.Set(1) d = op2.Set(4) m = op2.Map(s, d, 2, [1, 3]) d2 = op2.Set(4) m2 = op2.Map(s, d2, 3, [1, 2, 3]) sparsity = op2.Sparsity((d, d), (m, m)) sparsity2 = op2.Sparsity((d, d2), (m, m2)) assert all(sparsity.nnz == [1, 2, 1, 2]) assert all(sparsity2.nnz == [0, 3, 0, 3])
def get_node_set(mesh, nodes_per_entity): """Get the :class:`node set <pyop2.Set>`. :arg mesh: The mesh to use. :arg nodes_per_entity: The number of function space nodes per topological entity. :returns: A :class:`pyop2.Set` for the function space nodes. """ global_numbering = get_global_numbering(mesh, nodes_per_entity) node_classes = mesh.node_classes(nodes_per_entity) halo = halo_mod.Halo(mesh._plex, global_numbering) node_set = op2.Set(node_classes, halo=halo, comm=mesh.comm) extruded = mesh.cell_set._extruded if extruded: # FIXME! This is a LIE! But these sets should not be extruded # anyway, only the code gen in PyOP2 is busted. node_set = op2.ExtrudedSet(node_set, layers=2) assert global_numbering.getStorageSize() == node_set.total_size if not extruded and node_set.total_size >= (1 << (IntType.itemsize * 8 - 4)): raise RuntimeError( "Problems with more than %d nodes per process unsupported", (1 << (IntType.itemsize * 8 - 4))) return node_set
def get_node_set(mesh, nodes_per_entity): """Get the :class:`node set <pyop2.Set>`. :arg mesh: The mesh to use. :arg nodes_per_entity: The number of function space nodes per topological entity. :returns: A :class:`pyop2.Set` for the function space nodes. """ global_numbering = get_global_numbering(mesh, nodes_per_entity) # Use a DM to create the halo SFs dm = PETSc.DMShell().create(mesh.comm) dm.setPointSF(mesh._plex.getPointSF()) dm.setDefaultSection(global_numbering) node_classes = tuple(numpy.dot(nodes_per_entity, mesh._entity_classes)) node_set = op2.Set(node_classes, halo=halo_mod.Halo(dm), comm=mesh.comm) # Don't need it any more, explicitly destroy. dm.destroy() extruded = bool(mesh.layers) if extruded: node_set = op2.ExtrudedSet(node_set, layers=mesh.layers) assert global_numbering.getStorageSize() == node_set.total_size if not extruded and node_set.total_size >= (1 << (IntType.itemsize * 8 - 4)): raise RuntimeError( "Problems with more than %d nodes per process unsupported", (1 << (IntType.itemsize * 8 - 4))) return node_set
def get_node_set(mesh, key): """Get the :class:`node set <pyop2.Set>`. :arg mesh: The mesh to use. :arg key: a (nodes_per_entity, real_tensorproduct) tuple where nodes_per_entity is a tuple of the number of nodes per topological entity; real_tensorproduct is True if the function space is a degenerate fs x Real tensorproduct. :returns: A :class:`pyop2.Set` for the function space nodes. """ nodes_per_entity, real_tensorproduct = key global_numbering = get_global_numbering( mesh, (nodes_per_entity, real_tensorproduct)) node_classes = mesh.node_classes(nodes_per_entity, real_tensorproduct=real_tensorproduct) halo = halo_mod.Halo(mesh._topology_dm, global_numbering) node_set = op2.Set(node_classes, halo=halo, comm=mesh.comm) extruded = mesh.cell_set._extruded assert global_numbering.getStorageSize() == node_set.total_size if not extruded and node_set.total_size >= (1 << (IntType.itemsize * 8 - 4)): raise RuntimeError( "Problems with more than %d nodes per process unsupported", (1 << (IntType.itemsize * 8 - 4))) return node_set
def test_complementary_subsets(self, backend, iterset): """Test par_loop on two complementary subsets""" even = np.array([i for i in range(nelems) if not i % 2], dtype=np.int) odd = np.array([i for i in range(nelems) if i % 2], dtype=np.int) sseven = op2.Subset(iterset, even) ssodd = op2.Subset(iterset, odd) indset = op2.Set(nelems, "indset") map = op2.Map(iterset, indset, 1, [i for i in range(nelems)]) dat1 = op2.Dat(iterset ** 1, data=None, dtype=np.uint32) dat2 = op2.Dat(indset ** 1, data=None, dtype=np.uint32) k = op2.Kernel("""\ void inc(unsigned int* v1, unsigned int* v2) { *v1 += 1; *v2 += 1; } """, "inc") op2.par_loop(k, sseven, dat1(op2.RW), dat2(op2.INC, map[0])) op2.par_loop(k, ssodd, dat1(op2.RW), dat2(op2.INC, map[0])) assert np.sum(dat1.data) == nelems assert np.sum(dat2.data) == nelems
def test_plan_per_iterset_partition(self, backend): set = op2.Set([2, 4, 4, 4], "set") indset = op2.Set(4, "indset") dat = op2.Dat(set**1, [0, 1, 2, 3], dtype=numpy.int32) inddat = op2.Dat(indset**1, [0, 0, 0, 0], dtype=numpy.int32) map = op2.Map(set, indset, 1, [0, 1, 2, 3]) self.cache.clear() assert len(self.cache) == 0 op2.par_loop( op2.Kernel("void assign(int* src, int* dst) { *dst = *src; }", "assign"), set, dat(op2.READ), inddat(op2.WRITE, map[0])) assert (dat.data == inddat.data).all() assert len(self.cache) == 2
def test_mat_always_has_diagonal_space(self): # A sparsity should always have space for diagonal entries s = op2.Set(1) d = op2.Set(4) m = op2.Map(s, d, 1, [2]) d2 = op2.Set(3) m2 = op2.Map(s, d2, 1, [1]) sparsity = op2.Sparsity((d, d2), (m, m2)) from petsc4py import PETSc # petsc4py default error handler swallows SETERRQ, so just # install the abort handler to notice an error. PETSc.Sys.pushErrorHandler("abort") mat = op2.Mat(sparsity) PETSc.Sys.popErrorHandler() assert np.allclose(mat.handle.getDiagonal().array, 0.0)
def test_norm_mixed(self): s = op2.Set(1) n = op2.Dat(s, [3], np.complex128) o = op2.Dat(s, [4j], np.complex128) md = op2.MixedDat([n, o]) assert type(md.norm) is float assert abs(md.norm - 5) < 1e-12
def test_norm_mixed(self): s = op2.Set(1) n = op2.Dat(s, [3], np.float64) o = op2.Dat(s, [4], np.float64) md = op2.MixedDat([n, o]) assert abs(md.norm - 5) < 1e-12
def node_set(self): """A :class:`pyop2.Set` containing the nodes of this :class:`.FunctionSpace`. One or (for :class:`.VectorFunctionSpace`\s) more degrees of freedom are stored at each node. """ name = "%s_nodes" % self.name if self._halo: s = op2.Set(self.dof_classes, name, halo=self._halo) if self.extruded: return op2.ExtrudedSet(s, layers=self._mesh.layers) return s else: s = op2.Set(self.node_count, name) if self.extruded: return op2.ExtrudedSet(s, layers=self._mesh.layers) return s
def read_triangle(f, layers=None): """Read the triangle file with prefix f into OP2 data strctures. Presently only .node and .ele files are read, attributes are ignored, and there may be bugs. The dat structures are returned as: (nodes, coords, elements, elem_node) These items have type: (Set, Dat, Set, Map) The Layers argument allows the reading of data for extruded meshes. It is to be used when dealing with extruded meshes. """ # Read nodes with open(f + '.node') as h: num_nodes = int(h.readline().split(' ')[0]) node_values = np.zeros((num_nodes, 2), dtype=np.float64) for line in h: if line[0] == '#': continue node, x, y = line.split()[:3] node_values[int(node) - 1, :] = [float(x), float(y)] nodes = op2.Set(num_nodes, "nodes") coords = op2.Dat(nodes ** 2, node_values, name="coords") # Read elements with open(f + '.ele') as h: num_tri, nodes_per_tri, num_attrs = [int(col) for col in h.readline().split()] map_values = np.zeros((num_tri, nodes_per_tri), dtype=np.int32) for line in h: if line[0] == '#': continue vals = [int(v) - 1 for v in line.split()] map_values[vals[0], :] = vals[1:nodes_per_tri + 1] if layers is not None: elements = op2.ExtrudedSet(op2.Set(num_tri, "elements"), layers=layers) else: elements = op2.Set(num_tri, "elements") elem_node = op2.Map(elements, nodes, nodes_per_tri, map_values, "elem_node") return nodes, coords, elements, elem_node
def test_matrix(self, backend): """Test a indirect par_loop with a matrix argument""" iterset = op2.Set(2) idset = op2.Set(2) ss01 = op2.Subset(iterset, [0, 1]) ss10 = op2.Subset(iterset, [1, 0]) indset = op2.Set(4) dat = op2.Dat(idset ** 1, data=[0, 1], dtype=np.float) map = op2.Map(iterset, indset, 4, [0, 1, 2, 3, 0, 1, 2, 3]) idmap = op2.Map(iterset, idset, 1, [0, 1]) sparsity = op2.Sparsity((indset, indset), (map, map)) mat = op2.Mat(sparsity, np.float64) mat01 = op2.Mat(sparsity, np.float64) mat10 = op2.Mat(sparsity, np.float64) assembly = c_for("i", 4, c_for("j", 4, Incr(Symbol("mat", ("i", "j")), FlatBlock("(*dat)*16+i*4+j")))) kernel_code = FunDecl("void", "unique_id", [Decl("double*", c_sym("dat")), Decl("double", Symbol("mat", (4, 4)))], Block([assembly], open_scope=False)) k = op2.Kernel(kernel_code, "unique_id") mat.zero() mat01.zero() mat10.zero() op2.par_loop(k, iterset, dat(op2.READ, idmap[0]), mat(op2.INC, (map[op2.i[0]], map[op2.i[1]]))) mat.assemble() op2.par_loop(k, ss01, dat(op2.READ, idmap[0]), mat01(op2.INC, (map[op2.i[0]], map[op2.i[1]]))) mat01.assemble() op2.par_loop(k, ss10, dat(op2.READ, idmap[0]), mat10(op2.INC, (map[op2.i[0]], map[op2.i[1]]))) mat10.assemble() assert (mat01.values == mat.values).all() assert (mat10.values == mat.values).all()
def set(self): size = self.classes halo = None if isinstance(self.mesh, ExtrudedMeshTopology): if self.kind == "interior": base = self.mesh._base_mesh.interior_facets.set else: base = self.mesh._base_mesh.exterior_facets.set return op2.ExtrudedSet(base, layers=self.mesh.layers) return op2.Set(size, "%s_%s_facets" % (self.mesh.name, self.kind), halo=halo)
def test_inner(self): s = op2.Set(2) n = op2.Dat(s, [3, 4j], np.complex128) o = op2.Dat(s, [4, 5j], np.complex128) ret = n.inner(o) assert abs(ret - 32) < 1e-12 ret = o.inner(n) assert abs(ret - 32) < 1e-12
def test_inner(self): s = op2.Set(2) n = op2.Dat(s, [3, 4], np.float64) o = op2.Dat(s, [4, 5], np.float64) ret = n.inner(o) assert abs(ret - 32) < 1e-12 ret = o.inner(n) assert abs(ret - 32) < 1e-12
def matrix_funptr(form): from firedrake.tsfc_interface import compile_form test, trial = map(operator.methodcaller("function_space"), form.arguments()) if test != trial: raise NotImplementedError("Only for matching test and trial spaces") kernel, = compile_form(form, "subspace_form", split=False) kinfo = kernel.kinfo if kinfo.subdomain_id != "otherwise": raise NotImplementedError("Only for full domain integrals") if kinfo.integral_type != "cell": raise NotImplementedError("Only for cell integrals") # OK, now we've validated the kernel, let's build the callback args = [] toset = op2.Set(1, comm=test.comm) dofset = op2.DataSet(toset, 1) arity = sum(m.arity * s.cdim for m, s in zip(test.cell_node_map(), test.dof_dset)) iterset = test.cell_node_map().iterset cell_node_map = op2.Map(iterset, toset, arity, values=numpy.zeros(iterset.total_size * arity, dtype=IntType)) mat = DenseMat(dofset) arg = mat(op2.INC, (cell_node_map[op2.i[0]], cell_node_map[op2.i[1]])) arg.position = 0 args.append(arg) mesh = form.ufl_domains()[kinfo.domain_number] arg = mesh.coordinates.dat(op2.READ, mesh.coordinates.cell_node_map()[op2.i[0]]) arg.position = 1 args.append(arg) for n in kinfo.coefficient_map: c = form.coefficients()[n] for (i, c_) in enumerate(c.split()): map_ = c_.cell_node_map() if map_ is not None: map_ = map_[op2.i[0]] arg = c_.dat(op2.READ, map_) arg.position = len(args) args.append(arg) iterset = op2.Subset(mesh.cell_set, [0]) mod = JITModule(kinfo.kernel, iterset, *args) return mod._fun, kinfo
def test_indirect_loop_empty(self, backend, iterset): """Test a indirect ParLoop on an empty""" ss = op2.Subset(iterset, []) indset = op2.Set(2, "indset") map = op2.Map(iterset, indset, 1, [(1 if i % 2 else 0) for i in range(nelems)]) d = op2.Dat(indset ** 1, data=None, dtype=np.uint32) k = op2.Kernel("void inc(unsigned int* v) { *v += 1;}", "inc") d.data[:] = 0 op2.par_loop(k, ss, d(op2.INC, map[0])) assert (d.data == 0).all()
def test_vec_norm_changes(self): s = op2.Set(1) d = op2.Dat(s) d.data[:] = 1 with d.vec_ro as v: assert np.allclose(v.norm(), 1.0) d.data[:] = 2 with d.vec_ro as v: assert np.allclose(v.norm(), 2.0)
def test_vec_norm_changes(self, backend, skip_cuda, skip_opencl): s = op2.Set(1) d = op2.Dat(s) d.data[:] = 1 with d.vec_ro as v: assert np.allclose(v.norm(), 1.0) d.data[:] = 2 with d.vec_ro as v: assert np.allclose(v.norm(), 2.0)
def test_2d_map(self): """Sum nodal values incident to a common edge.""" nedges = nelems - 1 nodes = op2.Set(nelems, "nodes") edges = op2.Set(nedges, "edges") node_vals = op2.Dat(nodes, np.arange(nelems, dtype=np.uint32), np.uint32, "node_vals") edge_vals = op2.Dat(edges, np.zeros(nedges, dtype=np.uint32), np.uint32, "edge_vals") e_map = np.array([(i, i + 1) for i in range(nedges)], dtype=np.uint32) edge2node = op2.Map(edges, nodes, 2, e_map, "edge2node") kernel_sum = """ static void sum(unsigned int *edge, unsigned int *nodes) { *edge = nodes[0] + nodes[1]; }""" op2.par_loop(op2.Kernel(kernel_sum, "sum"), edges, edge_vals(op2.WRITE), node_vals(op2.READ, edge2node)) expected = np.arange(1, nedges * 2 + 1, 2) assert all(expected == edge_vals.data)
def test_indirect_loop(self, backend, iterset): """Test a indirect ParLoop on a subset""" indices = np.array([i for i in range(nelems) if not i % 2], dtype=np.int) ss = op2.Subset(iterset, indices) indset = op2.Set(2, "indset") map = op2.Map(iterset, indset, 1, [(1 if i % 2 else 0) for i in range(nelems)]) d = op2.Dat(indset ** 1, data=None, dtype=np.uint32) k = op2.Kernel("void inc(unsigned int* v) { *v += 1;}", "inc") op2.par_loop(k, ss, d(op2.INC, map[0])) assert d.data[0] == nelems / 2
def testKernel(data=None, op2set=None, op2map=None): """ for testing purposes, it just prints out the data Dat array (assuming) it has dimension 3 in its Map (op2map). The kernel iterates over the Set op2set, if no arguments are passed in, this creates dummy values and prints them out """ if not op2set: op2set = op2.Set(5, 'fromset') if not op2map: op2toset = op2.Set(4, 'toset') npmapping = np.array([0, 1, 1, 2, 2, 3, 3, 1, 3, 2], np.uint32) print '-' * 80 print 'mapping: ', npmapping, npmapping.dtype, npmapping.shape op2map = op2.Map(op2set, op2toset, 2, npmapping, 'testmap') if not data: numpydata = np.array([[0, 1, 1], [1, 2, 2], [2, 3, 3], [3, 4, 4]], dtype=np.float64) print '-' * 80 print 'data:' print numpydata data = op2.Dat(op2toset ** 3, numpydata, np.float64, 'testdata') test = op2.Kernel(""" void test_kernel(double *x[3]) { std::cout << " " << x[0][0] << " " << x[0][1] << " " << x[0][2]; std::cout << " : " << x[1][0] << " " << x[1][1] << " " << x[1][2] << std::endl; } """, 'test_kernel') print '-' * 80 print 'PyOP2 output:' op2.par_loop(test, op2set, data(op2map, op2.READ)) print '-' * 80
def test_indirect_loop_with_direct_dat(self, backend, iterset): """Test a indirect ParLoop on a subset""" indices = np.array([i for i in range(nelems) if not i % 2], dtype=np.int) ss = op2.Subset(iterset, indices) indset = op2.Set(2, "indset") map = op2.Map(iterset, indset, 1, [(1 if i % 2 else 0) for i in range(nelems)]) values = [2976579765] * nelems values[::2] = [i/2 for i in range(nelems)][::2] dat1 = op2.Dat(iterset ** 1, data=values, dtype=np.uint32) dat2 = op2.Dat(indset ** 1, data=None, dtype=np.uint32) k = op2.Kernel("void inc(unsigned* s, unsigned int* d) { *d += *s;}", "inc") op2.par_loop(k, ss, dat1(op2.READ), dat2(op2.INC, map[0])) assert dat2.data[0] == sum(values[::2])
def test_mixed_vec_access(self): s = op2.Set(1) ms = op2.MixedSet([s, s]) d = op2.MixedDat(ms) d.data[0][:] = 1.0 d.data[1][:] = 2.0 with d.vec_ro as v: assert np.allclose(v.array_r, [1.0, 2.0]) d.data[0][:] = 0.0 d.data[0][:] = 0.0 with d.vec_wo as v: assert np.allclose(v.array_r, [1.0, 2.0]) v.array[:] = 1 assert d.data[0][0] == 1 assert d.data[1][0] == 1
def test_inner_mixed(self): s = op2.Set(1) n = op2.Dat(s, [3], np.float64) o = op2.Dat(s, [4], np.float64) md = op2.MixedDat([n, o]) n1 = op2.Dat(s, [4], np.float64) o1 = op2.Dat(s, [5], np.float64) md1 = op2.MixedDat([n1, o1]) ret = md.inner(md1) assert abs(ret - 32) < 1e-12 ret = md1.inner(md) assert abs(ret - 32) < 1e-12