Exemple #1
0
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)
Exemple #2
0
    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])
Exemple #3
0
 def test_uninitialized_map(self, iterset, indset, x):
     """Accessing a par_loop argument via an uninitialized Map should raise
     an exception."""
     kernel_wo = "void kernel_wo(unsigned int* x) { *x = 42; }\n"
     with pytest.raises(MapValueError):
         op2.par_loop(op2.Kernel(kernel_wo, "kernel_wo"), iterset,
                      x(op2.WRITE, op2.Map(iterset, indset, 1)))
Exemple #4
0
    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)
Exemple #5
0
def coords_map(elements, node_set1):
    lsize = nums[2] * map_dofs_coords
    ind_coords = compute_ind_extr(nums, map_dofs_coords, nelems, layers,
                                  mesh2d, dofs_coords, A, wedges, elems2nodes,
                                  lsize)
    return op2.Map(elements, node_set1, map_dofs_coords, ind_coords,
                   "elem_dofs", off1)
Exemple #6
0
def coarse_to_fine_node_map(coarse, fine):
    if len(coarse) > 1:
        assert len(fine) == len(coarse)
        return op2.MixedMap(
            coarse_to_fine_node_map(c, f) for c, f in zip(coarse, fine))
    mesh = coarse.mesh()
    assert hasattr(mesh, "_shared_data_cache")
    if not (coarse.ufl_element() == fine.ufl_element()):
        raise ValueError("Can't transfer between different spaces")
    ch, level = get_level(mesh)
    fh, fine_level = get_level(fine.mesh())
    if ch is not fh:
        raise ValueError("Can't map between different hierarchies")
    refinements_per_level = ch.refinements_per_level
    if refinements_per_level * level + 1 != refinements_per_level * fine_level:
        raise ValueError("Can't map between level %s and level %s" %
                         (level, fine_level))
    c2f, vperm = ch._cells_vperm[int(level * refinements_per_level)]

    key = entity_dofs_key(coarse.finat_element.entity_dofs()) + (level, )
    cache = mesh._shared_data_cache["hierarchy_cell_node_map"]
    try:
        return cache[key]
    except KeyError:
        from .impl import create_cell_node_map
        map_vals, offset = create_cell_node_map(coarse, fine, c2f, vperm)
        return cache.setdefault(
            key,
            op2.Map(mesh.cell_set,
                    fine.node_set,
                    map_vals.shape[1],
                    map_vals,
                    offset=offset))
Exemple #7
0
    def cell_node_map(self, level):
        """A :class:`pyop2.Map` from cells on a coarse mesh to the
        corresponding degrees of freedom on a the fine mesh below it.

        :arg level: the coarse level the map should be from.
        """
        if not 0 <= level < len(self) - 1:
            raise RuntimeError(
                "Requested coarse level %d outside permissible range [0, %d)" %
                (level, len(self) - 1))
        try:
            return self._map_cache[level]
        except KeyError:
            pass
        Vc = self._hierarchy[level]
        Vf = self._hierarchy[level + 1]

        c2f, vperm = self._mesh_hierarchy._cells_vperm[level]

        map_vals, offset = impl.create_cell_node_map(Vc, Vf, c2f, vperm)
        map = op2.Map(self._cell_sets[level],
                      Vf.node_set,
                      map_vals.shape[1],
                      map_vals,
                      offset=offset)
        self._map_cache[level] = map
        return map
Exemple #8
0
def composed_map(map1, map2):
    """
    Manually build a :class:`PyOP2.Map` from the iterset of map1 to the
    toset of map2.

    :arg map1: The map with the desired iterset
    :arg map2: The map with the desired toset

    :returns:  The composed map

    Requires that `map1.toset == map2.iterset`.
    Only currently implemented for `map1.arity == 1`
    """
    if map2 is None:
        # Real function space case
        return None
    if map1.toset != map2.iterset:
        raise ValueError(
            "Cannot compose a map where the intermediate sets do not match!")
    if map1.arity != 1:
        raise NotImplementedError(
            "Can only currently build composed maps where map1.arity == 1")
    iterset = map1.iterset
    toset = map2.toset
    arity = map2.arity
    values = map2.values[map1.values].reshape(iterset.size, arity)
    assert values.shape == (iterset.size, arity)
    return op2.Map(iterset, toset, arity, values)
Exemple #9
0
    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
Exemple #10
0
    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)
Exemple #11
0
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
Exemple #12
0
    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)
Exemple #13
0
    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()
Exemple #14
0
 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])
Exemple #15
0
def coarse_cell_to_fine_node_map(Vc, Vf):
    if len(Vf) > 1:
        assert len(Vf) == len(Vc)
        return op2.MixedMap(
            coarse_cell_to_fine_node_map(f, c) for f, c in zip(Vf, Vc))
    mesh = Vc.mesh()
    assert hasattr(mesh, "_shared_data_cache")
    hierarchyf, levelf = get_level(Vf.ufl_domain())
    hierarchyc, levelc = get_level(Vc.ufl_domain())

    if hierarchyc != hierarchyf:
        raise ValueError("Can't map across hierarchies")

    hierarchy = hierarchyf
    increment = Fraction(1, hierarchyf.refinements_per_level)
    if levelc + increment != levelf:
        raise ValueError("Can't map between level %s and level %s" %
                         (levelc, levelf))

    key = (entity_dofs_key(Vf.finat_element.entity_dofs()) + (levelc, levelf))
    cache = mesh._shared_data_cache["hierarchy_coarse_cell_to_fine_node_map"]
    try:
        return cache[key]
    except KeyError:
        assert Vc.extruded == Vf.extruded
        if Vc.mesh().variable_layers or Vf.mesh().variable_layers:
            raise NotImplementedError(
                "Not implemented for variable layers, sorry")
        if Vc.extruded and Vc.mesh().layers != Vf.mesh().layers:
            raise ValueError(
                "Coarse and fine meshes must have same number of layers")

        coarse_to_fine = hierarchy.coarse_to_fine_cells[levelc]
        _, ncell = coarse_to_fine.shape
        iterset = Vc.mesh().cell_set
        arity = Vf.finat_element.space_dimension() * ncell
        coarse_to_fine_nodes = numpy.full((iterset.total_size, arity),
                                          -1,
                                          dtype=IntType)
        values = Vf.cell_node_map().values[coarse_to_fine, :].reshape(
            iterset.size, arity)

        coarse_to_fine_nodes[:Vc.mesh().cell_set.size, :] = values
        offset = Vf.offset
        if offset is not None:
            offset = numpy.tile(offset, ncell)
        return cache.setdefault(
            key,
            op2.Map(iterset,
                    Vf.node_set,
                    arity=arity,
                    values=coarse_to_fine_nodes,
                    offset=offset))
Exemple #16
0
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
Exemple #17
0
    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
Exemple #18
0
    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()
Exemple #19
0
    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
Exemple #20
0
    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])
Exemple #21
0
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
Exemple #22
0
def coarse_node_to_fine_node_map(Vc, Vf):
    if len(Vf) > 1:
        assert len(Vf) == len(Vc)
        return op2.MixedMap(
            coarse_node_to_fine_node_map(f, c) for f, c in zip(Vf, Vc))
    mesh = Vc.mesh()
    assert hasattr(mesh, "_shared_data_cache")
    hierarchyf, levelf = get_level(Vf.ufl_domain())
    hierarchyc, levelc = get_level(Vc.ufl_domain())

    if hierarchyc != hierarchyf:
        raise ValueError("Can't map across hierarchies")

    hierarchy = hierarchyf
    increment = Fraction(1, hierarchyf.refinements_per_level)
    if levelc + increment != levelf:
        raise ValueError("Can't map between level %s and level %s" %
                         (levelc, levelf))

    key = (entity_dofs_key(Vc.finat_element.entity_dofs()) +
           entity_dofs_key(Vf.finat_element.entity_dofs()) + (levelc, levelf))

    cache = mesh._shared_data_cache["hierarchy_coarse_node_to_fine_node_map"]
    try:
        return cache[key]
    except KeyError:
        assert Vc.extruded == Vf.extruded
        if Vc.mesh().variable_layers or Vf.mesh().variable_layers:
            raise NotImplementedError(
                "Not implemented for variable layers, sorry")
        if Vc.extruded and not ((Vf.mesh().layers - 1) /
                                (Vc.mesh().layers - 1)).is_integer():
            raise ValueError(
                "Coarse and fine meshes must have an integer ratio of layers")

        coarse_to_fine = hierarchy.coarse_to_fine_cells[levelc]
        coarse_to_fine_nodes = impl.coarse_to_fine_nodes(
            Vc, Vf, coarse_to_fine)
        return cache.setdefault(
            key,
            op2.Map(Vc.node_set,
                    Vf.node_set,
                    coarse_to_fine_nodes.shape[1],
                    values=coarse_to_fine_nodes))
Exemple #23
0
def fine_node_to_coarse_node_map(Vf, Vc):
    if len(Vf) > 1:
        assert len(Vf) == len(Vc)
        return op2.MixedMap(
            fine_node_to_coarse_node_map(f, c) for f, c in zip(Vf, Vc))
    mesh = Vf.mesh()
    assert hasattr(mesh, "_shared_data_cache")
    hierarchyf, levelf = get_level(Vf.ufl_domain())
    hierarchyc, levelc = get_level(Vc.ufl_domain())

    if hierarchyc != hierarchyf:
        raise ValueError("Can't map across hierarchies")

    hierarchy = hierarchyf
    if levelc + 1 != levelf:
        raise ValueError("Can't map between level %s and level %s" %
                         (levelc, levelf))

    key = (entity_dofs_key(Vc.finat_element.entity_dofs()) +
           entity_dofs_key(Vf.finat_element.entity_dofs()) + (levelc, levelf))

    cache = mesh._shared_data_cache["hierarchy_fine_node_to_coarse_node_map"]
    try:
        return cache[key]
    except KeyError:
        assert Vc.extruded == Vf.extruded
        if Vc.mesh().variable_layers or Vf.mesh().variable_layers:
            raise NotImplementedError(
                "Not implemented for variable layers, sorry")
        if Vc.extruded and Vc.mesh().layers != Vf.mesh().layers:
            raise ValueError(
                "Coarse and fine meshes must have same number of layers")

        fine_to_coarse = hierarchy.fine_to_coarse_cells[levelc + 1]
        fine_to_coarse_nodes = impl.fine_to_coarse_nodes(
            Vf, Vc, fine_to_coarse)
        return cache.setdefault(
            key,
            op2.Map(Vf.node_set,
                    Vc.node_set,
                    fine_to_coarse_nodes.shape[1],
                    values=fine_to_coarse_nodes))
    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 get_map(self, V, entity_set, map_arity, name, offset):
        """Return a :class:`pyop2.Map` from some topological entity to
        degrees of freedom.

        :arg V: The :class:`FunctionSpace` to create the map for.
        :arg entity_set: The :class:`pyop2.Set` of entities to map from.
        :arg map_arity: The arity of the resulting map.
        :arg name: A name for the resulting map.
        :arg offset: Map offset (for extruded)."""
        # V is only really used for error checking and "name".
        assert len(V) == 1, "get_map should not be called on MixedFunctionSpace"
        entity_node_list = self.entity_node_lists[entity_set]

        val = self.map_cache[entity_set]
        if val is None:
            val = op2.Map(entity_set, self.node_set,
                          map_arity,
                          entity_node_list,
                          ("%s_"+name) % (V.name),
                          offset=offset)

            self.map_cache[entity_set] = val
        return val
Exemple #26
0
    def test_minimal_zero_mat(self):
        """Assemble a matrix that is all zeros."""

        code = c_for("i", 1,
                     c_for("j", 1,
                           Assign(Symbol("local_mat", ("i", "j")), c_sym("0.0"))))
        zero_mat_code = FunDecl("void", "zero_mat",
                                [Decl("double", Symbol("local_mat", (1, 1)))],
                                Block([code], open_scope=False))

        nelems = 128
        set = op2.Set(nelems)
        map = op2.Map(set, set, 1, np.array(list(range(nelems)), np.uint32))
        sparsity = op2.Sparsity((set, set), (map, map))
        mat = op2.Mat(sparsity, np.float64)
        kernel = op2.Kernel(zero_mat_code, "zero_mat")
        op2.par_loop(kernel, set,
                     mat(op2.WRITE, (map[op2.i[0]], map[op2.i[1]])))

        mat.assemble()
        expected_matrix = np.zeros((nelems, nelems), dtype=np.float64)
        eps = 1.e-12
        assert_allclose(mat.values, expected_matrix, eps)
Exemple #27
0
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
Exemple #28
0
    def exterior_facet_boundary_node_map(self, V, method):
        """Return the :class:`pyop2.Map` from exterior facets to nodes
        on the boundary.

        :arg V: The function space.
        :arg method:  The method for determining boundary nodes.  See
           :class:`~.DirichletBC` for details.
        """
        try:
            return self.map_caches["boundary_node"][method]
        except KeyError:
            pass
        el = V.finat_element

        dim = self.mesh.facet_dimension()

        if method == "topological":
            boundary_dofs = el.entity_closure_dofs()[dim]
        elif method == "geometric":
            # This function is only called on extruded meshes when
            # asking for the nodes that live on the "vertical"
            # exterior facets.
            boundary_dofs = entity_support_dofs(el, dim)

        nodes_per_facet = \
            len(boundary_dofs[0])

        # HACK ALERT
        # The facet set does not have a halo associated with it, since
        # we only construct halos for DoF sets.  Fortunately, this
        # loop is direct and we already have all the correct
        # information available locally.  So We fake a set of the
        # correct size and carry out a direct loop
        facet_set = op2.Set(self.mesh.exterior_facets.set.total_size,
                            comm=self.mesh.comm)

        fs_dat = op2.Dat(
            facet_set**el.space_dimension(),
            data=V.exterior_facet_node_map().values_with_halo.view())

        facet_dat = op2.Dat(facet_set**nodes_per_facet, dtype=IntType)

        # Ensure these come out in sorted order.
        local_facet_nodes = numpy.array(
            [boundary_dofs[e] for e in sorted(boundary_dofs.keys())])

        # Helper function to turn the inner index of an array into c
        # array literals.
        c_array = lambda xs: "{" + ", ".join(map(str, xs)) + "}"

        # AST for: l_nodes[facet[0]][n]
        rank_ast = ast.Symbol("l_nodes",
                              rank=(ast.Symbol("facet", rank=(0, )), "n"))

        body = ast.Block([
            ast.Decl("int",
                     ast.Symbol("l_nodes",
                                (len(el.cell.topology[dim]), nodes_per_facet)),
                     init=ast.ArrayInit(
                         c_array(map(c_array, local_facet_nodes))),
                     qualifiers=["const"]),
            ast.For(
                ast.Decl("int", "n", 0), ast.Less("n", nodes_per_facet),
                ast.Incr("n", 1),
                ast.Assign(ast.Symbol("facet_nodes", ("n", )),
                           ast.Symbol("cell_nodes", (rank_ast, ))))
        ])

        kernel = op2.Kernel(
            ast.FunDecl("void", "create_bc_node_map", [
                ast.Decl("%s*" % as_cstr(fs_dat.dtype), "cell_nodes"),
                ast.Decl("%s*" % as_cstr(facet_dat.dtype), "facet_nodes"),
                ast.Decl("unsigned int*", "facet")
            ], body), "create_bc_node_map")

        local_facet_dat = op2.Dat(
            facet_set**self.mesh.exterior_facets._rank,
            self.mesh.exterior_facets.local_facet_dat.data_ro_with_halos,
            dtype=numpy.uintc)
        op2.par_loop(kernel, facet_set, fs_dat(op2.READ), facet_dat(op2.WRITE),
                     local_facet_dat(op2.READ))

        if self.extruded:
            offset = self.offset[boundary_dofs[0]]
        else:
            offset = None
        val = op2.Map(facet_set,
                      self.node_set,
                      nodes_per_facet,
                      facet_dat.data_ro_with_halos,
                      name="exterior_facet_boundary_node",
                      offset=offset)
        self.map_caches["boundary_node"][method] = val
        return val
Exemple #29
0
    def get_map(self,
                V,
                entity_set,
                map_arity,
                bcs,
                name,
                offset,
                parent,
                kind=None):
        """Return a :class:`pyop2.Map` from some topological entity to
        degrees of freedom.

        :arg V: The :class:`FunctionSpace` to create the map for.
        :arg entity_set: The :class:`pyop2.Set` of entities to map from.
        :arg map_arity: The arity of the resulting map.
        :arg bcs: An iterable of :class:`~.DirichletBC` objects (may
            be ``None``.
        :arg name: A name for the resulting map.
        :arg offset: Map offset (for extruded).
        :arg parent: The parent map (used when bcs are provided)."""
        # V is only really used for error checking and "name".
        assert len(
            V) == 1, "get_map should not be called on MixedFunctionSpace"
        entity_node_list = self.entity_node_lists[entity_set]
        cache = self.map_caches[entity_set]

        if bcs is not None:
            # Separate explicit bcs (we just place negative entries in
            # the appropriate map values) from implicit ones (extruded
            # top and bottom) that require PyOP2 code gen.
            explicit_bcs = [
                bc for bc in bcs if bc.sub_domain not in ['top', 'bottom']
            ]
            implicit_bcs = [(bc.sub_domain, bc.method) for bc in bcs
                            if bc.sub_domain in ['top', 'bottom']]
            if len(explicit_bcs) == 0:
                # Implicit bcs are not part of the cache key for the
                # map (they only change the generated PyOP2 code),
                # hence rewrite bcs here.
                bcs = ()
            if len(implicit_bcs) == 0:
                implicit_bcs = None
        else:
            # Empty tuple if no bcs found.  This is so that matrix
            # assembly, which uses a set to keep track of the bcs
            # applied to matrix hits the cache when that set is
            # empty.  tuple(set([])) == tuple().
            bcs = ()
            implicit_bcs = None

        for bc in bcs:
            fs = bc.function_space()
            # Unwind proxies for ComponentFunctionSpace, but not
            # IndexedFunctionSpace.
            while fs.component is not None and fs.parent is not None:
                fs = fs.parent
            if fs.topological != V:
                raise RuntimeError(
                    "DirichletBC defined on a different FunctionSpace!")
        # Ensure bcs is a tuple in a canonical order for the hash key.
        lbcs = tuple(sorted(bcs, key=lambda bc: bc.__hash__()))

        cache = self.map_caches[entity_set]
        try:
            # Cache hit
            val = cache[lbcs]
            # In the implicit bc case, we decorate the cached map with
            # the list of implicit boundary conditions so PyOP2 knows
            # what to do.
            if implicit_bcs:
                val = op2.DecoratedMap(val, implicit_bcs=implicit_bcs)
            return val
        except KeyError:
            # Cache miss.
            # Any top and bottom bcs (for the extruded case) are handled elsewhere.
            nodes = [
                bc.nodes for bc in lbcs
                if bc.sub_domain not in ['top', 'bottom']
            ]
            decorate = any(bc.function_space().component is not None
                           for bc in lbcs)
            if nodes:
                bcids = reduce(numpy.union1d, nodes)
                negids = numpy.copy(bcids)
                for bc in lbcs:
                    if bc.sub_domain in ["top", "bottom"]:
                        continue
                    nbits = IntType.itemsize * 8 - 2
                    if decorate and bc.function_space().component is None:
                        # Some of the other entries will be marked
                        # with high bits, so we need to set all the
                        # high bits for these bcs
                        idx = numpy.searchsorted(bcids, bc.nodes)
                        if bc.function_space().dim > 3:
                            raise ValueError(
                                "Can't have component BCs with more than three components (have %d)",
                                bc.function_space().dim)
                        for cmp in range(bc.function_space().dim):
                            negids[idx] |= (1 << (nbits - cmp))

                    # FunctionSpace with component is IndexedVFS
                    if bc.function_space().component is not None:
                        # For indexed VFS bcs, we encode the component
                        # in the high bits of the map value.
                        # That value is then negated to indicate to
                        # the generated code to discard the values
                        #
                        # So here we do:
                        #
                        # node = -(node + 2**(nbits-cmpt) + 1)
                        #
                        # And in the generated code we can then
                        # extract the information to discard the
                        # correct entries.
                        # bcids is sorted, so use searchsorted to find indices
                        idx = numpy.searchsorted(bcids, bc.nodes)
                        # Set appropriate bit
                        negids[idx] |= (
                            1 << (nbits - bc.function_space().component))
                node_list_bc = numpy.arange(self.node_set.total_size,
                                            dtype=IntType)
                # Fix up for extruded, doesn't commute with indexedvfs
                # for now
                if self.extruded:
                    node_list_bc[bcids] = -10000000
                else:
                    node_list_bc[bcids] = -(negids + 1)
                new_entity_node_list = node_list_bc.take(entity_node_list)
            else:
                new_entity_node_list = entity_node_list

            if kind == "interior_facet" and self.bt_masks is not None:
                bt_masks = {}
                off = map_arity // 2
                for method, (bottom, top) in iteritems(self.bt_masks):
                    b = []
                    t = []
                    for i in bottom:
                        b.append(i)
                        b.append(i + off)
                    for i in top:
                        t.append(i)
                        t.append(i + off)
                    bt_masks[method] = (b, t)
            else:
                bt_masks = self.bt_masks
            val = op2.Map(entity_set,
                          self.node_set,
                          map_arity,
                          new_entity_node_list, ("%s_" + name) % (V.name),
                          offset=offset,
                          parent=parent,
                          bt_masks=bt_masks)

            if decorate:
                val = op2.DecoratedMap(val, vector_index=True)
            cache[lbcs] = val
            if implicit_bcs:
                return op2.DecoratedMap(val, implicit_bcs=implicit_bcs)
            return val
Exemple #30
0
def elem_node(elements, nodes):
    return op2.Map(elements, nodes, 3, elem_node_map, "elem_node")