Пример #1
0
    def send_mesh_parts(self, mesh, part_per_element, num_parts):
        """
        :arg mesh: A :class:`Mesh` to distribute to other ranks.
        :arg part_per_element: A :class:`numpy.ndarray` containing one
            integer per element of *mesh* indicating which part of the
            partitioned mesh the element is to become a part of.
        :arg num_parts: The number of partitions to divide the mesh into.

        Sends each partition to a different rank.
        Returns one partition that was not sent to any other rank.
        """
        mpi_comm = self.mpi_comm
        rank = mpi_comm.Get_rank()
        assert num_parts <= mpi_comm.Get_size()

        assert self.is_mananger_rank()

        from meshmode.mesh.processing import partition_mesh
        parts = [partition_mesh(mesh, part_per_element, i)[0]
                        for i in range(num_parts)]

        local_part = None

        reqs = []
        for r, part in enumerate(parts):
            if r == self.manager_rank:
                local_part = part
            else:
                reqs.append(mpi_comm.isend(part, dest=r, tag=TAG_DISTRIBUTE_MESHES))

        logger.info('rank %d: sent all mesh partitions', rank)
        for req in reqs:
            req.wait()

        return local_part
Пример #2
0
    def send_mesh_parts(self, mesh, part_per_element, num_parts):
        """
        :arg mesh: A :class:`Mesh` to distribute to other ranks.
        :arg part_per_element: A :class:`numpy.ndarray` containing one
            integer per element of *mesh* indicating which part of the
            partitioned mesh the element is to become a part of.
        :arg num_parts: The number of partitions to divide the mesh into.

        Sends each partition to a different rank.
        Returns one partition that was not sent to any other rank.
        """
        mpi_comm = self.mpi_comm
        rank = mpi_comm.Get_rank()
        assert num_parts <= mpi_comm.Get_size()

        assert self.is_mananger_rank()

        from meshmode.mesh.processing import partition_mesh
        parts = [partition_mesh(mesh, part_per_element, i)[0]
                        for i in range(num_parts)]

        local_part = None

        reqs = []
        for r, part in enumerate(parts):
            if r == self.manager_rank:
                local_part = part
            else:
                reqs.append(mpi_comm.isend(part, dest=r, tag=TAG_DISTRIBUTE_MESHES))

        logger.info('rank %d: sent all mesh partitions', rank)
        for req in reqs:
            req.wait()

        return local_part
Пример #3
0
def test_partition_interpolation(actx_factory, dim, mesh_pars, num_parts,
                                 num_groups, part_method):
    np.random.seed(42)
    group_factory = PolynomialWarpAndBlendGroupFactory
    actx = actx_factory()

    order = 4

    def f(x):
        return 10. * actx.np.sin(50. * x)

    for n in mesh_pars:
        from meshmode.mesh.generation import generate_warped_rect_mesh
        base_mesh = generate_warped_rect_mesh(dim, order=order, n=n)

        if num_groups > 1:
            from meshmode.mesh.processing import split_mesh_groups
            # Group every Nth element
            element_flags = np.arange(
                base_mesh.nelements,
                dtype=base_mesh.element_id_dtype) % num_groups
            mesh = split_mesh_groups(base_mesh, element_flags)
        else:
            mesh = base_mesh

        if part_method == "random":
            part_per_element = np.random.randint(num_parts,
                                                 size=mesh.nelements)
        else:
            pytest.importorskip("pymetis")

            from meshmode.distributed import get_partition_by_pymetis
            part_per_element = get_partition_by_pymetis(
                mesh, num_parts, connectivity=part_method)

        from meshmode.mesh.processing import partition_mesh
        part_meshes = [
            partition_mesh(mesh, part_per_element, i)[0]
            for i in range(num_parts)
        ]

        connected_parts = set()
        for i_local_part, part_mesh in enumerate(part_meshes):
            from meshmode.distributed import get_connected_partitions
            neighbors = get_connected_partitions(part_mesh)
            for i_remote_part in neighbors:
                connected_parts.add((i_local_part, i_remote_part))

        from meshmode.discretization import Discretization
        vol_discrs = [
            Discretization(actx, part_meshes[i], group_factory(order))
            for i in range(num_parts)
        ]

        from meshmode.mesh import BTAG_PARTITION
        from meshmode.discretization.connection import (
            make_face_restriction, make_partition_connection, check_connection)

        for i_local_part, i_remote_part in connected_parts:
            # Mark faces within local_mesh that are connected to remote_mesh
            local_bdry_conn = make_face_restriction(
                actx, vol_discrs[i_local_part], group_factory(order),
                BTAG_PARTITION(i_remote_part))

            # Mark faces within remote_mesh that are connected to local_mesh
            remote_bdry_conn = make_face_restriction(
                actx, vol_discrs[i_remote_part], group_factory(order),
                BTAG_PARTITION(i_local_part))

            bdry_nelements = sum(grp.nelements
                                 for grp in local_bdry_conn.to_discr.groups)
            remote_bdry_nelements = sum(
                grp.nelements for grp in remote_bdry_conn.to_discr.groups)
            assert bdry_nelements == remote_bdry_nelements, \
                    "partitions do not have the same number of connected elements"

            local_bdry = local_bdry_conn.to_discr

            remote_bdry = remote_bdry_conn.to_discr

            from meshmode.distributed import make_remote_group_infos
            remote_to_local_conn = make_partition_connection(
                actx,
                local_bdry_conn=local_bdry_conn,
                i_local_part=i_local_part,
                remote_bdry_discr=remote_bdry,
                remote_group_infos=make_remote_group_infos(
                    actx, remote_bdry_conn))

            # Connect from local mesh to remote mesh
            local_to_remote_conn = make_partition_connection(
                actx,
                local_bdry_conn=remote_bdry_conn,
                i_local_part=i_remote_part,
                remote_bdry_discr=local_bdry,
                remote_group_infos=make_remote_group_infos(
                    actx, local_bdry_conn))

            check_connection(actx, remote_to_local_conn)
            check_connection(actx, local_to_remote_conn)

            true_local_points = f(thaw(actx, local_bdry.nodes()[0]))
            remote_points = local_to_remote_conn(true_local_points)
            local_points = remote_to_local_conn(remote_points)

            err = actx.np.linalg.norm(true_local_points - local_points, np.inf)

            # Can't currently expect exact results due to limitations of
            # interpolation "snapping" in DirectDiscretizationConnection's
            # _resample_point_pick_indices
            assert err < 1e-11
Пример #4
0
def test_partition_mesh(mesh_size, num_parts, num_groups, dim,
                        scramble_partitions):
    np.random.seed(42)
    n = (mesh_size, ) * dim
    from meshmode.mesh.generation import generate_regular_rect_mesh
    meshes = [
        generate_regular_rect_mesh(a=(0 + i, ) * dim, b=(1 + i, ) * dim, n=n)
        for i in range(num_groups)
    ]

    from meshmode.mesh.processing import merge_disjoint_meshes
    mesh = merge_disjoint_meshes(meshes)

    if scramble_partitions:
        part_per_element = np.random.randint(num_parts, size=mesh.nelements)
    else:
        pytest.importorskip("pymetis")

        from meshmode.distributed import get_partition_by_pymetis
        part_per_element = get_partition_by_pymetis(mesh, num_parts)

    from meshmode.mesh.processing import partition_mesh
    # TODO: The same part_per_element array must be used to partition each mesh.
    # Maybe the interface should be changed to guarantee this.
    new_meshes = [
        partition_mesh(mesh, part_per_element, i) for i in range(num_parts)
    ]

    assert mesh.nelements == np.sum(
        [new_meshes[i][0].nelements for i in range(num_parts)]), \
        "part_mesh has the wrong number of elements"

    assert count_tags(mesh, BTAG_ALL) == np.sum(
        [count_tags(new_meshes[i][0], BTAG_ALL) for i in range(num_parts)]), \
        "part_mesh has the wrong number of BTAG_ALL boundaries"

    connected_parts = set()
    for i_local_part, (part_mesh, _) in enumerate(new_meshes):
        from meshmode.distributed import get_connected_partitions
        neighbors = get_connected_partitions(part_mesh)
        for i_remote_part in neighbors:
            connected_parts.add((i_local_part, i_remote_part))

    from meshmode.mesh import BTAG_PARTITION, InterPartitionAdjacencyGroup
    from meshmode.mesh.processing import find_group_indices
    num_tags = np.zeros((num_parts, ))

    index_lookup_table = dict()
    for ipart, (m, _) in enumerate(new_meshes):
        for igrp in range(len(m.groups)):
            adj = m.facial_adjacency_groups[igrp][None]
            if not isinstance(adj, InterPartitionAdjacencyGroup):
                # This group is not connected to another partition.
                continue
            for i, (elem,
                    face) in enumerate(zip(adj.elements, adj.element_faces)):
                index_lookup_table[ipart, igrp, elem, face] = i

    for part_num in range(num_parts):
        part, part_to_global = new_meshes[part_num]
        for grp_num in range(len(part.groups)):
            adj = part.facial_adjacency_groups[grp_num][None]
            tags = -part.facial_adjacency_groups[grp_num][None].neighbors
            assert np.all(tags >= 0)
            if not isinstance(adj, InterPartitionAdjacencyGroup):
                # This group is not connected to another partition.
                continue
            elem_base = part.groups[grp_num].element_nr_base
            for idx in range(len(adj.elements)):
                if adj.partition_neighbors[idx] == -1:
                    continue
                elem = adj.elements[idx]
                face = adj.element_faces[idx]
                n_part_num = adj.neighbor_partitions[idx]
                n_meshwide_elem = adj.partition_neighbors[idx]
                n_face = adj.neighbor_faces[idx]
                num_tags[n_part_num] += 1
                n_part, n_part_to_global = new_meshes[n_part_num]
                # Hack: find_igrps expects a numpy.ndarray and returns
                #       a numpy.ndarray. But if a single integer is fed
                #       into find_igrps, an integer is returned.
                n_grp_num = int(
                    find_group_indices(n_part.groups, n_meshwide_elem))
                n_adj = n_part.facial_adjacency_groups[n_grp_num][None]
                n_elem_base = n_part.groups[n_grp_num].element_nr_base
                n_elem = n_meshwide_elem - n_elem_base
                n_idx = index_lookup_table[n_part_num, n_grp_num, n_elem,
                                           n_face]
                assert (part_num == n_adj.neighbor_partitions[n_idx]
                        and elem + elem_base == n_adj.partition_neighbors[n_idx]
                        and face == n_adj.neighbor_faces[n_idx]),\
                        "InterPartitionAdjacencyGroup is not consistent"
                _, n_part_to_global = new_meshes[n_part_num]
                p_meshwide_elem = part_to_global[elem + elem_base]
                p_meshwide_n_elem = n_part_to_global[n_elem + n_elem_base]

                p_grp_num = find_group_indices(mesh.groups, p_meshwide_elem)
                p_n_grp_num = find_group_indices(mesh.groups,
                                                 p_meshwide_n_elem)

                p_elem_base = mesh.groups[p_grp_num].element_nr_base
                p_n_elem_base = mesh.groups[p_n_grp_num].element_nr_base
                p_elem = p_meshwide_elem - p_elem_base
                p_n_elem = p_meshwide_n_elem - p_n_elem_base

                f_groups = mesh.facial_adjacency_groups[p_grp_num]
                for p_bnd_adj in f_groups.values():
                    for idx in range(len(p_bnd_adj.elements)):
                        if (p_elem == p_bnd_adj.elements[idx]
                                and face == p_bnd_adj.element_faces[idx]):
                            assert p_n_elem == p_bnd_adj.neighbors[idx],\
                                    "Tag does not give correct neighbor"
                            assert n_face == p_bnd_adj.neighbor_faces[idx],\
                                    "Tag does not give correct neighbor"

    for i_remote_part in range(num_parts):
        tag_sum = 0
        for i_local_part, (mesh, _) in enumerate(new_meshes):
            if (i_local_part, i_remote_part) in connected_parts:
                tag_sum += count_tags(mesh, BTAG_PARTITION(i_remote_part))
        assert num_tags[i_remote_part] == tag_sum,\
                "part_mesh has the wrong number of BTAG_PARTITION boundaries"
Пример #5
0
def test_partition_interpolation(ctx_factory, dim, mesh_pars, num_parts,
                                 num_groups, scramble_partitions):
    np.random.seed(42)
    group_factory = PolynomialWarpAndBlendGroupFactory
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    order = 4

    from pytools.convergence import EOCRecorder
    eoc_rec = dict()
    for i in range(num_parts):
        for j in range(num_parts):
            if i == j:
                continue
            eoc_rec[i, j] = EOCRecorder()

    def f(x):
        return 10. * cl.clmath.sin(50. * x)

    for n in mesh_pars:
        from meshmode.mesh.generation import generate_warped_rect_mesh
        meshes = [
            generate_warped_rect_mesh(dim, order=order, n=n)
            for _ in range(num_groups)
        ]

        if num_groups > 1:
            from meshmode.mesh.processing import merge_disjoint_meshes
            mesh = merge_disjoint_meshes(meshes)
        else:
            mesh = meshes[0]

        if scramble_partitions:
            part_per_element = np.random.randint(num_parts,
                                                 size=mesh.nelements)
        else:
            from pymetis import part_graph
            _, p = part_graph(
                num_parts,
                xadj=mesh.nodal_adjacency.neighbors_starts.tolist(),
                adjncy=mesh.nodal_adjacency.neighbors.tolist())
            part_per_element = np.array(p)

        from meshmode.mesh.processing import partition_mesh
        part_meshes = [
            partition_mesh(mesh, part_per_element, i)[0]
            for i in range(num_parts)
        ]

        from meshmode.discretization import Discretization
        vol_discrs = [
            Discretization(cl_ctx, part_meshes[i], group_factory(order))
            for i in range(num_parts)
        ]

        from meshmode.mesh import BTAG_PARTITION
        from meshmode.discretization.connection import (
            make_face_restriction, make_partition_connection, check_connection)

        for i_local_part, i_remote_part in eoc_rec.keys():
            if eoc_rec[i_local_part, i_remote_part] is None:
                continue

            # Mark faces within local_mesh that are connected to remote_mesh
            local_bdry_conn = make_face_restriction(
                vol_discrs[i_local_part], group_factory(order),
                BTAG_PARTITION(i_remote_part))

            # If these parts are not connected, don't bother checking the error
            bdry_nodes = local_bdry_conn.to_discr.nodes()
            if bdry_nodes.size == 0:
                eoc_rec[i_local_part, i_remote_part] = None
                continue

            # Mark faces within remote_mesh that are connected to local_mesh
            remote_bdry_conn = make_face_restriction(
                vol_discrs[i_remote_part], group_factory(order),
                BTAG_PARTITION(i_local_part))

            assert bdry_nodes.size == remote_bdry_conn.to_discr.nodes().size, \
                        "partitions do not have the same number of connected nodes"

            # Gather just enough information for the connection
            local_bdry = local_bdry_conn.to_discr
            local_mesh = part_meshes[i_local_part]
            local_adj_groups = [
                local_mesh.facial_adjacency_groups[i][None]
                for i in range(len(local_mesh.groups))
            ]
            local_batches = [
                local_bdry_conn.groups[i].batches
                for i in range(len(local_mesh.groups))
            ]
            local_from_elem_faces = [[
                batch.to_element_face for batch in grp_batches
            ] for grp_batches in local_batches]
            local_from_elem_indices = [[
                batch.to_element_indices.get(queue=queue)
                for batch in grp_batches
            ] for grp_batches in local_batches]

            remote_bdry = remote_bdry_conn.to_discr
            remote_mesh = part_meshes[i_remote_part]
            remote_adj_groups = [
                remote_mesh.facial_adjacency_groups[i][None]
                for i in range(len(remote_mesh.groups))
            ]
            remote_batches = [
                remote_bdry_conn.groups[i].batches
                for i in range(len(remote_mesh.groups))
            ]
            remote_from_elem_faces = [[
                batch.to_element_face for batch in grp_batches
            ] for grp_batches in remote_batches]
            remote_from_elem_indices = [[
                batch.to_element_indices.get(queue=queue)
                for batch in grp_batches
            ] for grp_batches in remote_batches]

            # Connect from remote_mesh to local_mesh
            remote_to_local_conn = make_partition_connection(
                local_bdry_conn, i_local_part, remote_bdry, remote_adj_groups,
                remote_from_elem_faces, remote_from_elem_indices)
            # Connect from local mesh to remote mesh
            local_to_remote_conn = make_partition_connection(
                remote_bdry_conn, i_remote_part, local_bdry, local_adj_groups,
                local_from_elem_faces, local_from_elem_indices)
            check_connection(remote_to_local_conn)
            check_connection(local_to_remote_conn)

            true_local_points = f(local_bdry.nodes()[0].with_queue(queue))
            remote_points = local_to_remote_conn(queue, true_local_points)
            local_points = remote_to_local_conn(queue, remote_points)

            err = la.norm((true_local_points - local_points).get(), np.inf)
            eoc_rec[i_local_part, i_remote_part].add_data_point(1. / n, err)

    for (i, j), e in eoc_rec.items():
        if e is not None:
            print("Error of connection from part %i to part %i." % (i, j))
            print(e)
            assert (e.order_estimate() >= order - 0.5 or e.max_error() < 1e-11)
Пример #6
0
def test_partition_interpolation(ctx_factory, dim, mesh_pars,
                                 num_parts, num_groups, part_method):
    np.random.seed(42)
    group_factory = PolynomialWarpAndBlendGroupFactory
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    order = 4

    def f(x):
        return 10.*actx.np.sin(50.*x)

    for n in mesh_pars:
        from meshmode.mesh.generation import generate_warped_rect_mesh
        base_mesh = generate_warped_rect_mesh(dim, order=order, n=n)

        if num_groups > 1:
            from meshmode.mesh.processing import split_mesh_groups
            # Group every Nth element
            element_flags = np.arange(base_mesh.nelements,
                        dtype=base_mesh.element_id_dtype) % num_groups
            mesh = split_mesh_groups(base_mesh, element_flags)
        else:
            mesh = base_mesh

        if part_method == "random":
            part_per_element = np.random.randint(num_parts, size=mesh.nelements)
        else:
            pytest.importorskip('pymetis')

            from meshmode.distributed import get_partition_by_pymetis
            part_per_element = get_partition_by_pymetis(mesh, num_parts,
                    connectivity=part_method)

        from meshmode.mesh.processing import partition_mesh
        part_meshes = [
            partition_mesh(mesh, part_per_element, i)[0] for i in range(num_parts)]

        connected_parts = set()
        for i_local_part, part_mesh in enumerate(part_meshes):
            from meshmode.distributed import get_connected_partitions
            neighbors = get_connected_partitions(part_mesh)
            for i_remote_part in neighbors:
                connected_parts.add((i_local_part, i_remote_part))

        from meshmode.discretization import Discretization
        vol_discrs = [Discretization(actx, part_meshes[i], group_factory(order))
                        for i in range(num_parts)]

        from meshmode.mesh import BTAG_PARTITION
        from meshmode.discretization.connection import (make_face_restriction,
                                                        make_partition_connection,
                                                        check_connection)

        for i_local_part, i_remote_part in connected_parts:
            # Mark faces within local_mesh that are connected to remote_mesh
            local_bdry_conn = make_face_restriction(actx, vol_discrs[i_local_part],
                                                    group_factory(order),
                                                    BTAG_PARTITION(i_remote_part))

            # Mark faces within remote_mesh that are connected to local_mesh
            remote_bdry_conn = make_face_restriction(actx, vol_discrs[i_remote_part],
                                                     group_factory(order),
                                                     BTAG_PARTITION(i_local_part))

            bdry_nelements = sum(
                    grp.nelements for grp in local_bdry_conn.to_discr.groups)
            remote_bdry_nelements = sum(
                    grp.nelements for grp in remote_bdry_conn.to_discr.groups)
            assert bdry_nelements == remote_bdry_nelements, \
                    "partitions do not have the same number of connected elements"

            # Gather just enough information for the connection
            local_bdry = local_bdry_conn.to_discr
            local_mesh = part_meshes[i_local_part]
            local_adj_groups = [local_mesh.facial_adjacency_groups[i][None]
                                for i in range(len(local_mesh.groups))]
            local_batches = [local_bdry_conn.groups[i].batches
                                for i in range(len(local_mesh.groups))]
            local_from_elem_faces = [[batch.to_element_face
                                            for batch in grp_batches]
                                        for grp_batches in local_batches]
            local_from_elem_indices = [[batch.to_element_indices.get(queue=queue)
                                            for batch in grp_batches]
                                        for grp_batches in local_batches]

            remote_bdry = remote_bdry_conn.to_discr
            remote_mesh = part_meshes[i_remote_part]
            remote_adj_groups = [remote_mesh.facial_adjacency_groups[i][None]
                                for i in range(len(remote_mesh.groups))]
            remote_batches = [remote_bdry_conn.groups[i].batches
                                for i in range(len(remote_mesh.groups))]
            remote_from_elem_faces = [[batch.to_element_face
                                            for batch in grp_batches]
                                        for grp_batches in remote_batches]
            remote_from_elem_indices = [[batch.to_element_indices.get(queue=queue)
                                            for batch in grp_batches]
                                        for grp_batches in remote_batches]

            # Connect from remote_mesh to local_mesh
            remote_to_local_conn = make_partition_connection(
                    actx, local_bdry_conn, i_local_part, remote_bdry,
                    remote_adj_groups, remote_from_elem_faces,
                    remote_from_elem_indices)

            # Connect from local mesh to remote mesh
            local_to_remote_conn = make_partition_connection(
                    actx, remote_bdry_conn, i_remote_part, local_bdry,
                    local_adj_groups, local_from_elem_faces,
                    local_from_elem_indices)

            check_connection(actx, remote_to_local_conn)
            check_connection(actx, local_to_remote_conn)

            true_local_points = f(thaw(actx, local_bdry.nodes()[0]))
            remote_points = local_to_remote_conn(true_local_points)
            local_points = remote_to_local_conn(remote_points)

            err = flat_norm(true_local_points - local_points, np.inf)

            # Can't currently expect exact results due to limitations of
            # interpolation 'snapping' in DirectDiscretizationConnection's
            # _resample_point_pick_indices
            assert err < 1e-11