Пример #1
0
def test_mass_operator_inverse(actx_factory, name):
    actx = actx_factory()

    # {{{ cases

    import mesh_data
    if name == "2-1-ellipse":
        # curve
        builder = mesh_data.EllipseMeshBuilder(radius=3.1, aspect_ratio=2.0)
    elif name == "spheroid":
        # surface
        builder = mesh_data.SpheroidMeshBuilder()
    elif name.startswith("warped_rect"):
        builder = mesh_data.WarpedRectMeshBuilder(dim=int(name[-1]))

    else:
        raise ValueError("unknown geometry name: %s" % name)

    # }}}

    # {{{ inv(m) @ m == id

    from pytools.convergence import EOCRecorder
    eoc = EOCRecorder()

    for resolution in builder.resolutions:
        mesh = builder.get_mesh(resolution, builder.mesh_order)
        dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
        volume_discr = dcoll.discr_from_dd(dof_desc.DD_VOLUME)

        logger.info("ndofs:     %d", volume_discr.ndofs)
        logger.info("nelements: %d", volume_discr.mesh.nelements)

        # {{{ compute inverse mass

        def f(x):
            return actx.np.cos(4.0 * x[0])

        dd = dof_desc.DD_VOLUME
        x_volm = thaw(volume_discr.nodes(), actx)
        f_volm = f(x_volm)
        f_inv = op.inverse_mass(dcoll, op.mass(dcoll, dd, f_volm))

        inv_error = actx.to_numpy(
            op.norm(dcoll, f_volm - f_inv, 2) / op.norm(dcoll, f_volm, 2))

        # }}}

        # compute max element size
        from grudge.dt_utils import h_max_from_volume

        h_max = h_max_from_volume(dcoll)

        eoc.add_data_point(h_max, inv_error)

    logger.info("inverse mass error\n%s", str(eoc))

    # NOTE: both cases give 1.0e-16-ish at the moment, but just to be on the
    # safe side, choose a slightly larger tolerance
    assert eoc.max_error() < 1.0e-14
Пример #2
0
def main(write_output=True):
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(
        queue,
        allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)),
        force_device_scalars=True,
    )

    from meshmode.mesh import BTAG_ALL
    from meshmode.mesh.generation import generate_warped_rect_mesh
    mesh = generate_warped_rect_mesh(dim=2, order=4, nelements_side=6)

    dcoll = DiscretizationCollection(actx, mesh, order=4)

    nodes = thaw(dcoll.nodes(), actx)
    bdry_nodes = thaw(dcoll.nodes(dd=BTAG_ALL), actx)
    bdry_normals = thaw(dcoll.normal(dd=BTAG_ALL), actx)

    if write_output:
        vis = shortcuts.make_visualizer(dcoll)
        vis.write_vtk_file("geo.vtu", [("nodes", nodes)])

        bvis = shortcuts.make_boundary_visualizer(dcoll)
        bvis.write_vtk_file("bgeo.vtu", [("bdry normals", bdry_normals),
                                         ("bdry nodes", bdry_nodes)])
Пример #3
0
def test_bessel(actx_factory):
    actx = actx_factory()

    dims = 2

    mesh = mgen.generate_regular_rect_mesh(a=(0.1, ) * dims,
                                           b=(1.0, ) * dims,
                                           nelements_per_axis=(8, ) * dims)

    dcoll = DiscretizationCollection(actx, mesh, order=3)

    nodes = thaw(dcoll.nodes(), actx)
    r = actx.np.sqrt(nodes[0]**2 + nodes[1]**2)

    # FIXME: Bessel functions need to brought out of the symbolic
    # layer. Related issue: https://github.com/inducer/grudge/issues/93
    def bessel_j(actx, n, r):
        from grudge import sym, bind
        return bind(dcoll, sym.bessel_j(n, sym.var("r")))(actx, r=r)

    # https://dlmf.nist.gov/10.6.1
    n = 3
    bessel_zero = (bessel_j(actx, n + 1, r) + bessel_j(actx, n - 1, r) -
                   2 * n / r * bessel_j(actx, n, r))

    z = op.norm(dcoll, bessel_zero, 2)

    assert z < 1e-15
Пример #4
0
def simple_mpi_communication_entrypoint():
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue, force_device_scalars=True)

    from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis
    from meshmode.mesh import BTAG_ALL

    from mpi4py import MPI
    comm = MPI.COMM_WORLD
    num_parts = comm.Get_size()

    mesh_dist = MPIMeshDistributor(comm)

    if mesh_dist.is_mananger_rank():
        from meshmode.mesh.generation import generate_regular_rect_mesh
        mesh = generate_regular_rect_mesh(a=(-1,)*2,
                                          b=(1,)*2,
                                          nelements_per_axis=(2,)*2)

        part_per_element = get_partition_by_pymetis(mesh, num_parts)

        local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element, num_parts)
    else:
        local_mesh = mesh_dist.receive_mesh_part()

    dcoll = DiscretizationCollection(actx, local_mesh, order=5,
            mpi_communicator=comm)

    x = thaw(dcoll.nodes(), actx)
    myfunc = actx.np.sin(np.dot(x, [2, 3]))

    from grudge.dof_desc import as_dofdesc

    dd_int = as_dofdesc("int_faces")
    dd_vol = as_dofdesc("vol")
    dd_af = as_dofdesc("all_faces")

    all_faces_func = op.project(dcoll, dd_vol, dd_af, myfunc)
    int_faces_func = op.project(dcoll, dd_vol, dd_int, myfunc)
    bdry_faces_func = op.project(dcoll, BTAG_ALL, dd_af,
                                 op.project(dcoll, dd_vol, BTAG_ALL, myfunc))

    hopefully_zero = (
        op.project(
            dcoll, "int_faces", "all_faces",
            dcoll.opposite_face_connection()(int_faces_func)
        )
        + sum(op.project(dcoll, tpair.dd, "all_faces", tpair.int)
              for tpair in op.cross_rank_trace_pairs(dcoll, myfunc))
    ) - (all_faces_func - bdry_faces_func)

    error = actx.to_numpy(flat_norm(hopefully_zero, ord=np.inf))

    print(__file__)
    with np.printoptions(threshold=100000000, suppress=True):
        logger.debug(hopefully_zero)
    logger.info("error: %.5e", error)

    assert error < 1e-14
Пример #5
0
def test_surface_mass_operator_inverse(actx_factory, name):
    actx = actx_factory()

    # {{{ cases

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

    # }}}

    # {{{ convergence

    from pytools.convergence import EOCRecorder
    eoc = EOCRecorder()

    for resolution in builder.resolutions:
        mesh = builder.get_mesh(resolution, builder.mesh_order)
        discr = DiscretizationCollection(actx, mesh, order=builder.order)
        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)

        # {{{ compute inverse mass

        dd = dof_desc.DD_VOLUME
        sym_f = sym.cos(4.0 * sym.nodes(mesh.ambient_dim, dd)[0])
        sym_op = sym.InverseMassOperator(dd, dd)(sym.MassOperator(dd, dd)(
            sym.var("f")))

        f = bind(discr, sym_f)(actx)
        f_inv = bind(discr, sym_op)(actx, f=f)

        inv_error = bind(
            discr,
            sym.norm(2,
                     sym.var("x") - sym.var("y")) / sym.norm(2, sym.var("y")))(
                         actx, x=f_inv, y=f)

        # }}}

        h_max = bind(
            discr,
            sym.h_max_from_volume(discr.ambient_dim, dim=discr.dim,
                                  dd=dd))(actx)
        eoc.add_data_point(h_max, inv_error)

    # }}}

    logger.info("inverse mass error\n%s", str(eoc))

    # NOTE: both cases give 1.0e-16-ish at the moment, but just to be on the
    # safe side, choose a slightly larger tolerance
    assert eoc.max_error() < 1.0e-14
Пример #6
0
    def conv_test(descr, use_quad):
        logger.info("-" * 75)
        logger.info(descr)
        logger.info("-" * 75)
        eoc_rec = EOCRecorder()

        if use_quad:
            qtag = dof_desc.DISCR_TAG_QUAD
        else:
            qtag = None

        ns = [20, 25]
        for n in ns:
            mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dims,
                                                   b=(0.5, ) * dims,
                                                   nelements_per_axis=(n, ) *
                                                   dims,
                                                   order=order)

            if use_quad:
                discr_tag_to_group_factory = {
                    qtag: QuadratureSimplexGroupFactory(order=4 * order)
                }
            else:
                discr_tag_to_group_factory = {}

            dcoll = DiscretizationCollection(
                actx,
                mesh,
                order=order,
                discr_tag_to_group_factory=discr_tag_to_group_factory)

            nodes = thaw(dcoll.nodes(), actx)

            def zero_inflow(dtag, t=0):
                dd = dof_desc.DOFDesc(dtag, qtag)
                return dcoll.discr_from_dd(dd).zeros(actx)

            adv_op = VariableCoefficientAdvectionOperator(
                dcoll,
                flat_obj_array(-1 * nodes[1], nodes[0]),
                inflow_u=lambda t: zero_inflow(BTAG_ALL, t=t),
                flux_type="upwind",
                quad_tag=qtag)

            total_error = op.norm(dcoll,
                                  adv_op.operator(0, gaussian_mode(nodes)), 2)
            eoc_rec.add_data_point(1.0 / n, actx.to_numpy(total_error))

        logger.info(
            "\n%s",
            eoc_rec.pretty_print(abscissa_label="h", error_label="L2 Error"))

        return eoc_rec.order_estimate(), np.array(
            [x[1] for x in eoc_rec.history])
Пример #7
0
def test_nodal_reductions(actx_factory):
    actx = actx_factory()

    from mesh_data import BoxMeshBuilder
    builder = BoxMeshBuilder(ambient_dim=1)

    mesh = builder.get_mesh(4, builder.mesh_order)
    dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
    x = thaw(dcoll.nodes(), actx)

    def f(x):
        return -actx.np.sin(10 * x[0])

    def g(x):
        return actx.np.cos(2 * x[0])

    def h(x):
        return -actx.np.tan(5 * x[0])

    fields = make_obj_array([f(x), g(x), h(x)])

    f_ref = actx.to_numpy(flatten(fields[0]))
    g_ref = actx.to_numpy(flatten(fields[1]))
    h_ref = actx.to_numpy(flatten(fields[2]))
    concat_fields = np.concatenate([f_ref, g_ref, h_ref])

    for inner_grudge_op, np_op in [(op.nodal_sum, np.sum),
                                   (op.nodal_max, np.max),
                                   (op.nodal_min, np.min)]:

        # FIXME: Remove this once all grudge reductions return device scalars
        def grudge_op(dcoll, dd, vec):
            res = inner_grudge_op(dcoll, dd, vec)

            from numbers import Number
            if not isinstance(res, Number):
                return actx.to_numpy(res)
            else:
                return res

        # Componentwise reduction checks
        assert np.isclose(grudge_op(dcoll, "vol", fields[0]),
                          np_op(f_ref),
                          rtol=1e-13)
        assert np.isclose(grudge_op(dcoll, "vol", fields[1]),
                          np_op(g_ref),
                          rtol=1e-13)
        assert np.isclose(grudge_op(dcoll, "vol", fields[2]),
                          np_op(h_ref),
                          rtol=1e-13)

        # Test nodal reductions work on object arrays
        assert np.isclose(grudge_op(dcoll, "vol", fields),
                          np_op(concat_fields),
                          rtol=1e-13)
Пример #8
0
def parametrization_derivative(actx: ArrayContext,
                               dcoll: DiscretizationCollection,
                               dd) -> MultiVector:
    r"""Computes the product of forward metric derivatives spanning the
    tangent space with topological dimension *dim*.

    :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
        Defaults to the base volume discretization.
    :returns: a :class:`pymbolic.geometric_algebra.MultiVector` containing
        the product of metric derivatives.
    """
    if dd is None:
        dd = DD_VOLUME

    dim = dcoll.discr_from_dd(dd).dim
    if dim == 0:
        from pymbolic.geometric_algebra import get_euclidean_space

        return MultiVector(_signed_face_ones(actx, dcoll, dd),
                           space=get_euclidean_space(dcoll.ambient_dim))

    from pytools import product

    return product(
        forward_metric_derivative_mv(actx, dcoll, rst_axis, dd)
        for rst_axis in range(dim))
Пример #9
0
def forward_metric_derivative_mat(actx: ArrayContext,
                                  dcoll: DiscretizationCollection,
                                  dd=None) -> np.ndarray:
    r"""Computes the forward metric derivative matrix, also commonly
    called the Jacobian matrix, with entries defined as the
    forward metric derivatives:

    .. math::

        J = \left\lbrack
            \frac{\partial x_i}{\partial \xi_j}
            \right\rbrack_{(0, 0) \leq (i, j) \leq (n, m)}

    where :math:`x_1, \dots, x_n` denote the physical coordinates and
    :math:`\xi_1, \dots, \xi_m` denote coordinates on the reference element.
    Note that, in the case of immersed manifolds, `J` is not necessarily
    a square matrix.

    :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one.
        Defaults to the base volume discretization.
    :returns: a matrix containing the evaluated forward metric derivatives
        of each physical coordinate, with respect to each reference coordinate.
    """
    ambient_dim = dcoll.ambient_dim

    if dd is None:
        dd = DD_VOLUME

    dim = dcoll.discr_from_dd(dd).dim

    result = np.zeros((ambient_dim, dim), dtype=object)
    for j in range(dim):
        result[:, j] = forward_metric_derivative_vector(actx, dcoll, j, dd=dd)

    return result
Пример #10
0
def test_inverse_metric(actx_factory, dim):
    actx = actx_factory()

    mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                           b=(0.5, ) * dim,
                                           nelements_per_axis=(6, ) * dim,
                                           order=4)

    def m(x):
        result = np.empty_like(x)
        result[0] = (1.5 * x[0] + np.cos(x[0]) + 0.1 * np.sin(10 * x[1]))
        result[1] = (0.05 * np.cos(10 * x[0]) + 1.3 * x[1] + np.sin(x[1]))
        if len(x) == 3:
            result[2] = x[2]
        return result

    from meshmode.mesh.processing import map_mesh
    mesh = map_mesh(mesh, m)

    dcoll = DiscretizationCollection(actx, mesh, order=4)

    from grudge.geometry import \
        forward_metric_derivative_mat, inverse_metric_derivative_mat

    mat = forward_metric_derivative_mat(actx, dcoll).dot(
        inverse_metric_derivative_mat(actx, dcoll))

    for i in range(mesh.dim):
        for j in range(mesh.dim):
            tgt = 1 if i == j else 0

            err = flat_norm(mat[i, j] - tgt, ord=np.inf)
            logger.info("error[%d, %d]: %.5e", i, j, err)
            assert err < 1.0e-12, (i, j, err)
Пример #11
0
def test_norm_obj_array(actx_factory, p):
    """Test :func:`grudge.op.norm` for object arrays."""

    actx = actx_factory()

    dim = 2
    mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                           b=(0.5, ) * dim,
                                           nelements_per_axis=(8, ) * dim,
                                           order=1)
    dcoll = DiscretizationCollection(actx, mesh, order=4)

    w = make_obj_array([1.0, 2.0, 3.0])[:dim]

    # {{ scalar

    norm = op.norm(dcoll, w[0], p)

    norm_exact = w[0]
    logger.info("norm: %.5e %.5e", norm, norm_exact)
    assert abs(norm - norm_exact) < 1.0e-14

    # }}}

    # {{{ vector

    norm = op.norm(dcoll, w, p)

    norm_exact = np.sqrt(np.sum(w**2)) if p == 2 else np.max(w)
    logger.info("norm: %.5e %.5e", norm, norm_exact)
    assert abs(norm - norm_exact) < 1.0e-14
Пример #12
0
def test_external_call(actx_factory):
    actx = actx_factory()

    def double(queue, x):
        return 2 * x

    dims = 2

    mesh = mgen.generate_regular_rect_mesh(a=(0, ) * dims,
                                           b=(1, ) * dims,
                                           nelements_per_axis=(4, ) * dims)
    discr = DiscretizationCollection(actx, mesh, order=1)

    ones = sym.Ones(dof_desc.DD_VOLUME)
    op = (ones * 3 + sym.FunctionSymbol("double")(ones))

    from grudge.function_registry import (base_function_registry,
                                          register_external_function)

    freg = register_external_function(base_function_registry,
                                      "double",
                                      implementation=double,
                                      dd=dof_desc.DD_VOLUME)

    bound_op = bind(discr, op, function_registry=freg)

    result = bound_op(actx, double=double)
    assert actx.to_numpy(flatten(result) == 5).all()
Пример #13
0
def test_non_geometric_factors(actx_factory, name):
    from grudge.dt_utils import dt_non_geometric_factors

    actx = actx_factory()

    # {{{ cases

    if name == "interval":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=1)
    elif name == "box2d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=2)
    elif name == "box3d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=3)
    else:
        raise ValueError("unknown geometry name: %s" % name)

    # }}}

    factors = []
    degrees = list(range(1, 8))
    for degree in degrees:
        mesh = builder.get_mesh(1, degree)
        dcoll = DiscretizationCollection(actx, mesh, order=degree)
        factors.append(min(dt_non_geometric_factors(dcoll)))

    # Crude estimate, factors should behave like 1/N**2
    factors = np.asarray(factors)
    lower_bounds = 1 / (np.asarray(degrees)**2)
    upper_bounds = 6.295 * lower_bounds

    assert all(lower_bounds <= factors)
    assert all(factors <= upper_bounds)
Пример #14
0
def main(write_output=True):
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    from meshmode.mesh import BTAG_ALL
    from meshmode.mesh.generation import generate_warped_rect_mesh
    mesh = generate_warped_rect_mesh(dim=2, order=4, nelements_side=6)

    discr = DiscretizationCollection(actx, mesh, order=4)

    sym_op = sym.normal(BTAG_ALL, mesh.dim)
    # sym_op = sym.nodes(mesh.dim, dd=BTAG_ALL)
    print(sym.pretty(sym_op))
    op = bind(discr, sym_op)
    print()
    print(op.eval_code)

    vec = op(actx)

    vis = shortcuts.make_visualizer(discr)
    vis.write_vtk_file("geo.vtu", [])

    bvis = shortcuts.make_boundary_visualizer(discr)
    bvis.write_vtk_file("bgeo.vtu", [("normals", vec)])
Пример #15
0
def test_trace_pair(actx_factory):
    """Simple smoke test for :class:`grudge.trace_pair.TracePair`."""
    actx = actx_factory()
    dim = 3
    order = 1
    n = 4

    mesh = mgen.generate_regular_rect_mesh(
        a=(-1,)*dim, b=(1,)*dim,
        nelements_per_axis=(n,)*dim)

    dcoll = DiscretizationCollection(actx, mesh, order=order)

    def rand():
        return DOFArray(
                actx,
                tuple(actx.from_numpy(
                    np.random.rand(grp.nelements, grp.nunit_dofs))
                    for grp in dcoll.discr_from_dd("vol").groups))

    interior = rand()
    exterior = rand()
    tpair = TracePair("vol", interior=interior, exterior=exterior)

    import grudge.op as op
    assert op.norm(dcoll, tpair.avg - 0.5*(exterior + interior), np.inf) == 0
    assert op.norm(dcoll, tpair.diff - (exterior - interior), np.inf) == 0
    assert op.norm(dcoll, tpair.int - interior, np.inf) == 0
    assert op.norm(dcoll, tpair.ext - exterior, np.inf) == 0
Пример #16
0
def test_geometric_factors_regular_refinement(actx_factory, name):
    from grudge.dt_utils import dt_geometric_factors

    actx = actx_factory()

    # {{{ cases

    if name == "interval":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=1)
    elif name == "box2d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=2)
    elif name == "box3d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=3)
    else:
        raise ValueError("unknown geometry name: %s" % name)

    # }}}

    min_factors = []
    for resolution in builder.resolutions:
        mesh = builder.get_mesh(resolution, builder.mesh_order)
        dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
        min_factors.append(
            actx.to_numpy(
                op.nodal_min(dcoll, "vol",
                             thaw(dt_geometric_factors(dcoll), actx))))

    # Resolution is doubled each refinement, so the ratio of consecutive
    # geometric factors should satisfy: gfi+1 / gfi = 2
    min_factors = np.asarray(min_factors)
    ratios = min_factors[:-1] / min_factors[1:]
    assert np.all(np.isclose(ratios, 2))
def simple_mpi_communication_entrypoint():
    cl_ctx = cl.create_some_context()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    from meshmode.distributed import MPIMeshDistributor, get_partition_by_pymetis
    from meshmode.mesh import BTAG_ALL

    from mpi4py import MPI
    comm = MPI.COMM_WORLD
    num_parts = comm.Get_size()

    mesh_dist = MPIMeshDistributor(comm)

    if mesh_dist.is_mananger_rank():
        from meshmode.mesh.generation import generate_regular_rect_mesh
        mesh = generate_regular_rect_mesh(a=(-1, ) * 2,
                                          b=(1, ) * 2,
                                          nelements_per_axis=(2, ) * 2)

        part_per_element = get_partition_by_pymetis(mesh, num_parts)

        local_mesh = mesh_dist.send_mesh_parts(mesh, part_per_element,
                                               num_parts)
    else:
        local_mesh = mesh_dist.receive_mesh_part()

    vol_discr = DiscretizationCollection(actx,
                                         local_mesh,
                                         order=5,
                                         mpi_communicator=comm)

    sym_x = sym.nodes(local_mesh.dim)
    myfunc_symb = sym.sin(np.dot(sym_x, [2, 3]))
    myfunc = bind(vol_discr, myfunc_symb)(actx)

    sym_all_faces_func = sym.cse(
        sym.project("vol", "all_faces")(sym.var("myfunc")))
    sym_int_faces_func = sym.cse(
        sym.project("vol", "int_faces")(sym.var("myfunc")))
    sym_bdry_faces_func = sym.cse(
        sym.project(BTAG_ALL,
                    "all_faces")(sym.project("vol",
                                             BTAG_ALL)(sym.var("myfunc"))))

    bound_face_swap = bind(
        vol_discr,
        sym.project("int_faces", "all_faces")(
            sym.OppositeInteriorFaceSwap("int_faces")(sym_int_faces_func)) -
        (sym_all_faces_func - sym_bdry_faces_func))

    hopefully_zero = bound_face_swap(myfunc=myfunc)
    error = actx.np.linalg.norm(hopefully_zero, ord=np.inf)

    print(__file__)
    with np.printoptions(threshold=100000000, suppress=True):
        logger.debug(hopefully_zero)
    logger.info("error: %.5e", error)

    assert error < 1e-14
Пример #18
0
def test_operator_compiler_overwrite(actx_factory):
    """Tests that the same expression in ``eval_code`` and ``discr_code``
    does not confuse the OperatorCompiler in grudge/symbolic/compiler.py.
    """

    actx = actx_factory()

    ambient_dim = 2
    target_order = 4

    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim,
                                      b=(0.5, ) * ambient_dim,
                                      n=(8, ) * ambient_dim,
                                      order=1)
    discr = DiscretizationCollection(actx, mesh, order=target_order)

    # {{{ test

    sym_u = sym.nodes(ambient_dim)
    sym_div_u = sum(d(u) for d, u in zip(sym.nabla(ambient_dim), sym_u))

    div_u = bind(discr, sym_div_u)(actx)
    error = bind(discr, sym.norm(2, sym.var("x")))(actx, x=div_u - discr.dim)
    logger.info("error: %.5e", error)
Пример #19
0
def test_inverse_metric(actx_factory, dim):
    actx = actx_factory()

    mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                           b=(0.5, ) * dim,
                                           nelements_per_axis=(6, ) * dim,
                                           order=4)

    def m(x):
        result = np.empty_like(x)
        result[0] = (1.5 * x[0] + np.cos(x[0]) + 0.1 * np.sin(10 * x[1]))
        result[1] = (0.05 * np.cos(10 * x[0]) + 1.3 * x[1] + np.sin(x[1]))
        if len(x) == 3:
            result[2] = x[2]
        return result

    from meshmode.mesh.processing import map_mesh
    mesh = map_mesh(mesh, m)

    discr = DiscretizationCollection(actx, mesh, order=4)

    sym_op = (sym.forward_metric_derivative_mat(mesh.dim).dot(
        sym.inverse_metric_derivative_mat(mesh.dim)).reshape(-1))

    op = bind(discr, sym_op)
    mat = op(actx).reshape(mesh.dim, mesh.dim)

    for i in range(mesh.dim):
        for j in range(mesh.dim):
            tgt = 1 if i == j else 0

            err = actx.np.linalg.norm(mat[i, j] - tgt, ord=np.inf)
            logger.info("error[%d, %d]: %.5e", i, j, err)
            assert err < 1.0e-12, (i, j, err)
Пример #20
0
def test_norm_obj_array(actx_factory, p):
    """Test :func:`grudge.symbolic.operators.norm` for object arrays."""

    actx = actx_factory()

    dim = 2
    mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                           b=(0.5, ) * dim,
                                           nelements_per_axis=(8, ) * dim,
                                           order=1)
    discr = DiscretizationCollection(actx, mesh, order=4)

    w = make_obj_array([1.0, 2.0, 3.0])[:dim]

    # {{ scalar

    sym_w = sym.var("w")
    norm = bind(discr, sym.norm(p, sym_w))(actx, w=w[0])

    norm_exact = w[0]
    logger.info("norm: %.5e %.5e", norm, norm_exact)
    assert abs(norm - norm_exact) < 1.0e-14

    # }}}

    # {{{ vector

    sym_w = sym.make_sym_array("w", dim)
    norm = bind(discr, sym.norm(p, sym_w))(actx, w=w)

    norm_exact = np.sqrt(np.sum(w**2)) if p == 2 else np.max(w)
    logger.info("norm: %.5e %.5e", norm, norm_exact)
    assert abs(norm - norm_exact) < 1.0e-14
Пример #21
0
def test_incorrect_assignment_aggregation(actx_factory, ambient_dim):
    """Tests that the greedy assignemnt aggregation code works on a non-trivial
    expression (on which it didn't work at the time of writing).
    """

    actx = actx_factory()

    target_order = 4

    from meshmode.mesh.generation import generate_regular_rect_mesh
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim,
                                      b=(0.5, ) * ambient_dim,
                                      n=(8, ) * ambient_dim,
                                      order=1)
    discr = DiscretizationCollection(actx, mesh, order=target_order)

    # {{{ test with a relative norm

    from grudge.dof_desc import DD_VOLUME
    dd = DD_VOLUME
    sym_x = sym.make_sym_array("y", ambient_dim, dd=dd)
    sym_y = sym.make_sym_array("y", ambient_dim, dd=dd)

    sym_norm_y = sym.norm(2, sym_y, dd=dd)
    sym_norm_d = sym.norm(2, sym_x - sym_y, dd=dd)
    sym_op = sym_norm_d / sym_norm_y
    logger.info("%s", sym.pretty(sym_op))

    # FIXME: this shouldn't raise a RuntimeError
    with pytest.raises(RuntimeError):
        bind(discr, sym_op)(actx, x=1.0, y=discr.discr_from_dd(dd).nodes())

    # }}}

    # {{{ test with repeated mass inverses

    sym_minv_y = sym.cse(sym.InverseMassOperator()(sym_y), "minv_y")

    sym_u = make_obj_array([0.5 * sym.Ones(dd), 0.0, 0.0])[:ambient_dim]
    sym_div_u = sum(d(u) for d, u in zip(sym.nabla(ambient_dim), sym_u))

    sym_op = sym.MassOperator(dd)(sym_u) \
            + sym.MassOperator(dd)(sym_minv_y * sym_div_u)
    logger.info("%s", sym.pretty(sym_op))

    # FIXME: this shouldn't raise a RuntimeError either
    bind(discr, sym_op)(actx, y=discr.discr_from_dd(dd).nodes())
Пример #22
0
def test_nodal_reductions_with_container(actx_factory):
    actx = actx_factory()

    from mesh_data import BoxMeshBuilder
    builder = BoxMeshBuilder(ambient_dim=2)

    mesh = builder.get_mesh(4, builder.mesh_order)
    dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
    x = thaw(dcoll.nodes(), actx)

    def f(x):
        return -actx.np.sin(10 * x[0]) * actx.np.cos(2 * x[1])

    def g(x):
        return actx.np.cos(2 * x[0]) * actx.np.sin(10 * x[1])

    def h(x):
        return -actx.np.tan(5 * x[0]) * actx.np.tan(0.5 * x[1])

    mass = f(x) + g(x)
    momentum = make_obj_array([f(x) / g(x), h(x)])
    enthalpy = h(x) - g(x)

    ary_container = MyContainer(name="container",
                                mass=mass,
                                momentum=momentum,
                                enthalpy=enthalpy)

    mass_ref = actx.to_numpy(flatten(mass))
    momentum_ref = np.concatenate(
        [actx.to_numpy(mom_i) for mom_i in flatten(momentum)])
    enthalpy_ref = actx.to_numpy(flatten(enthalpy))
    concat_fields = np.concatenate([mass_ref, momentum_ref, enthalpy_ref])

    for grudge_op, np_op in [(op.nodal_sum, np.sum), (op.nodal_max, np.max),
                             (op.nodal_min, np.min)]:

        assert np.isclose(actx.to_numpy(grudge_op(dcoll, "vol",
                                                  ary_container)),
                          np_op(concat_fields),
                          rtol=1e-13)

    # Check norm reduction
    assert np.isclose(actx.to_numpy(op.norm(dcoll, ary_container, np.inf)),
                      np.linalg.norm(concat_fields, ord=np.inf),
                      rtol=1e-13)
Пример #23
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
Пример #24
0
def test_empty_boundary(actx_factory):
    # https://github.com/inducer/grudge/issues/54

    from meshmode.mesh import BTAG_NONE

    actx = actx_factory()

    dim = 2
    mesh = mgen.generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                           b=(0.5, ) * dim,
                                           nelements_per_axis=(8, ) * dim,
                                           order=4)
    discr = DiscretizationCollection(actx, mesh, order=4)
    normal = bind(discr, sym.normal(BTAG_NONE, dim, dim=dim - 1))(actx)
    from meshmode.dof_array import DOFArray
    for component in normal:
        assert isinstance(component, DOFArray)
        assert len(component) == len(discr.discr_from_dd(BTAG_NONE).groups)
Пример #25
0
def test_elementwise_reductions(actx_factory):
    actx = actx_factory()

    from mesh_data import BoxMeshBuilder
    builder = BoxMeshBuilder(ambient_dim=1)

    nelements = 4
    mesh = builder.get_mesh(nelements, builder.mesh_order)
    dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
    x = thaw(dcoll.nodes(), actx)

    def f(x):
        return actx.np.sin(x[0])

    field = f(x)
    mins = []
    maxs = []
    sums = []
    for gidx, grp_f in enumerate(field):
        min_res = np.empty(grp_f.shape)
        max_res = np.empty(grp_f.shape)
        sum_res = np.empty(grp_f.shape)
        for eidx in range(dcoll._volume_discr.groups[gidx].nelements):
            element_data = actx.to_numpy(grp_f[eidx])
            min_res[eidx, :] = np.min(element_data)
            max_res[eidx, :] = np.max(element_data)
            sum_res[eidx, :] = np.sum(element_data)
        mins.append(actx.from_numpy(min_res))
        maxs.append(actx.from_numpy(max_res))
        sums.append(actx.from_numpy(sum_res))

    from meshmode.dof_array import DOFArray, flat_norm

    ref_mins = DOFArray(actx, data=tuple(mins))
    ref_maxs = DOFArray(actx, data=tuple(maxs))
    ref_sums = DOFArray(actx, data=tuple(sums))

    elem_mins = op.elementwise_min(dcoll, field)
    elem_maxs = op.elementwise_max(dcoll, field)
    elem_sums = op.elementwise_sum(dcoll, field)

    assert flat_norm(elem_mins - ref_mins, ord=np.inf) < 1.e-15
    assert flat_norm(elem_maxs - ref_maxs, ord=np.inf) < 1.e-15
    assert flat_norm(elem_sums - ref_sums, ord=np.inf) < 1.e-15
Пример #26
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
Пример #27
0
def test_norm_complex(actx_factory, p):
    actx = actx_factory()

    dim = 2
    mesh = mgen.generate_regular_rect_mesh(a=(0, ) * dim,
                                           b=(1, ) * dim,
                                           nelements_per_axis=(8, ) * dim,
                                           order=1)
    dcoll = DiscretizationCollection(actx, mesh, order=4)
    nodes = thaw(dcoll.nodes(), actx)

    norm = op.norm(dcoll, (1 + 1j) * nodes[0], p)
    if p == 2:
        ref_norm = (2 / 3)**0.5
    elif p == np.inf:
        ref_norm = 2**0.5

    logger.info("norm: %.5e %.5e", norm, ref_norm)
    assert abs(norm - ref_norm) / abs(ref_norm) < 1e-13
Пример #28
0
def mv_normal(
    actx: ArrayContext,
    dcoll: DiscretizationCollection,
    dd,
) -> MultiVector:
    """Exterior unit normal as a :class:`~pymbolic.geometric_algebra.MultiVector`.
    This supports both volume discretizations
    (where ambient == topological dimension) and surface discretizations
    (where ambient == topological dimension + 1). In the latter case, extra
    processing ensures that the returned normal is in the local tangent space
    of the element at the point where the normal is being evaluated.

    :arg dd: a :class:`~grudge.dof_desc.DOFDesc` as the surface discretization.
    :returns: a :class:`~pymbolic.geometric_algebra.MultiVector`
        containing the unit normals.
    """
    import grudge.dof_desc as dof_desc

    dd = dof_desc.as_dofdesc(dd)

    dim = dcoll.discr_from_dd(dd).dim
    ambient_dim = dcoll.ambient_dim

    if dim == ambient_dim:
        raise ValueError(
            "may only request normals on domains whose topological "
            f"dimension ({dim}) differs from "
            f"their ambient dimension ({ambient_dim})")

    if dim == ambient_dim - 1:
        return rel_mv_normal(actx, dcoll, dd=dd)

    # NOTE: In the case of (d - 2)-dimensional curves, we don't really have
    # enough information on the face to decide what an "exterior face normal"
    # is (e.g the "normal" to a 1D curve in 3D space is actually a
    # "normal plane")
    #
    # The trick done here is that we take the surface normal, move it to the
    # face and then take a cross product with the face tangent to get the
    # correct exterior face normal vector.
    assert dim == ambient_dim - 2

    from grudge.op import project
    import grudge.dof_desc as dof_desc

    volm_normal = MultiVector(
        project(
            dcoll, dof_desc.DD_VOLUME, dd,
            rel_mv_normal(actx, dcoll,
                          dd=dof_desc.DD_VOLUME).as_vector(dtype=object)))
    pder = pseudoscalar(actx, dcoll, dd=dd)

    mv = -(volm_normal ^ pder) << volm_normal.I.inv()

    return mv / actx.np.sqrt(mv.norm_squared())
Пример #29
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
Пример #30
0
def test_2d_gauss_theorem(actx_factory):
    """Verify Gauss's theorem explicitly on a mesh"""

    pytest.importorskip("meshpy")

    from meshpy.geometry import make_circle, GeometryBuilder
    from meshpy.triangle import MeshInfo, build

    geob = GeometryBuilder()
    geob.add_geometry(*make_circle(1))
    mesh_info = MeshInfo()
    geob.set(mesh_info)

    mesh_info = build(mesh_info)

    from meshmode.mesh.io import from_meshpy
    from meshmode.mesh import BTAG_ALL

    mesh = from_meshpy(mesh_info, order=1)

    actx = actx_factory()

    dcoll = DiscretizationCollection(actx, mesh, order=2)
    volm_disc = dcoll.discr_from_dd(dof_desc.DD_VOLUME)
    x_volm = thaw(volm_disc.nodes(), actx)

    def f(x):
        return flat_obj_array(
            actx.np.sin(3 * x[0]) + actx.np.cos(3 * x[1]),
            actx.np.sin(2 * x[0]) + actx.np.cos(x[1]))

    f_volm = f(x_volm)
    int_1 = op.integral(dcoll, "vol", op.local_div(dcoll, f_volm))

    prj_f = op.project(dcoll, "vol", BTAG_ALL, f_volm)
    normal = thaw(dcoll.normal(BTAG_ALL), actx)
    int_2 = op.integral(dcoll, BTAG_ALL, prj_f.dot(normal))

    assert abs(int_1 - int_2) < 1e-13