Example #1
0
def make_same_mesh_connection(to_discr, from_discr):
    from meshmode.discretization.connection import (
        InterpolationBatch, DiscretizationConnectionElementGroup,
        DirectDiscretizationConnection)

    if from_discr.mesh is not to_discr.mesh:
        raise ValueError("from_discr and to_discr must be based on "
                         "the same mesh")

    assert to_discr.cl_context == from_discr.cl_context

    with cl.CommandQueue(to_discr.cl_context) as queue:
        groups = []
        for igrp, (fgrp,
                   tgrp) in enumerate(zip(from_discr.groups, to_discr.groups)):
            all_elements = cl.array.arange(queue,
                                           fgrp.nelements,
                                           dtype=np.intp).with_queue(None)
            ibatch = InterpolationBatch(from_group_index=igrp,
                                        from_element_indices=all_elements,
                                        to_element_indices=all_elements,
                                        result_unit_nodes=tgrp.unit_nodes,
                                        to_element_face=None)

            groups.append(DiscretizationConnectionElementGroup([ibatch]))

    return DirectDiscretizationConnection(from_discr,
                                          to_discr,
                                          groups,
                                          is_surjective=True)
Example #2
0
def make_opposite_face_connection(volume_to_bdry_conn):
    """Given a boundary restriction connection *volume_to_bdry_conn*,
    return a :class:`DirectDiscretizationConnection` that performs data
    exchange across opposite faces.
    """

    vol_discr = volume_to_bdry_conn.from_discr
    vol_mesh = vol_discr.mesh
    bdry_discr = volume_to_bdry_conn.to_discr

    # make sure we were handed a volume-to-boundary connection
    for i_tgrp, conn_grp in enumerate(volume_to_bdry_conn.groups):
        for batch in conn_grp.batches:
            assert batch.from_group_index == i_tgrp
            assert batch.to_element_face is not None

    ngrps = len(volume_to_bdry_conn.groups)
    assert ngrps == len(vol_discr.groups)
    assert ngrps == len(bdry_discr.groups)

    # One interpolation batch in this connection corresponds
    # to a key (i_tgt_grp,)  (i_src_grp, i_face_tgt,)

    with cl.CommandQueue(vol_discr.cl_context) as queue:
        # a list of batches for each group
        groups = [[] for i_tgt_grp in range(ngrps)]

        for i_src_grp in range(ngrps):
            src_grp_el_lookup = _make_el_lookup_table(queue,
                                                      volume_to_bdry_conn,
                                                      i_src_grp)

            for i_tgt_grp in range(ngrps):
                vbc_tgt_grp_batches = volume_to_bdry_conn.groups[
                    i_tgt_grp].batches

                adj_grp = vol_mesh.facial_adjacency_groups[i_tgt_grp][
                    i_src_grp]

                for i_face_tgt in range(vol_mesh.groups[i_tgt_grp].nfaces):
                    vbc_tgt_grp_face_batch = _find_ibatch_for_face(
                        vbc_tgt_grp_batches, i_face_tgt)

                    groups[i_tgt_grp].extend(
                        _make_cross_face_batches(queue, vol_discr, bdry_discr,
                                                 i_tgt_grp, i_src_grp,
                                                 i_face_tgt, adj_grp,
                                                 vbc_tgt_grp_face_batch,
                                                 src_grp_el_lookup))

    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup)
    return DirectDiscretizationConnection(
        from_discr=bdry_discr,
        to_discr=bdry_discr,
        groups=[
            DiscretizationConnectionElementGroup(batches=batches)
            for batches in groups
        ],
        is_surjective=True)
Example #3
0
def make_refinement_connection(actx, refiner, coarse_discr, group_factory):
    """Return a
    :class:`meshmode.discretization.connection.DiscretizationConnection`
    connecting `coarse_discr` to a discretization on the fine mesh.

    :arg refiner: An instance of
        :class:`meshmode.mesh.refinement.Refiner`

    :arg coarse_discr: An instance of
        :class:`meshmode.discretization.Discretization` associated
        with the mesh given to the refiner

    :arg group_factory: An instance of
        :class:`meshmode.discretization.poly_element.ElementGroupFactory`. Used
        for discretizing the fine mesh.
    """
    from meshmode.discretization.connection import (
        DiscretizationConnectionElementGroup,
        DirectDiscretizationConnection)

    coarse_mesh = refiner.get_previous_mesh()
    fine_mesh = refiner.get_current_mesh()

    if coarse_discr.mesh != coarse_mesh:
        raise ValueError(
            "coarse_discr does not live on the same mesh given to the refiner")

    from meshmode.discretization import Discretization
    fine_discr = Discretization(
        actx,
        fine_mesh,
        group_factory,
        real_dtype=coarse_discr.real_dtype)

    groups = []
    for group_idx, (coarse_discr_group, fine_discr_group, record) in \
            enumerate(zip(coarse_discr.groups, fine_discr.groups,
                          refiner.group_refinement_records)):
        groups.append(
            DiscretizationConnectionElementGroup(
                list(_build_interpolation_batches_for_group(
                        actx, group_idx, coarse_discr_group,
                        fine_discr_group, record))))

    return DirectDiscretizationConnection(
        from_discr=coarse_discr,
        to_discr=fine_discr,
        groups=groups,
        is_surjective=True)
Example #4
0
def _build_boundary_connection(queue, vol_discr, bdry_discr, connection_data,
                               per_face_groups):
    from meshmode.discretization.connection import (
        InterpolationBatch, DiscretizationConnectionElementGroup,
        DirectDiscretizationConnection)

    ibdry_grp = 0
    batches = []

    connection_groups = []
    for igrp, vol_grp in enumerate(vol_discr.groups):
        mgrp = vol_grp.mesh_el_group

        for face_id in range(mgrp.nfaces):
            bdry_grp = bdry_discr.groups[ibdry_grp]
            data = connection_data[igrp, face_id]

            bdry_unit_nodes_01 = (bdry_grp.unit_nodes + 1) * 0.5
            result_unit_nodes = (np.dot(data.A, bdry_unit_nodes_01).T +
                                 data.b).T

            batches.append(
                InterpolationBatch(
                    from_group_index=igrp,
                    from_element_indices=cl.array.to_device(
                        queue,
                        data.group_source_element_indices).with_queue(None),
                    to_element_indices=cl.array.to_device(
                        queue,
                        data.group_target_element_indices).with_queue(None),
                    result_unit_nodes=result_unit_nodes,
                    to_element_face=face_id))

            is_last_face = face_id + 1 == mgrp.nfaces

            if per_face_groups or is_last_face:
                connection_groups.append(
                    DiscretizationConnectionElementGroup(batches))
                batches = []

                ibdry_grp += 1

    assert ibdry_grp == len(bdry_discr.groups)

    return DirectDiscretizationConnection(vol_discr,
                                          bdry_discr,
                                          connection_groups,
                                          is_surjective=True)
Example #5
0
def make_face_to_all_faces_embedding(faces_connection,
                                     all_faces_discr,
                                     from_discr=None):
    """Return a
    :class:`meshmode.discretization.connection.DiscretizationConnection`
    connecting a discretization containing some faces of a discretization
    to one containing all faces.

    :arg faces_connection: must be the (connection) result of calling
        :func:`meshmode.discretization.connection.make_face_restriction`
        with
        :class:`meshmode.discretization.connection.FACE_RESTR_INTERIOR`
        or a boundary tag.
    :arg all_faces_discr: must be the (discretization) result of calling
        :func:`meshmode.discretization.connection.make_face_restriction`
        with
        :class:`meshmode.discretization.connection.FACE_RESTR_ALL`
        for the same volume discretization as the one from which
        *faces_discr* was obtained.
    :arg from_discr: Allows substituting in a different origin
        discretization for the returned connection. This discretization
        must use the same mesh as ``faces_connection.to_discr``.
    """

    vol_discr = faces_connection.from_discr
    faces_discr = faces_connection.to_discr

    if from_discr is None:
        from_discr = faces_discr

    assert from_discr.mesh is faces_discr.mesh

    per_face_groups = (len(vol_discr.groups) != len(faces_discr.groups))

    if len(faces_discr.groups) != len(all_faces_discr.groups):
        raise ValueError("faces_discr and all_faces_discr must have the "
                         "same number of groups")
    if len(faces_connection.groups) != len(all_faces_discr.groups):
        raise ValueError("faces_connection and all_faces_discr must have the "
                         "same number of groups")

    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup,
        InterpolationBatch)

    i_faces_grp = 0

    with cl.CommandQueue(vol_discr.cl_context) as queue:
        groups = []
        for ivol_grp, vol_grp in enumerate(vol_discr.groups):
            batches = []

            nfaces = vol_grp.mesh_el_group.nfaces
            for iface in range(nfaces):
                all_faces_grp = all_faces_discr.groups[i_faces_grp]

                if per_face_groups:
                    assert len(
                        faces_connection.groups[i_faces_grp].batches) == 1
                else:
                    assert (len(
                        faces_connection.groups[i_faces_grp].batches) == nfaces
                            )

                assert np.array_equal(
                    from_discr.groups[i_faces_grp].unit_nodes,
                    all_faces_grp.unit_nodes)

                # {{{ find src_batch

                src_batches = faces_connection.groups[i_faces_grp].batches
                if per_face_groups:
                    src_batch, = src_batches
                else:
                    src_batch = src_batches[iface]
                del src_batches

                # }}}

                if per_face_groups:
                    to_element_indices = src_batch.from_element_indices
                else:
                    assert all_faces_grp.nelements == nfaces * vol_grp.nelements

                    to_element_indices = (
                        vol_grp.nelements * iface +
                        src_batch.from_element_indices.with_queue(queue)
                    ).with_queue(None)

                batches.append(
                    InterpolationBatch(
                        from_group_index=i_faces_grp,
                        from_element_indices=src_batch.to_element_indices,
                        to_element_indices=to_element_indices,
                        result_unit_nodes=all_faces_grp.unit_nodes,
                        to_element_face=None))

                is_last_face = iface + 1 == nfaces
                if per_face_groups or is_last_face:
                    groups.append(
                        DiscretizationConnectionElementGroup(batches=batches))
                    batches = []

                    i_faces_grp += 1

    return DirectDiscretizationConnection(from_discr,
                                          all_faces_discr,
                                          groups,
                                          is_surjective=False)
Example #6
0
def make_partition_connection(local_bdry_conn, i_local_part, remote_bdry,
                              remote_adj_groups, remote_from_elem_faces,
                              remote_from_elem_indices):
    """
    Connects ``local_bdry_conn`` to a neighboring partition.

    :arg local_bdry_conn: A :class:`DiscretizationConnection` of the local
        partition.
    :arg i_local_part: The partition number of the local partition.
    :arg remote_adj_groups: A list of :class:`InterPartitionAdjacency`` of the
        remote partition.
    :arg remote_bdry: A :class:`Discretization` of the boundary of the
        remote partition.
    :arg remote_from_elem_faces: `remote_from_elem_faces[igrp][idx]` gives the face
        that batch `idx` interpolates from in group `igrp`.
    :arg remote_from_elem_indices: `remote_from_elem_indices[igrp][idx]` gives a
        :class:`np.array` of element indices that batch `idx` interpolates from
        in group `igrp`.

    :returns: A :class:`DirectDiscretizationConnection` that performs data
        exchange across faces from the remote partition to partition `i_local_part`.

    .. versionadded:: 2017.1

    .. warning:: Interface is not final.
    """

    from meshmode.mesh.processing import find_group_indices
    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup)

    local_bdry = local_bdry_conn.to_discr
    local_groups = local_bdry_conn.from_discr.mesh.groups

    part_batches = [[] for _ in local_groups]

    with cl.CommandQueue(local_bdry_conn.cl_context) as queue:

        for i_remote_grp, adj in enumerate(remote_adj_groups):
            indices = (i_local_part == adj.neighbor_partitions)
            if not np.any(indices):
                # Skip because i_remote_grp is not connected to i_local_part.
                continue
            i_remote_faces = adj.element_faces[indices]
            i_local_meshwide_elems = adj.global_neighbors[indices]
            i_local_faces = adj.neighbor_faces[indices]

            i_local_grps = find_group_indices(local_groups,
                                              i_local_meshwide_elems)

            for i_local_grp in np.unique(i_local_grps):

                elem_base = local_groups[i_local_grp].element_nr_base
                local_el_lookup = _make_bdry_el_lookup_table(
                    queue, local_bdry_conn, i_local_grp)

                for i_remote_face in i_remote_faces:

                    index_flags = np.logical_and(
                        i_local_grps == i_local_grp,
                        i_remote_faces == i_remote_face)
                    if not np.any(index_flags):
                        continue

                    remote_bdry_indices = None
                    for idxs, face in zip(
                            remote_from_elem_indices[i_remote_grp],
                            remote_from_elem_faces[i_remote_grp]):
                        if face == i_remote_face:
                            remote_bdry_indices = idxs
                            break
                    assert remote_bdry_indices is not None

                    elems = i_local_meshwide_elems[index_flags] - elem_base
                    faces = i_local_faces[index_flags]
                    local_bdry_indices = local_el_lookup[elems, faces]

                    batches = _make_cross_face_batches(
                        queue, local_bdry, remote_bdry, i_local_grp,
                        i_remote_grp, local_bdry_indices, remote_bdry_indices)

                    part_batches[i_local_grp].extend(batches)

    return DirectDiscretizationConnection(
        from_discr=remote_bdry,
        to_discr=local_bdry,
        groups=[
            DiscretizationConnectionElementGroup(batches=grp_batches)
            for grp_batches in part_batches
        ],
        is_surjective=True)
Example #7
0
def make_opposite_face_connection(volume_to_bdry_conn):
    """Given a boundary restriction connection *volume_to_bdry_conn*,
    return a :class:`DirectDiscretizationConnection` that performs data
    exchange across opposite faces.
    """

    vol_discr = volume_to_bdry_conn.from_discr
    vol_mesh = vol_discr.mesh
    bdry_discr = volume_to_bdry_conn.to_discr

    # make sure we were handed a volume-to-boundary connection
    for i_tgrp, conn_grp in enumerate(volume_to_bdry_conn.groups):
        for batch in conn_grp.batches:
            assert batch.from_group_index == i_tgrp
            assert batch.to_element_face is not None

    ngrps = len(volume_to_bdry_conn.groups)
    assert ngrps == len(vol_discr.groups)
    assert ngrps == len(bdry_discr.groups)

    # One interpolation batch in this connection corresponds
    # to a key (i_tgt_grp,)  (i_src_grp, i_face_tgt,)

    with cl.CommandQueue(vol_discr.cl_context) as queue:
        # a list of batches for each group
        groups = [[] for i_tgt_grp in range(ngrps)]

        for i_src_grp in range(ngrps):
            src_grp_el_lookup = _make_bdry_el_lookup_table(
                queue, volume_to_bdry_conn, i_src_grp)

            for i_tgt_grp in range(ngrps):
                vbc_tgt_grp_batches = volume_to_bdry_conn.groups[
                    i_tgt_grp].batches

                adj = vol_mesh.facial_adjacency_groups[i_tgt_grp][i_src_grp]

                for i_face_tgt in range(vol_mesh.groups[i_tgt_grp].nfaces):
                    vbc_tgt_grp_face_batch = _find_ibatch_for_face(
                        vbc_tgt_grp_batches, i_face_tgt)

                    # {{{ index wrangling

                    # Assert that the adjacency group and the restriction
                    # interpolation batch and the adjacency group have the same
                    # element ordering.

                    adj_tgt_flags = adj.element_faces == i_face_tgt

                    assert (np.array_equal(
                        adj.elements[adj_tgt_flags],
                        vbc_tgt_grp_face_batch.from_element_indices.get(
                            queue=queue)))

                    # find to_element_indices

                    tgt_bdry_element_indices = (
                        vbc_tgt_grp_face_batch.to_element_indices.get(
                            queue=queue))

                    # find from_element_indices

                    src_vol_element_indices = adj.neighbors[adj_tgt_flags]
                    src_element_faces = adj.neighbor_faces[adj_tgt_flags]

                    src_bdry_element_indices = src_grp_el_lookup[
                        src_vol_element_indices, src_element_faces]

                    # }}}

                    # {{{ visualization (for debugging)

                    if 0:
                        print("TVE", adj.elements[adj_tgt_flags])
                        print("TBE", tgt_bdry_element_indices)
                        print("FVE", src_vol_element_indices)
                        from meshmode.mesh.visualization import draw_2d_mesh
                        import matplotlib.pyplot as pt
                        draw_2d_mesh(vol_discr.mesh,
                                     draw_element_numbers=True,
                                     set_bounding_box=True,
                                     draw_vertex_numbers=False,
                                     draw_face_numbers=True,
                                     fill=None)
                        pt.figure()

                        draw_2d_mesh(bdry_discr.mesh,
                                     draw_element_numbers=True,
                                     set_bounding_box=True,
                                     draw_vertex_numbers=False,
                                     draw_face_numbers=True,
                                     fill=None)

                        pt.show()

                    # }}}

                    groups[i_tgt_grp].extend(
                        _make_cross_face_batches(queue, bdry_discr, bdry_discr,
                                                 i_tgt_grp, i_src_grp,
                                                 tgt_bdry_element_indices,
                                                 src_bdry_element_indices))

    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup)
    return DirectDiscretizationConnection(
        from_discr=bdry_discr,
        to_discr=bdry_discr,
        groups=[
            DiscretizationConnectionElementGroup(batches=batches)
            for batches in groups
        ],
        is_surjective=True)
Example #8
0
def flatten_chained_connection(queue, connection):
    """Collapse a connection into a direct connection.

    If the given connection is already a
    :class:`~meshmode.discretization.connection.DirectDiscretizationConnection`
    nothing is done. However, if the connection is a
    :class:`~meshmode.discretization.connection.ChainedDiscretizationConnection`,
    a new direct connection is constructed that transports from
    :attr:`connection.from_discr` to :attr:`connection.to_discr`.

    The new direct connection will have a number of groups and batches that
    is, at worse, the product of all the connections in the chain. For
    example, if we consider a connection between a discretization and a
    two-level refinement, both levels will have :math:`n` groups and
    :math:`m + 1` batches per group, where :math:`m` is the number of
    subdivisions of an element (exact number depends on implementation
    details in
    :func:`~meshmode.discretization.connection.make_refinement_connection`).
    However, a direct connection from level :math:`0` to level :math:`2`
    will have at worst :math:`n^2` groups and each group will have
    :math:`(m + 1)^2` batches.

    .. warning::

        If a large number of connections is chained, the number of groups and
        batches can become very large.

    :arg queue: An instance of :class:`pyopencl.CommandQueue`.
    :arg connection: An instance of
        :class:`~meshmode.discretization.connection.DiscretizationConnection`.
    :return: An instance of
        :class:`~meshmode.discretization.connection.DirectDiscretizationConnection`.
    """
    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup,
        make_same_mesh_connection)

    if not hasattr(connection, 'connections'):
        return connection

    if not connection.connections:
        return make_same_mesh_connection(connection.to_discr,
                                         connection.from_discr)

    # recursively build direct connections
    connections = connection.connections
    direct_connections = []
    for conn in connections:
        direct_connections.append(flatten_chained_connection(queue, conn))

    # merge all the direct connections
    from_conn = direct_connections[0]
    for to_conn in direct_connections[1:]:
        el_table = _build_element_lookup_table(queue, from_conn)
        grp_to_grp, batch_info = _build_new_group_table(from_conn, to_conn)

        # distribute the indices to new groups and batches
        from_bins = [[np.empty(0, dtype=np.int) for _ in g]
                     for g in batch_info]
        to_bins = [[np.empty(0, dtype=np.int) for _ in g] for g in batch_info]

        for (igrp, ibatch), (_, from_batch) in _iterbatches(from_conn.groups):
            from_to_element_indices = from_batch.to_element_indices.get(queue)

            for (jgrp, jbatch), (_, to_batch) in _iterbatches(to_conn.groups):
                igrp_new, ibatch_new = grp_to_grp[igrp, ibatch, jgrp, jbatch]

                jfrom = to_batch.from_element_indices.get(queue)
                jto = to_batch.to_element_indices.get(queue)

                mask = np.isin(jfrom, from_to_element_indices)
                from_bins[igrp_new][ibatch_new] = \
                    np.hstack([from_bins[igrp_new][ibatch_new],
                               el_table[igrp][jfrom[mask]]])
                to_bins[igrp_new][ibatch_new] = \
                    np.hstack([to_bins[igrp_new][ibatch_new],
                               jto[mask]])

        # build new groups
        groups = []
        for igrp, (from_bin, to_bin) in enumerate(zip(from_bins, to_bins)):
            groups.append(
                DiscretizationConnectionElementGroup(
                    list(
                        _build_batches(queue, from_bin, to_bin,
                                       batch_info[igrp]))))

        from_conn = DirectDiscretizationConnection(
            from_discr=from_conn.from_discr,
            to_discr=to_conn.to_discr,
            groups=groups,
            is_surjective=connection.is_surjective)

    return from_conn
Example #9
0
def make_partition_connection(actx, *, local_bdry_conn, i_local_part,
                              remote_bdry_discr, remote_group_infos):
    """
    Connects ``local_bdry_conn`` to a neighboring partition.

    :arg local_bdry_conn: A :class:`DiscretizationConnection` of the local
        partition.
    :arg i_local_part: The partition number of the local partition.
    :arg remote_bdry_discr: A :class:`~meshmode.discretization.Discretization`
        of the boundary of the remote partition.
    :arg remote_group_infos: An array of
        :class:`meshmode.distributed.RemoteGroupInfo` instances, one per remote
        volume element group.
    :returns: A :class:`DirectDiscretizationConnection` that performs data
        exchange across faces from the remote partition to partition `i_local_part`.

    .. versionadded:: 2017.1

    .. warning:: Interface is not final.
    """

    from meshmode.mesh.processing import find_group_indices
    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup)

    local_vol_groups = local_bdry_conn.from_discr.mesh.groups

    part_batches = [[] for _ in local_vol_groups]

    assert len(local_vol_groups) == len(local_bdry_conn.to_discr.groups)

    # We need a nested loop over remote and local groups here.
    # The code assumes that there is the same number of volume and surface groups.
    #
    # A weak reason to choose remote as the outer loop is because
    # InterPartitionAdjacency refers to neighbors by global volume element
    # numbers, and we only have enough information to resolve those to (group,
    # group_local_el_nr) for local elements (whereas we have no information
    # about remote volume elements).
    #
    # (See the find_group_indices below.)

    for rgi in remote_group_infos:
        rem_ipag = rgi.inter_partition_adj_group

        indices = (i_local_part == rem_ipag.neighbor_partitions)
        if not np.any(indices):
            # Skip because remote group is not connected to i_local_part.
            continue

        i_remote_vol_elems = rem_ipag.elements[indices]
        i_remote_faces = rem_ipag.element_faces[indices]
        i_local_vol_elems = rem_ipag.partition_neighbors[indices]
        i_local_faces = rem_ipag.neighbor_faces[indices]

        del indices

        i_local_grps = find_group_indices(local_vol_groups, i_local_vol_elems)

        # {{{ make remote_vol_to_bdry

        remote_approx_vol_nelements = np.max(rgi.vol_elem_indices) + 1
        remote_approx_nfaces = np.max(rgi.bdry_faces) + 1
        remote_vol_to_bdry = np.full(
            (remote_approx_vol_nelements, remote_approx_nfaces),
            -1,
            dtype=remote_bdry_discr.mesh.element_id_dtype)
        remote_vol_to_bdry[rgi.vol_elem_indices, rgi.bdry_faces] = \
                rgi.bdry_elem_indices

        # }}}

        for i_local_grp in np.unique(i_local_grps):

            # {{{ come up with matched_{local,remote}_bdry_el_indices

            local_vol_to_bdry = _make_bdry_el_lookup_table(
                actx, local_bdry_conn, i_local_grp)

            local_indices = np.where(i_local_grps == i_local_grp)[0]
            if len(local_indices) == 0:
                continue

            local_grp_vol_elems = (
                i_local_vol_elems[local_indices] -
                local_vol_groups[i_local_grp].element_nr_base)
            # These are group-local.
            remote_grp_vol_elems = i_remote_vol_elems[local_indices]

            matched_local_bdry_el_indices = local_vol_to_bdry[
                local_grp_vol_elems, i_local_faces[local_indices]]
            assert (matched_local_bdry_el_indices >= 0).all()
            matched_remote_bdry_el_indices = remote_vol_to_bdry[
                remote_grp_vol_elems, i_remote_faces[local_indices]]
            assert (matched_remote_bdry_el_indices >= 0).all()

            # }}}

            grp_batches = _make_cross_face_batches(
                actx, local_bdry_conn.to_discr, remote_bdry_discr, i_local_grp,
                rem_ipag.igroup, matched_local_bdry_el_indices,
                matched_remote_bdry_el_indices)

            part_batches[i_local_grp].extend(grp_batches)

    return DirectDiscretizationConnection(
        from_discr=remote_bdry_discr,
        to_discr=local_bdry_conn.to_discr,
        groups=[
            DiscretizationConnectionElementGroup(batches=grp_batches)
            for grp_batches in part_batches
        ],
        is_surjective=True)
Example #10
0
def make_opposite_face_connection(actx, volume_to_bdry_conn):
    """Given a boundary restriction connection *volume_to_bdry_conn*,
    return a :class:`DirectDiscretizationConnection` that performs data
    exchange across opposite faces.
    """

    vol_discr = volume_to_bdry_conn.from_discr
    vol_mesh = vol_discr.mesh
    bdry_discr = volume_to_bdry_conn.to_discr

    # make sure we were handed a volume-to-boundary connection
    for i_tgrp, conn_grp in enumerate(volume_to_bdry_conn.groups):
        for batch in conn_grp.batches:
            assert batch.from_group_index == i_tgrp
            assert batch.to_element_face is not None

    ngrps = len(volume_to_bdry_conn.groups)
    assert ngrps == len(vol_discr.groups)
    assert ngrps == len(bdry_discr.groups)

    # One interpolation batch in this connection corresponds
    # to a key (i_tgt_grp,)  (i_src_grp, i_face_tgt,)

    # a list of batches for each group
    groups = [[] for i_tgt_grp in range(ngrps)]

    for i_src_grp in range(ngrps):
        src_grp_el_lookup = _make_bdry_el_lookup_table(actx,
                                                       volume_to_bdry_conn,
                                                       i_src_grp)

        for i_tgt_grp in range(ngrps):
            vbc_tgt_grp_batches = volume_to_bdry_conn.groups[i_tgt_grp].batches

            adj = vol_mesh.facial_adjacency_groups[i_tgt_grp][i_src_grp]

            for i_face_tgt in range(vol_mesh.groups[i_tgt_grp].nfaces):
                vbc_tgt_grp_face_batch = _find_ibatch_for_face(
                    vbc_tgt_grp_batches, i_face_tgt)

                # {{{ index wrangling

                # The elements in the adjacency group will be a subset of
                # the elements in the restriction interpolation batch:
                # Imagine an inter-group boundary. The volume-to-boundary
                # connection will include all faces as targets, whereas
                # there will be separate adjacency groups for intra- and
                # inter-group connections.

                adj_tgt_flags = adj.element_faces == i_face_tgt
                adj_els = adj.elements[adj_tgt_flags]
                if adj_els.size == 0:
                    # NOTE: this case can happen for inter-group boundaries
                    # when all elements are adjacent on the same face
                    # index, so all other ones will be empty
                    continue

                vbc_els = thaw_to_numpy(
                    actx, vbc_tgt_grp_face_batch.from_element_indices)

                if len(adj_els) == len(vbc_els):
                    # Same length: assert (below) that the two use the same
                    # ordering.
                    vbc_used_els = slice(None)

                else:
                    # Genuine subset: figure out an index mapping.
                    vbc_els_sort_idx = np.argsort(vbc_els)
                    vbc_used_els = vbc_els_sort_idx[np.searchsorted(
                        vbc_els, adj_els, sorter=vbc_els_sort_idx)]

                assert np.array_equal(vbc_els[vbc_used_els], adj_els)

                # find to_element_indices

                tgt_bdry_element_indices = thaw_to_numpy(
                    actx,
                    vbc_tgt_grp_face_batch.to_element_indices)[vbc_used_els]

                # find from_element_indices

                src_vol_element_indices = adj.neighbors[adj_tgt_flags]
                src_element_faces = adj.neighbor_faces[adj_tgt_flags]

                src_bdry_element_indices = src_grp_el_lookup[
                    src_vol_element_indices, src_element_faces]

                # }}}

                # {{{ visualization (for debugging)

                if 0:
                    print("TVE", adj.elements[adj_tgt_flags])
                    print("TBE", tgt_bdry_element_indices)
                    print("FVE", src_vol_element_indices)
                    from meshmode.mesh.visualization import draw_2d_mesh
                    import matplotlib.pyplot as pt
                    draw_2d_mesh(vol_discr.mesh,
                                 draw_element_numbers=True,
                                 set_bounding_box=True,
                                 draw_vertex_numbers=False,
                                 draw_face_numbers=True,
                                 fill=None)
                    pt.figure()

                    draw_2d_mesh(bdry_discr.mesh,
                                 draw_element_numbers=True,
                                 set_bounding_box=True,
                                 draw_vertex_numbers=False,
                                 draw_face_numbers=True,
                                 fill=None)

                    pt.show()

                # }}}

                batches = _make_cross_face_batches(actx, bdry_discr,
                                                   bdry_discr, i_tgt_grp,
                                                   i_src_grp,
                                                   tgt_bdry_element_indices,
                                                   src_bdry_element_indices)
                groups[i_tgt_grp].extend(batches)

    from meshmode.discretization.connection import (
        DirectDiscretizationConnection, DiscretizationConnectionElementGroup)
    return DirectDiscretizationConnection(
        from_discr=bdry_discr,
        to_discr=bdry_discr,
        groups=[
            DiscretizationConnectionElementGroup(batches=batches)
            for batches in groups
        ],
        is_surjective=True)