Ejemplo n.º 1
0
def cross_rank_trace_pairs(discrwb, vec, tag=None):
    if (isinstance(vec, np.ndarray)
            and vec.dtype.char == "O"
            and not isinstance(vec, DOFArray)):

        n, = vec.shape
        result = {}
        for ivec in range(n):
            for rank_tpair in _cross_rank_trace_pairs_scalar_field(
                    discrwb, vec[ivec]):
                assert isinstance(rank_tpair.dd.domain_tag, sym.DTAG_BOUNDARY)
                assert isinstance(rank_tpair.dd.domain_tag.tag, BTAG_PARTITION)
                result[rank_tpair.dd.domain_tag.tag.part_nr, ivec] = rank_tpair

        return [
            TracePair(
                dd=sym.as_dofdesc(sym.DTAG_BOUNDARY(BTAG_PARTITION(remote_rank))),
                interior=make_obj_array([
                    result[remote_rank, i].int for i in range(n)]),
                exterior=make_obj_array([
                    result[remote_rank, i].ext for i in range(n)])
                )
            for remote_rank in discrwb.connected_ranks()]
    else:
        return _cross_rank_trace_pairs_scalar_field(discrwb, vec, tag=tag)
Ejemplo n.º 2
0
    def discr_from_dd(self, dd):
        dd = sym.as_dofdesc(dd)

        qtag = dd.quadrature_tag

        if dd.is_volume():
            if qtag is not sym.QTAG_NONE:
                return self._quad_volume_discr(qtag)
            return self._volume_discr

        if qtag is not sym.QTAG_NONE:
            no_quad_discr = self.discr_from_dd(sym.DOFDesc(dd.domain_tag))

            from meshmode.discretization import Discretization
            return Discretization(self._volume_discr.cl_context,
                                  no_quad_discr.mesh,
                                  self.group_factory_for_quadrature_tag(qtag))

        assert qtag is sym.QTAG_NONE

        if dd.domain_tag is sym.FACE_RESTR_ALL:
            return self._all_faces_volume_connection().to_discr
        elif dd.domain_tag is sym.FACE_RESTR_INTERIOR:
            return self._interior_faces_connection().to_discr
        elif dd.is_boundary():
            return self._boundary_connection(dd.domain_tag).to_discr
        else:
            raise ValueError("DOF desc tag not understood: " + str(dd))
Ejemplo n.º 3
0
def norm(p, arg, dd=None):
    """
    :arg arg: is assumed to be a vector, i.e. have shape ``(n,)``.
    """
    sym = _sym()

    if dd is None:
        dd = sym.DD_VOLUME

    dd = sym.as_dofdesc(dd)

    if p == 2:
        norm_squared = sym.NodalSum(dd_in=dd)(
                sym.FunctionSymbol("fabs")(
                    arg * sym.MassOperator()(arg)))

        if isinstance(norm_squared, np.ndarray):
            norm_squared = norm_squared.sum()

        return sym.FunctionSymbol("sqrt")(norm_squared)

    elif p == np.Inf:
        result = sym.NodalMax(dd_in=dd)(sym.FunctionSymbol("fabs")(arg))
        from pymbolic.primitives import Max

        if isinstance(result, np.ndarray):
            from functools import reduce
            result = reduce(Max, result)

        return result

    else:
        raise ValueError("unsupported value of p")
Ejemplo n.º 4
0
    def discr_from_dd(self, dd):
        dd = sym.as_dofdesc(dd)

        if dd.quadrature_tag is not sym.QTAG_NONE:
            raise ValueError("quadrature discretization requested from "
                             "PointsDiscretization")
        if dd.domain_tag is not sym.DTAG_VOLUME_ALL:
            raise ValueError("non-volume discretization requested from "
                             "PointsDiscretization")

        return self
Ejemplo n.º 5
0
def integral(arg, dd=None):
    sym = _sym()

    if dd is None:
        dd = sym.DD_VOLUME

    dd = sym.as_dofdesc(dd)

    return sym.NodalSum(dd)(
            arg * sym.cse(
                sym.MassOperator(dd_in=dd)(sym.Ones(dd)),
                "mass_quad_weights",
                sym.cse_scope.DISCRETIZATION))
Ejemplo n.º 6
0
    def project(self, src, tgt, vec):
        """Project from one discretization to another, e.g. from the
        volume to the boundary, or from the base to the an overintegrated
        quadrature discretization.

        :arg src: a :class:`~grudge.sym.DOFDesc`, or a value convertible to one
        :arg tgt: a :class:`~grudge.sym.DOFDesc`, or a value convertible to one
        :arg vec: a :class:`~meshmode.dof_array.DOFArray`
        """
        src = sym.as_dofdesc(src)
        tgt = sym.as_dofdesc(tgt)
        if src == tgt:
            return vec

        if isinstance(vec, np.ndarray):
            return obj_array_vectorize(lambda el: self.project(src, tgt, el),
                                       vec)

        if isinstance(vec, Number):
            return vec

        return self.connection_from_dds(src, tgt)(vec)
Ejemplo n.º 7
0
    def finish(self):
        self.recv_req.Wait()

        actx = self.array_context
        remote_dof_array = unflatten(self.array_context, self.bdry_discr,
                actx.from_numpy(self.remote_data_host))

        bdry_conn = self.discrwb.get_distributed_boundary_swap_connection(
                sym.as_dofdesc(sym.DTAG_BOUNDARY(self.remote_btag)))
        swapped_remote_dof_array = bdry_conn(remote_dof_array)

        self.send_req.Wait()

        return TracePair(self.remote_btag, self.local_dof_array,
                swapped_remote_dof_array)
Ejemplo n.º 8
0
    def norm(self, vec, p=2, dd=None):
        if dd is None:
            dd = "vol"

        dd = sym.as_dofdesc(dd)

        if isinstance(vec, np.ndarray):
            if p == 2:
                return sum(
                    self.norm(vec[idx], dd=dd)**2
                    for idx in np.ndindex(vec.shape))**0.5
            elif p == np.inf:
                return max(
                    self.norm(vec[idx], np.inf, dd=dd)
                    for idx in np.ndindex(vec.shape))
            else:
                raise ValueError("unsupported norm order")

        return self._norm(p, dd)(arg=vec)
Ejemplo n.º 9
0
 def __init__(self, i_remote_part):
     from meshmode.discretization.connection import FACE_RESTR_INTERIOR
     from meshmode.mesh import BTAG_PARTITION
     self.prev_dd = sym.as_dofdesc(FACE_RESTR_INTERIOR)
     self.new_dd = sym.as_dofdesc(BTAG_PARTITION(i_remote_part))
Ejemplo n.º 10
0
def test_surface_divergence_theorem(actx_factory, mesh_name, visualize=False):
    r"""Check the surface divergence theorem.

        .. math::

            \int_Sigma \phi \nabla_i f_i =
            \int_\Sigma \nabla_i \phi f_i +
            \int_\Sigma \kappa \phi f_i n_i +
            \int_{\partial \Sigma} \phi f_i m_i

        where :math:`n_i` is the surface normal and :class:`m_i` is the
        face normal (which should be orthogonal to both the surface normal
        and the face tangent).
    """
    actx = actx_factory()

    # {{{ cases

    if mesh_name == "2-1-ellipse":
        from mesh_data import EllipseMeshBuilder
        builder = EllipseMeshBuilder(radius=3.1, aspect_ratio=2.0)
    elif mesh_name == "spheroid":
        from mesh_data import SpheroidMeshBuilder
        builder = SpheroidMeshBuilder()
    elif mesh_name == "circle":
        from mesh_data import EllipseMeshBuilder
        builder = EllipseMeshBuilder(radius=1.0, aspect_ratio=1.0)
    elif mesh_name == "starfish":
        from mesh_data import StarfishMeshBuilder
        builder = StarfishMeshBuilder()
    elif mesh_name == "sphere":
        from mesh_data import SphereMeshBuilder
        builder = SphereMeshBuilder(radius=1.0, mesh_order=16)
    else:
        raise ValueError("unknown mesh name: %s" % mesh_name)

    # }}}

    # {{{ convergene

    def f(x):
        return flat_obj_array(
                sym.sin(3*x[1]) + sym.cos(3*x[0]) + 1.0,
                sym.sin(2*x[0]) + sym.cos(x[1]),
                3.0 * sym.cos(x[0] / 2) + sym.cos(x[1]),
                )[:ambient_dim]

    from pytools.convergence import EOCRecorder
    eoc_global = EOCRecorder()
    eoc_local = EOCRecorder()

    theta = np.pi / 3.33
    ambient_dim = builder.ambient_dim
    if ambient_dim == 2:
        mesh_rotation = np.array([
            [np.cos(theta), -np.sin(theta)],
            [np.sin(theta), np.cos(theta)],
            ])
    else:
        mesh_rotation = np.array([
            [1.0, 0.0, 0.0],
            [0.0, np.cos(theta), -np.sin(theta)],
            [0.0, np.sin(theta), np.cos(theta)],
            ])

    mesh_offset = np.array([0.33, -0.21, 0.0])[:ambient_dim]

    for i, resolution in enumerate(builder.resolutions):
        from meshmode.mesh.processing import affine_map
        mesh = builder.get_mesh(resolution, builder.mesh_order)
        mesh = affine_map(mesh, A=mesh_rotation, b=mesh_offset)

        from meshmode.discretization.poly_element import \
                QuadratureSimplexGroupFactory
        discr = DGDiscretizationWithBoundaries(actx, mesh, order=builder.order,
                quad_tag_to_group_factory={
                    "product": QuadratureSimplexGroupFactory(2 * builder.order)
                    })

        volume = discr.discr_from_dd(sym.DD_VOLUME)
        logger.info("ndofs:     %d", volume.ndofs)
        logger.info("nelements: %d", volume.mesh.nelements)

        dd = sym.DD_VOLUME
        dq = dd.with_qtag("product")
        df = sym.as_dofdesc(sym.FACE_RESTR_ALL)
        ambient_dim = discr.ambient_dim
        dim = discr.dim

        # variables
        sym_f = f(sym.nodes(ambient_dim, dd=dd))
        sym_f_quad = f(sym.nodes(ambient_dim, dd=dq))
        sym_kappa = sym.summed_curvature(ambient_dim, dim=dim, dd=dq)
        sym_normal = sym.surface_normal(ambient_dim, dim=dim, dd=dq).as_vector()

        sym_face_normal = sym.normal(df, ambient_dim, dim=dim - 1)
        sym_face_f = sym.project(dd, df)(sym_f)

        # operators
        sym_stiff = sum(
                sym.StiffnessOperator(d)(f) for d, f in enumerate(sym_f)
                )
        sym_stiff_t = sum(
                sym.StiffnessTOperator(d)(f) for d, f in enumerate(sym_f)
                )
        sym_k = sym.MassOperator(dq, dd)(sym_kappa * sym_f_quad.dot(sym_normal))
        sym_flux = sym.FaceMassOperator()(sym_face_f.dot(sym_face_normal))

        # sum everything up
        sym_op_global = sym.NodalSum(dd)(
                sym_stiff - (sym_stiff_t + sym_k))
        sym_op_local = sym.ElementwiseSumOperator(dd)(
                sym_stiff - (sym_stiff_t + sym_k + sym_flux))

        # evaluate
        op_global = bind(discr, sym_op_global)(actx)
        op_local = bind(discr, sym_op_local)(actx)

        err_global = abs(op_global)
        err_local = bind(discr, sym.norm(np.inf, sym.var("x")))(actx, x=op_local)
        logger.info("errors: global %.5e local %.5e", err_global, err_local)

        # compute max element size
        h_max = bind(discr, sym.h_max_from_volume(
            discr.ambient_dim, dim=discr.dim, dd=dd))(actx)
        eoc_global.add_data_point(h_max, err_global)
        eoc_local.add_data_point(h_max, err_local)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(discr, vis_order=builder.order)

            filename = f"surface_divergence_theorem_{mesh_name}_{i:04d}.vtu"
            vis.write_vtk_file(filename, [
                ("r", actx.np.log10(op_local))
                ], overwrite=True)

    # }}}

    order = min(builder.order, builder.mesh_order) - 0.5
    logger.info("\n%s", str(eoc_global))
    logger.info("\n%s", str(eoc_local))

    assert eoc_global.max_error() < 1.0e-12 \
            or eoc_global.order_estimate() > order - 0.5

    assert eoc_local.max_error() < 1.0e-12 \
            or eoc_local.order_estimate() > order - 0.5
Ejemplo n.º 11
0
def test_face_normal_surface(actx_factory, mesh_name):
    """Check that face normals are orthogonal to the surface normal"""
    actx = actx_factory()

    # {{{ geometry

    if mesh_name == "2-1-ellipse":
        from mesh_data import EllipseMeshBuilder
        builder = EllipseMeshBuilder(radius=3.1, aspect_ratio=2.0)
    elif mesh_name == "spheroid":
        from mesh_data import SpheroidMeshBuilder
        builder = SpheroidMeshBuilder()
    else:
        raise ValueError("unknown mesh name: %s" % mesh_name)

    mesh = builder.get_mesh(builder.resolutions[0], builder.mesh_order)
    discr = DGDiscretizationWithBoundaries(actx, mesh, order=builder.order)

    volume_discr = discr.discr_from_dd(sym.DD_VOLUME)
    logger.info("ndofs:    %d", volume_discr.ndofs)
    logger.info("nelements: %d", volume_discr.mesh.nelements)

    # }}}

    # {{{ symbolic

    dv = sym.DD_VOLUME
    df = sym.as_dofdesc(sym.FACE_RESTR_INTERIOR)

    ambient_dim = mesh.ambient_dim
    dim = mesh.dim

    sym_surf_normal = sym.project(dv, df)(
            sym.surface_normal(ambient_dim, dim=dim, dd=dv).as_vector()
            )
    sym_surf_normal = sym_surf_normal / sym.sqrt(sum(sym_surf_normal**2))

    sym_face_normal_i = sym.normal(df, ambient_dim, dim=dim - 1)
    sym_face_normal_e = sym.OppositeInteriorFaceSwap(df)(sym_face_normal_i)

    if mesh.ambient_dim == 3:
        # NOTE: there's only one face tangent in 3d
        sym_face_tangent = (
                sym.pseudoscalar(ambient_dim, dim - 1, dd=df)
                / sym.area_element(ambient_dim, dim - 1, dd=df)).as_vector()

    # }}}

    # {{{ checks

    def _eval_error(x):
        return bind(discr, sym.norm(np.inf, sym.var("x", dd=df), dd=df))(actx, x=x)

    rtol = 1.0e-14

    surf_normal = bind(discr, sym_surf_normal)(actx)

    face_normal_i = bind(discr, sym_face_normal_i)(actx)
    face_normal_e = bind(discr, sym_face_normal_e)(actx)

    # check interpolated surface normal is orthogonal to face normal
    error = _eval_error(surf_normal.dot(face_normal_i))
    logger.info("error[n_dot_i]:    %.5e", error)
    assert error < rtol

    # check angle between two neighboring elements
    error = _eval_error(face_normal_i.dot(face_normal_e) + 1.0)
    logger.info("error[i_dot_e]:    %.5e", error)
    assert error > rtol

    # check orthogonality with face tangent
    if ambient_dim == 3:
        face_tangent = bind(discr, sym_face_tangent)(actx)

        error = _eval_error(face_tangent.dot(face_normal_i))
        logger.info("error[t_dot_i]:  %.5e", error)
        assert error < 5 * rtol
Ejemplo n.º 12
0
    def connection_from_dds(self, from_dd, to_dd):
        from_dd = sym.as_dofdesc(from_dd)
        to_dd = sym.as_dofdesc(to_dd)

        to_qtag = to_dd.quadrature_tag

        if (not from_dd.is_volume()
                and from_dd.quadrature_tag == to_dd.quadrature_tag
                and to_dd.domain_tag is sym.FACE_RESTR_ALL):
            faces_conn = self.connection_from_dds(
                sym.DOFDesc("vol"), sym.DOFDesc(from_dd.domain_tag))

            from meshmode.discretization.connection import \
                    make_face_to_all_faces_embedding

            return make_face_to_all_faces_embedding(
                faces_conn, self.discr_from_dd(to_dd),
                self.discr_from_dd(from_dd))

        # {{{ simplify domain + qtag change into chained

        if (from_dd.domain_tag != to_dd.domain_tag
                and from_dd.quadrature_tag is sym.QTAG_NONE
                and to_dd.quadrature_tag is not sym.QTAG_NONE):

            from meshmode.discretization.connection import \
                    ChainedDiscretizationConnection
            intermediate_dd = sym.DOFDesc(to_dd.domain_tag)
            return ChainedDiscretizationConnection([
                # first change domain
                self.connection_from_dds(from_dd, intermediate_dd),

                # then go to quad grid
                self.connection_from_dds(intermediate_dd, to_dd)
            ])

        # }}}

        # {{{ generic to-quad

        if (from_dd.domain_tag == to_dd.domain_tag
                and from_dd.quadrature_tag is sym.QTAG_NONE
                and to_dd.quadrature_tag is not sym.QTAG_NONE):
            from meshmode.discretization.connection.same_mesh import \
                    make_same_mesh_connection

            return make_same_mesh_connection(self.discr_from_dd(to_dd),
                                             self.discr_from_dd(from_dd))

        # }}}

        if from_dd.quadrature_tag is not sym.QTAG_NONE:
            raise ValueError("cannot interpolate *from* a "
                             "(non-interpolatory) quadrature grid")

        assert to_qtag is sym.QTAG_NONE

        if from_dd.is_volume():
            if to_dd.domain_tag is sym.FACE_RESTR_ALL:
                return self._all_faces_volume_connection()
            if to_dd.domain_tag is sym.FACE_RESTR_INTERIOR:
                return self._interior_faces_connection()
            elif to_dd.is_boundary():
                assert from_dd.quadrature_tag is sym.QTAG_NONE
                return self._boundary_connection(to_dd.domain_tag)
            elif to_dd.is_volume():
                from meshmode.discretization.connection import \
                        make_same_mesh_connection
                to_discr = self._quad_volume_discr(to_dd.quadrature_tag)
                from_discr = self._volume_discr
                return make_same_mesh_connection(to_discr, from_discr)

            else:
                raise ValueError("cannot interpolate from volume to: " +
                                 str(to_dd))

        else:
            raise ValueError("cannot interpolate from: " + str(from_dd))