Пример #1
0
def test_inverse_modal_connections_quadgrid(actx_factory):
    actx = actx_factory()
    order = 5

    def f(x):
        return 1 + 2 * x + 3 * x**2

    # Make a regular rectangle mesh
    mesh = mgen.generate_regular_rect_mesh(
        a=(0, 0),
        b=(5, 3),
        npoints_per_axis=(10, 6),
        order=order,
        group_cls=QuadratureSimplexGroupFactory.mesh_group_class)

    dcoll = DiscretizationCollection(
        actx,
        mesh,
        discr_tag_to_group_factory={
            dof_desc.DISCR_TAG_BASE:
            PolynomialWarpAndBlend2DRestrictingGroupFactory(order),
            dof_desc.DISCR_TAG_QUAD:
            QuadratureSimplexGroupFactory(2 * order)
        })

    # Use dof descriptors on the quadrature grid
    dd_modal = dof_desc.DD_VOLUME_MODAL
    dd_quad = dof_desc.DOFDesc(dof_desc.DTAG_VOLUME_ALL,
                               dof_desc.DISCR_TAG_QUAD)

    x_quad = thaw(dcoll.discr_from_dd(dd_quad).nodes()[0], actx)
    quad_f = f(x_quad)

    # Map nodal coefficients of f to modal coefficients
    forward_conn = dcoll.connection_from_dds(dd_quad, dd_modal)
    modal_f = forward_conn(quad_f)
    # Now map the modal coefficients back to nodal
    backward_conn = dcoll.connection_from_dds(dd_modal, dd_quad)
    quad_f_2 = backward_conn(modal_f)

    # This error should be small since we composed a map with
    # its inverse
    err = flat_norm(quad_f - quad_f_2)

    assert err <= 1e-11
Пример #2
0
def test_inverse_modal_connections(actx_factory, nodal_group_factory):
    actx = actx_factory()
    order = 4

    def f(x):
        return 2 * actx.np.sin(20 * x) + 0.5 * actx.np.cos(10 * x)

    # Make a regular rectangle mesh
    mesh = mgen.generate_regular_rect_mesh(
        a=(0, 0),
        b=(5, 3),
        npoints_per_axis=(10, 6),
        order=order,
        group_cls=nodal_group_factory.mesh_group_class)

    dcoll = DiscretizationCollection(actx,
                                     mesh,
                                     discr_tag_to_group_factory={
                                         dof_desc.DISCR_TAG_BASE:
                                         nodal_group_factory(order)
                                     })

    dd_modal = dof_desc.DD_VOLUME_MODAL
    dd_volume = dof_desc.DD_VOLUME

    x_nodal = thaw(actx, dcoll.discr_from_dd(dd_volume).nodes()[0])
    nodal_f = f(x_nodal)

    # Map nodal coefficients of f to modal coefficients
    forward_conn = dcoll.connection_from_dds(dd_volume, dd_modal)
    modal_f = forward_conn(nodal_f)
    # Now map the modal coefficients back to nodal
    backward_conn = dcoll.connection_from_dds(dd_modal, dd_volume)
    nodal_f_2 = backward_conn(modal_f)

    # This error should be small since we composed a map with
    # its inverse
    err = actx.np.linalg.norm(nodal_f - nodal_f_2)

    assert err <= 1e-13
Пример #3
0
def _signed_face_ones(actx: ArrayContext, dcoll: DiscretizationCollection,
                      dd) -> DOFArray:

    assert dd.is_trace()

    # NOTE: ignore quadrature_tags on dd, since we only care about
    # the face_id here
    all_faces_conn = dcoll.connection_from_dds(DD_VOLUME,
                                               DOFDesc(dd.domain_tag))
    signed_face_ones = dcoll.discr_from_dd(dd).zeros(
        actx, dtype=dcoll.real_dtype) + 1
    for igrp, grp in enumerate(all_faces_conn.groups):
        for batch in grp.batches:
            i = actx.thaw(batch.to_element_indices)
            grp_field = signed_face_ones[igrp].reshape(-1)
            grp_field[i] = \
                (2.0 * (batch.to_element_face % 2) - 1.0) * grp_field[i]

    return signed_face_ones
Пример #4
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")

    discr_tag_to_group_factory = {}
    if product_tag == "none":
        product_tag = None
    else:
        product_tag = dof_desc.DISCR_TAG_QUAD

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

    discr_tag_to_group_factory[dof_desc.DISCR_TAG_BASE] = \
        PolynomialWarpAndBlendGroupFactory(order)

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

    from grudge import DiscretizationCollection
    discr = DiscretizationCollection(
        actx, mesh, discr_tag_to_group_factory=discr_tag_to_group_factory)

    volume_discr = discr.discr_from_dd(dof_desc.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=dof_desc.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.write_vtk_file("fld-surface-velocity.vtu",
                           [("u", bind(discr, c)(actx)),
                            ("n", bind(discr, sym_normal)(actx))],
                           overwrite=True)

        df = dof_desc.DOFDesc(FACE_RESTR_INTERIOR)
        face_discr = discr.connection_from_dds(dof_desc.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.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)
Пример #5
0
def forward_metric_nth_derivative(actx: ArrayContext,
                                  dcoll: DiscretizationCollection,
                                  xyz_axis,
                                  ref_axes,
                                  dd=None) -> DOFArray:
    r"""Pointwise metric derivatives representing repeated derivatives of the
    physical coordinate enumerated by *xyz_axis*: :math:`x_{\mathrm{xyz\_axis}}`
    with respect to the coordiantes on the reference element :math:`\xi_i`:

    .. math::

        D^\alpha x_{\mathrm{xyz\_axis}} =
        \frac{\partial^{|\alpha|} x_{\mathrm{xyz\_axis}} }{
            \partial \xi_1^{\alpha_1}\cdots \partial \xi_m^{\alpha_m}}

    where :math:`\alpha` is a multi-index described by *ref_axes*.

    :arg xyz_axis: an integer denoting which physical coordinate to
        differentiate.
    :arg ref_axes: a :class:`tuple` of tuples indicating indices of
        coordinate axes of the reference element to the number of derivatives
        which will be taken. For example, the value ``((0, 2), (1, 1))``
        indicates taking the second derivative with respect to the first
        axis and the first derivative with respect to the second
        axis. Each axis must occur only once and the tuple must be sorted
        by the axis index.
    :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
        Defaults to the base volume discretization.
    :returns: a :class:`~meshmode.dof_array.DOFArray` containing the pointwise
        metric derivative at each nodal coordinate.
    """
    if dd is None:
        dd = DD_VOLUME

    inner_dd = dd.with_discr_tag(DISCR_TAG_BASE)

    if isinstance(ref_axes, int):
        ref_axes = ((ref_axes, 1), )

    if not isinstance(ref_axes, tuple):
        raise ValueError("ref_axes must be a tuple")

    if tuple(sorted(ref_axes)) != ref_axes:
        raise ValueError("ref_axes must be sorted")

    if len(set(ref_axes)) != len(ref_axes):
        raise ValueError("ref_axes must not contain an axis more than once")

    from pytools import flatten
    flat_ref_axes = flatten([rst_axis] * n for rst_axis, n in ref_axes)

    from meshmode.discretization import num_reference_derivative

    vec = num_reference_derivative(
        dcoll.discr_from_dd(inner_dd), flat_ref_axes,
        thaw(dcoll.discr_from_dd(inner_dd).nodes(), actx)[xyz_axis])

    if dd.uses_quadrature():
        vec = dcoll.connection_from_dds(inner_dd, dd)(vec)

    return vec