Example #1
0
    def face_mass(self, *args):
        if len(args) == 1:
            vec, = args
            dd = sym.DOFDesc("all_faces", sym.QTAG_NONE)
        elif len(args) == 2:
            dd, vec = args
        else:
            raise TypeError("invalid number of arguments")

        if isinstance(vec, np.ndarray):
            return obj_array_vectorize(lambda el: self.face_mass(dd, el), vec)

        return self._bound_face_mass(dd)(u=vec)
Example #2
0
    def sym_operator(self):
        u = sym.var("u")

        def flux(pair):
            return sym.project(pair.dd, face_dd)(self.flux(pair))

        face_dd = sym.DOFDesc(sym.FACE_RESTR_ALL, self.quad_tag)
        quad_dd = sym.DOFDesc(sym.DTAG_VOLUME_ALL, self.quad_tag)

        to_quad = sym.project(sym.DD_VOLUME, quad_dd)
        stiff_t_op = sym.stiffness_t(self.ambient_dim,
                                     dd_in=quad_dd,
                                     dd_out=sym.DD_VOLUME)

        quad_v = to_quad(self.v)
        quad_u = to_quad(u)

        return sym.InverseMassOperator()(
            sum(stiff_t_op[n](quad_u * quad_v[n])
                for n in range(self.ambient_dim)) -
            sym.FaceMassOperator(face_dd, sym.DD_VOLUME)
            (flux(sym.int_tpair(u, self.quad_tag))))
Example #3
0
    def __init__(self, dd_in=None, dd_out=None, unique_id=None):
        sym = _sym()

        if dd_in is None:
            dd_in = sym.DOFDesc(sym.FACE_RESTR_INTERIOR, None)
        if dd_out is None:
            dd_out = dd_in

        super(OppositeInteriorFaceSwap, self).__init__(dd_in, dd_out)
        if self.dd_in.domain_tag is not sym.FACE_RESTR_INTERIOR:
            raise ValueError("dd_in must be an interior faces domain")
        if self.dd_out != self.dd_in:
            raise ValueError("dd_out and dd_in must be identical")

        assert unique_id is None or isinstance(unique_id, int)
        self.unique_id = unique_id
Example #4
0
    def weak_d_dx(self, *args):
        r"""Return the derivative along axis *xyz_axis* of the volume function
        represented by *vec*.

        May be called with ``(xyz_axis, vecs)`` or ``(dd, xyz_axis, vecs)``.

        :arg xyz_axis: an integer indicating the axis along which the derivative
            is taken
        :arg vec: a :class:`~meshmode.dof_array.DOFArray`
        :returns: a :class:`~meshmode.dof_array.DOFArray`\ s
        """
        if len(args) == 2:
            xyz_axis, vec = args
            dd = sym.DOFDesc("vol", sym.QTAG_NONE)
        elif len(args) == 3:
            dd, xyz_axis, vec = args
        else:
            raise TypeError("invalid number of arguments")

        return self._bound_weak_d_dx(dd, xyz_axis)(u=vec)
Example #5
0
    def weak_grad(self, *args):
        r"""Return the "weak gradient" of the volume function represented by
        *vec*.

        May be called with ``(vecs)`` or ``(dd, vecs)``.

        :arg dd: a :class:`~grudge.sym.DOFDesc`, or a value convertible to one.
            Defaults to the base volume discretization if not provided.
        :arg vec: a :class:`~meshmode.dof_array.DOFArray`
        :returns: an object array of :class:`~meshmode.dof_array.DOFArray`\ s
        """
        if len(args) == 1:
            vec, = args
            dd = sym.DOFDesc("vol", sym.QTAG_NONE)
        elif len(args) == 2:
            dd, vec = args
        else:
            raise TypeError("invalid number of arguments")

        return self._bound_weak_grad(dd)(u=vec)
Example #6
0
    def map_signed_face_ones(self, expr):
        assert expr.dd.is_trace()
        face_discr = self.discrwb.discr_from_dd(expr.dd)
        assert face_discr.dim == 0

        # NOTE: ignore quadrature_tags on expr.dd, since we only care about
        # the face_id here
        all_faces_conn = self.discrwb.connection_from_dds(
            sym.DD_VOLUME, sym.DOFDesc(expr.dd.domain_tag))

        field = face_discr.empty(self.array_context,
                                 dtype=self.discrwb.real_dtype)
        for grp_ary in field:
            grp_ary.fill(1)

        for igrp, grp in enumerate(all_faces_conn.groups):
            for batch in grp.batches:
                i = self.array_context.thaw(batch.to_element_indices)
                grp_field = field[igrp].reshape(-1)
                grp_field[i] = \
                        (2.0 * (batch.to_element_face % 2) - 1.0) * grp_field[i]

        return field
Example #7
0
    def weak_div(self, *args):
        r"""Return the "weak divergence" of the vector volume function
        represented by *vecs*.

        May be called with ``(vecs)`` or ``(dd, vecs)``.

        :arg dd: a :class:`~grudge.sym.DOFDesc`, or a value convertible to one.
            Defaults to the base volume discretization if not provided.
        :arg vec: a object array of
            a :class:`~meshmode.dof_array.DOFArray`\ s,
            where the last axis of the array must have length
            matching the volume dimension.
        :returns: a :class:`~meshmode.dof_array.DOFArray`
        """
        if len(args) == 1:
            vecs, = args
            dd = sym.DOFDesc("vol", sym.QTAG_NONE)
        elif len(args) == 2:
            dd, vecs = args
        else:
            raise TypeError("invalid number of arguments")

        return self._div_helper(
            lambda i, subvec: self.weak_d_dx(dd, i, subvec), vecs)
Example #8
0
def test_mass_mat_trig(ctx_factory, ambient_dim, quad_tag):
    """Check the integral of some trig functions on an interval using the mass
    matrix.
    """
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    nelements = 17
    order = 4

    a = -4.0 * np.pi
    b = +9.0 * np.pi
    true_integral = 13 * np.pi / 2 * (b - a)**(ambient_dim - 1)

    from meshmode.discretization.poly_element import QuadratureSimplexGroupFactory
    dd_quad = sym.DOFDesc(sym.DTAG_VOLUME_ALL, quad_tag)
    if quad_tag is sym.QTAG_NONE:
        quad_tag_to_group_factory = {}
    else:
        quad_tag_to_group_factory = {
            quad_tag: QuadratureSimplexGroupFactory(order=2 * order)
        }

    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(a=(a, ) * ambient_dim,
                                      b=(b, ) * ambient_dim,
                                      n=(nelements, ) * ambient_dim,
                                      order=1)
    discr = DGDiscretizationWithBoundaries(
        actx,
        mesh,
        order=order,
        quad_tag_to_group_factory=quad_tag_to_group_factory)

    def _get_variables_on(dd):
        sym_f = sym.var("f", dd=dd)
        sym_x = sym.nodes(ambient_dim, dd=dd)
        sym_ones = sym.Ones(dd)

        return sym_f, sym_x, sym_ones

    sym_f, sym_x, sym_ones = _get_variables_on(sym.DD_VOLUME)
    f_volm = actx.to_numpy(flatten(bind(discr, sym.cos(sym_x[0])**2)(actx)))
    ones_volm = actx.to_numpy(flatten(bind(discr, sym_ones)(actx)))

    sym_f, sym_x, sym_ones = _get_variables_on(dd_quad)
    f_quad = bind(discr, sym.cos(sym_x[0])**2)(actx)
    ones_quad = bind(discr, sym_ones)(actx)

    mass_op = bind(discr, sym.MassOperator(dd_quad, sym.DD_VOLUME)(sym_f))

    num_integral_1 = np.dot(ones_volm,
                            actx.to_numpy(flatten(mass_op(f=f_quad))))
    err_1 = abs(num_integral_1 - true_integral)
    assert err_1 < 1e-9, err_1

    num_integral_2 = np.dot(f_volm,
                            actx.to_numpy(flatten(mass_op(f=ones_quad))))
    err_2 = abs(num_integral_2 - true_integral)
    assert err_2 < 1.0e-9, err_2

    if quad_tag is sym.QTAG_NONE:
        # NOTE: `integral` always makes a square mass matrix and
        # `QuadratureSimplexGroupFactory` does not have a `mass_matrix` method.
        num_integral_3 = bind(discr, sym.integral(sym_f, dd=dd_quad))(f=f_quad)
        err_3 = abs(num_integral_3 - true_integral)
        assert err_3 < 5.0e-10, err_3
Example #9
0
def main(ctx_factory, dim=2, order=4, product_tag=None, visualize=False):
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # {{{ parameters

    # sphere radius
    radius = 1.0
    # sphere resolution
    resolution = 64 if dim == 2 else 1

    # cfl
    dt_factor = 2.0
    # final time
    final_time = np.pi

    # velocity field
    sym_x = sym.nodes(dim)
    c = make_obj_array([-sym_x[1], sym_x[0], 0.0])[:dim]
    # flux
    flux_type = "lf"

    # }}}

    # {{{ discretization

    if dim == 2:
        from meshmode.mesh.generation import make_curve_mesh, ellipse
        mesh = make_curve_mesh(lambda t: radius * ellipse(1.0, t),
                               np.linspace(0.0, 1.0, resolution + 1), order)
    elif dim == 3:
        from meshmode.mesh.generation import generate_icosphere
        mesh = generate_icosphere(radius,
                                  order=4 * order,
                                  uniform_refinement_rounds=resolution)
    else:
        raise ValueError("unsupported dimension")

    quad_tag_to_group_factory = {}
    if product_tag == "none":
        product_tag = None

    from meshmode.discretization.poly_element import \
            PolynomialWarpAndBlendGroupFactory, \
            QuadratureSimplexGroupFactory

    quad_tag_to_group_factory[sym.QTAG_NONE] = \
            PolynomialWarpAndBlendGroupFactory(order)

    if product_tag:
        quad_tag_to_group_factory[product_tag] = \
                QuadratureSimplexGroupFactory(order=4*order)

    from grudge import DGDiscretizationWithBoundaries
    discr = DGDiscretizationWithBoundaries(
        actx, mesh, quad_tag_to_group_factory=quad_tag_to_group_factory)

    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 operators

    def f_initial_condition(x):
        return x[0]

    from grudge.models.advection import SurfaceAdvectionOperator
    op = SurfaceAdvectionOperator(c, flux_type=flux_type, quad_tag=product_tag)

    bound_op = bind(discr, op.sym_operator())
    u0 = bind(discr, f_initial_condition(sym_x))(actx, t=0)

    def rhs(t, u):
        return bound_op(actx, t=t, u=u)

    # check velocity is tangential
    sym_normal = sym.surface_normal(dim, dim=dim - 1,
                                    dd=sym.DD_VOLUME).as_vector()
    error = bind(discr, sym.norm(2, c.dot(sym_normal)))(actx)
    logger.info("u_dot_n:   %.5e", error)

    # }}}

    # {{{ time stepping

    # compute time step
    h_min = bind(discr, sym.h_max_from_volume(discr.ambient_dim,
                                              dim=discr.dim))(actx)
    dt = dt_factor * h_min / order**2
    nsteps = int(final_time // dt) + 1
    dt = final_time / nsteps + 1.0e-15

    logger.info("dt:        %.5e", dt)
    logger.info("nsteps:    %d", nsteps)

    from grudge.shortcuts import set_up_rk4
    dt_stepper = set_up_rk4("u", dt, u0, rhs)
    plot = Plotter(actx, discr, order, visualize=visualize)

    norm = bind(discr, sym.norm(2, sym.var("u")))
    norm_u = norm(actx, u=u0)

    step = 0

    event = dt_stepper.StateComputed(0.0, 0, 0, u0)
    plot(event, "fld-surface-%04d" % 0)

    if visualize and dim == 3:
        from grudge.shortcuts import make_visualizer
        vis = make_visualizer(discr, vis_order=order)
        vis.write_vtk_file("fld-surface-velocity.vtu",
                           [("u", bind(discr, c)(actx)),
                            ("n", bind(discr, sym_normal)(actx))],
                           overwrite=True)

        df = sym.DOFDesc(sym.FACE_RESTR_INTERIOR)
        face_discr = discr.connection_from_dds(sym.DD_VOLUME, df).to_discr

        face_normal = bind(
            discr, sym.normal(df, face_discr.ambient_dim,
                              dim=face_discr.dim))(actx)

        from meshmode.discretization.visualization import make_visualizer
        vis = make_visualizer(actx, face_discr, vis_order=order)
        vis.write_vtk_file("fld-surface-face-normals.vtu",
                           [("n", face_normal)],
                           overwrite=True)

    for event in dt_stepper.run(t_end=final_time, max_steps=nsteps + 1):
        if not isinstance(event, dt_stepper.StateComputed):
            continue

        step += 1
        if step % 10 == 0:
            norm_u = norm(actx, u=event.state_component)
            plot(event, "fld-surface-%04d" % step)

        logger.info("[%04d] t = %.5f |u| = %.5e", step, event.t, norm_u)

    plot(event, "fld-surface-%04d" % step)
Example #10
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))