示例#1
0
 def to_numpy(self, actx: PyOpenCLArrayContext) -> "BlockProxyPoints":
     from arraycontext import to_numpy
     from dataclasses import replace
     return replace(self,
                    points=to_numpy(self.points, actx),
                    centers=to_numpy(self.centers, actx),
                    radii=to_numpy(self.radii, actx))
示例#2
0
    def __init__(self,
                 dcoll: DiscretizationCollection,
                 array_container: ArrayOrContainerT,
                 remote_rank, tag=None):
        actx = get_container_context_recursively(array_container)
        btag = BTAG_PARTITION(remote_rank)

        local_bdry_data = project(dcoll, "vol", btag, array_container)
        comm = dcoll.mpi_communicator

        self.dcoll = dcoll
        self.array_context = actx
        self.remote_btag = btag
        self.bdry_discr = dcoll.discr_from_dd(btag)
        self.local_bdry_data = local_bdry_data
        self.local_bdry_data_np = \
            to_numpy(flatten(self.local_bdry_data, actx), actx)

        self.tag = self.base_tag
        if tag is not None:
            self.tag += tag

        # Here, we initialize both send and recieve operations through
        # mpi4py `Request` (MPI_Request) instances for comm.Isend (MPI_Isend)
        # and comm.Irecv (MPI_Irecv) respectively. These initiate non-blocking
        # point-to-point communication requests and require explicit management
        # via the use of wait (MPI_Wait, MPI_Waitall, MPI_Waitany, MPI_Waitsome),
        # test (MPI_Test, MPI_Testall, MPI_Testany, MPI_Testsome), and cancel
        # (MPI_Cancel). The rank-local data `self.local_bdry_data_np` will have its
        # associated memory buffer sent across connected ranks and must not be
        # modified at the Python level during this process. Completion of the
        # requests is handled in :meth:`finish`.
        #
        # For more details on the mpi4py semantics, see:
        # https://mpi4py.readthedocs.io/en/stable/overview.html#nonblocking-communications
        #
        # NOTE: mpi4py currently (2021-11-03) holds a reference to the send
        # memory buffer for (i.e. `self.local_bdry_data_np`) until the send
        # requests is complete, however it is not clear that this is documented
        # behavior. We hold on to the buffer (via the instance attribute)
        # as well, just in case.
        self.send_req = comm.Isend(self.local_bdry_data_np,
                                   remote_rank,
                                   tag=self.tag)
        self.remote_data_host_numpy = np.empty_like(self.local_bdry_data_np)
        self.recv_req = comm.Irecv(self.remote_data_host_numpy,
                                   remote_rank,
                                   tag=self.tag)
示例#3
0
def gather_block_neighbor_points(
        actx: PyOpenCLArrayContext,
        discr: Discretization,
        pxy: BlockProxyPoints,
        max_particles_in_box: Optional[int] = None) -> BlockIndexRanges:
    """Generate a set of neighboring points for each range of points in
    *discr*. Neighboring points of a range :math:`i` are defined
    as all the points inside the proxy ball :math:`i` that do not also
    belong to the range itself.
    """

    if max_particles_in_box is None:
        # FIXME: this is a fairly arbitrary value
        max_particles_in_box = 32

    # {{{ get only sources in indices

    @memoize_in(actx,
                (gather_block_neighbor_points, discr.ambient_dim, "picker_knl")
                )
    def prg():
        knl = lp.make_kernel(
            "{[idim, i]: 0 <= idim < ndim and 0 <= i < npoints}",
            """
            result[idim, i] = ary[idim, srcindices[i]]
            """,
            [
                lp.GlobalArg("ary",
                             None,
                             shape=(discr.ambient_dim, "ndofs"),
                             dim_tags="sep,C"),
                lp.ValueArg("ndofs", np.int64), ...
            ],
            name="picker_knl",
            assumptions="ndim>=1 and npoints>=1",
            fixed_parameters=dict(ndim=discr.ambient_dim),
            lang_version=MOST_RECENT_LANGUAGE_VERSION,
        )

        knl = lp.tag_inames(knl, "idim*:unr")
        knl = lp.split_iname(knl, "i", 64, outer_tag="g.0")

        return knl

    _, (sources, ) = prg()(actx.queue,
                           ary=flatten(discr.nodes(),
                                       actx,
                                       leaf_class=DOFArray),
                           srcindices=pxy.srcindices.indices)

    # }}}

    # {{{ perform area query

    from boxtree import TreeBuilder
    builder = TreeBuilder(actx.context)
    tree, _ = builder(actx.queue,
                      sources,
                      max_particles_in_box=max_particles_in_box)

    from boxtree.area_query import AreaQueryBuilder
    builder = AreaQueryBuilder(actx.context)
    query, _ = builder(actx.queue, tree, pxy.centers, pxy.radii)

    # find nodes inside each proxy ball
    tree = tree.get(actx.queue)
    query = query.get(actx.queue)

    # }}}

    # {{{ retrieve results

    from arraycontext import to_numpy
    pxycenters = to_numpy(pxy.centers, actx)
    pxyradii = to_numpy(pxy.radii, actx)
    indices = pxy.srcindices

    nbrindices = np.empty(indices.nblocks, dtype=object)
    for iblock in range(indices.nblocks):
        # get list of boxes intersecting the current ball
        istart = query.leaves_near_ball_starts[iblock]
        iend = query.leaves_near_ball_starts[iblock + 1]
        iboxes = query.leaves_near_ball_lists[istart:iend]

        if (iend - istart) <= 0:
            nbrindices[iblock] = np.empty(0, dtype=np.int64)
            continue

        # get nodes inside the boxes
        istart = tree.box_source_starts[iboxes]
        iend = istart + tree.box_source_counts_cumul[iboxes]
        isources = np.hstack([np.arange(s, e) for s, e in zip(istart, iend)])
        nodes = np.vstack([s[isources] for s in tree.sources])
        isources = tree.user_source_ids[isources]

        # get nodes inside the ball but outside the current range
        # FIXME: this assumes that only the points in `pxy.srcindices` should
        # count as neighbors, not all the nodes in the discretization.
        # FIXME: it also assumes that all the indices are sorted?
        center = pxycenters[:, iblock].reshape(-1, 1)
        radius = pxyradii[iblock]
        mask = ((la.norm(nodes - center, axis=0) < radius)
                & ((isources < indices.ranges[iblock])
                   | (indices.ranges[iblock + 1] <= isources)))

        nbrindices[iblock] = indices.indices[isources[mask]]

    # }}}

    from pytential.linalg import make_block_index_from_array
    return make_block_index_from_array(indices=nbrindices)
示例#4
0
    def __call__(self, actx: PyOpenCLArrayContext, source_dd,
                 indices: BlockIndexRanges, **kwargs) -> BlockProxyPoints:
        """Generate proxy points for each block in *indices* with nodes in
        the discretization *source_dd*.

        :arg source_dd: a :class:`~pytential.symbolic.primitives.DOFDescriptor`
            for the discretization on which the proxy points are to be
            generated.
        """
        from pytential import sym
        source_dd = sym.as_dofdesc(source_dd)
        discr = self.places.get_discretization(source_dd.geometry,
                                               source_dd.discr_stage)

        # {{{ get proxy centers and radii

        sources = flatten(discr.nodes(), actx, leaf_class=DOFArray)

        knl = self.get_centers_knl(actx)
        _, (centers_dev, ) = knl(actx.queue,
                                 sources=sources,
                                 srcindices=indices.indices,
                                 srcranges=indices.ranges)

        knl = self.get_radii_knl(actx)
        _, (radii_dev, ) = knl(actx.queue,
                               sources=sources,
                               srcindices=indices.indices,
                               srcranges=indices.ranges,
                               radius_factor=self.radius_factor,
                               proxy_centers=centers_dev,
                               **kwargs)

        # }}}

        # {{{ build proxy points for each block

        from arraycontext import to_numpy
        centers = np.vstack(to_numpy(centers_dev, actx))
        radii = to_numpy(radii_dev, actx)

        nproxy = self.nproxy * indices.nblocks
        proxies = np.empty((self.ambient_dim, nproxy), dtype=centers.dtype)
        pxy_nr_base = 0

        for i in range(indices.nblocks):
            points = radii[i] * self.ref_points + centers[:, i].reshape(-1, 1)
            proxies[:, pxy_nr_base:pxy_nr_base + self.nproxy] = points

            pxy_nr_base += self.nproxy

        # }}}

        pxyindices = np.arange(0, nproxy, dtype=indices.indices.dtype)
        pxyranges = np.arange(0, nproxy + 1, self.nproxy)

        from arraycontext import freeze, from_numpy
        from pytential.linalg import make_block_index_from_array
        return BlockProxyPoints(
            lpot_source=self.places.get_geometry(source_dd.geometry),
            srcindices=indices,
            indices=make_block_index_from_array(pxyindices, pxyranges),
            points=freeze(from_numpy(proxies, actx), actx),
            centers=freeze(centers_dev, actx),
            radii=freeze(radii_dev, actx),
        )
示例#5
0
                                     FACE_RESTR_INTERIOR, "all_faces",
                                     flux(dcoll, interior_tpair)))

    duh_by_dt = op.inverse_mass(dcoll,
                                np.dot([2 * np.pi], Su) - lift)

    # forward euler time step
    uh = uh + dt * duh_by_dt
    t += dt
# ENDEXAMPLE


# Plot the solution:
def u_exact(x, t):
    return actx.np.sin(x[0] - 2 * np.pi * t)


assert op.norm(dcoll,
               uh - u_exact(x_vol, t_final),
               p=2) <= 0.1
import matplotlib.pyplot as plt
from arraycontext import to_numpy
plt.plot(to_numpy(actx.np.ravel(x_vol[0][0]), actx),
         to_numpy(actx.np.ravel(uh[0]), actx), label="Numerical")
plt.plot(to_numpy(actx.np.ravel(x_vol[0][0]), actx),
         to_numpy(actx.np.ravel(u_exact(x_vol, t_final)[0]), actx), label="Exact")
plt.xlabel("$x$")
plt.ylabel("$u$")
plt.legend()
plt.show()
示例#6
0
 def to_numpy(self, ary):
     from arraycontext import to_numpy
     return to_numpy(ary, self.geo_data._setup_actx)