Beispiel #1
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
Beispiel #2
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
Beispiel #3
0
def test_isentropic_vortex(actx_factory, order):
    """Advance the 2D isentropic vortex case in time with non-zero velocities
    using an RK4 timestepping scheme. Check the advanced field values against
    the exact/analytic expressions.

    This tests all parts of the Euler module working together, with results
    converging at the expected rates vs. the order.
    """
    actx = actx_factory()

    dim = 2

    from pytools.convergence import EOCRecorder

    eoc_rec = EOCRecorder()

    for nel_1d in [16, 32, 64]:
        from meshmode.mesh.generation import (
            generate_regular_rect_mesh, )

        mesh = generate_regular_rect_mesh(a=(-5.0, ) * dim,
                                          b=(5.0, ) * dim,
                                          nelements_per_axis=(nel_1d, ) * dim)

        exittol = 1.0
        t_final = 0.001
        cfl = 1.0
        vel = np.zeros(shape=(dim, ))
        orig = np.zeros(shape=(dim, ))
        vel[:dim] = 1.0
        dt = .0001
        initializer = Vortex2D(center=orig, velocity=vel)
        casename = "Vortex"
        boundaries = {BTAG_ALL: PrescribedBoundary(initializer)}
        eos = IdealSingleGas()
        t = 0
        flowparams = {
            "dim": dim,
            "dt": dt,
            "order": order,
            "time": t,
            "boundaries": boundaries,
            "initializer": initializer,
            "eos": eos,
            "casename": casename,
            "mesh": mesh,
            "tfinal": t_final,
            "exittol": exittol,
            "cfl": cfl,
            "constantcfl": False,
            "nstatus": 0
        }
        maxerr = _euler_flow_stepper(actx, flowparams)
        eoc_rec.add_data_point(1.0 / nel_1d, maxerr)

    logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-11)
Beispiel #4
0
def test_wave_accuracy(actx_factory, problem, order, visualize=False):
    """Checks accuracy of the wave operator for a given problem setup.
    """
    actx = actx_factory()

    p = problem

    sym_u, sym_v, sym_f, sym_rhs = sym_wave(p.dim, p.sym_phi)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for n in [8, 10, 12] if p.dim == 3 else [8, 12, 16]:
        mesh = p.mesh_factory(n)

        from grudge.eager import EagerDGDiscretization
        discr = EagerDGDiscretization(actx, mesh, order=order)

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

        def sym_eval(expr, t):
            return sym.EvaluationMapper({"c": p.c, "x": nodes, "t": t})(expr)

        t_check = 1.23456789

        u = sym_eval(sym_u, t_check)
        v = sym_eval(sym_v, t_check)

        fields = flat_obj_array(u, v)

        rhs = wave_operator(discr, c=p.c, w=fields)
        rhs[0] = rhs[0] + sym_eval(sym_f, t_check)

        expected_rhs = sym_eval(sym_rhs, t_check)

        rel_linf_err = actx.to_numpy(
            discr.norm(rhs - expected_rhs, np.inf) /
            discr.norm(expected_rhs, np.inf))
        eoc_rec.add_data_point(1. / n, rel_linf_err)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(discr, discr.order)
            vis.write_vtk_file(
                "wave_accuracy_{order}_{n}.vtu".format(order=order, n=n), [
                    ("u", fields[0]),
                    ("v", fields[1:]),
                    ("rhs_u_actual", rhs[0]),
                    ("rhs_v_actual", rhs[1:]),
                    ("rhs_u_expected", expected_rhs[0]),
                    ("rhs_v_expected", expected_rhs[1:]),
                ])

    print("Approximation error:")
    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-11)
Beispiel #5
0
def test_lump_rhs(actx_factory, dim, order):
    """Test the inviscid rhs using the non-trivial mass lump case.

    The case is tested against the analytic expressions of the RHS.
    Checks several different orders and refinement levels to check error behavior.
    """
    actx = actx_factory()

    tolerance = 1e-10
    maxxerr = 0.0

    from pytools.convergence import EOCRecorder

    eoc_rec = EOCRecorder()

    for nel_1d in [4, 8, 12]:
        from meshmode.mesh.generation import (
            generate_regular_rect_mesh, )

        mesh = generate_regular_rect_mesh(
            a=(-5, ) * dim,
            b=(5, ) * dim,
            nelements_per_axis=(nel_1d, ) * dim,
        )

        logger.info(f"Number of elements: {mesh.nelements}")

        discr = EagerDGDiscretization(actx, mesh, order=order)
        nodes = thaw(actx, discr.nodes())

        # Init soln with Lump and expected RHS = 0
        center = np.zeros(shape=(dim, ))
        velocity = np.zeros(shape=(dim, ))
        lump = Lump(dim=dim, center=center, velocity=velocity)
        lump_soln = lump(nodes)
        boundaries = {
            BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=lump)
        }
        inviscid_rhs = euler_operator(discr,
                                      eos=IdealSingleGas(),
                                      boundaries=boundaries,
                                      cv=lump_soln,
                                      time=0.0)
        expected_rhs = lump.exact_rhs(discr, cv=lump_soln, time=0)

        err_max = discr.norm((inviscid_rhs - expected_rhs).join(), np.inf)
        if err_max > maxxerr:
            maxxerr = err_max

        eoc_rec.add_data_point(1.0 / nel_1d, err_max)
    logger.info(f"Max error: {maxxerr}")

    logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < tolerance)
Beispiel #6
0
def test_velocity_gradient_eoc(actx_factory, dim):
    """Test that the velocity gradient converges at the proper rate."""
    from mirgecom.fluid import velocity_gradient
    actx = actx_factory()

    order = 3

    from pytools.convergence import EOCRecorder
    eoc = EOCRecorder()

    nel_1d_0 = 4
    for hn1 in [1, 2, 3, 4]:

        nel_1d = hn1 * nel_1d_0
        h = 1/nel_1d

        from meshmode.mesh.generation import generate_regular_rect_mesh
        mesh = generate_regular_rect_mesh(
            a=(1.0,) * dim, b=(2.0,) * dim, nelements_per_axis=(nel_1d,) * dim
        )

        discr = EagerDGDiscretization(actx, mesh, order=order)
        nodes = thaw(actx, discr.nodes())
        zeros = discr.zeros(actx)
        energy = zeros + 2.5

        mass = nodes[dim-1]*nodes[dim-1]
        velocity = make_obj_array([actx.np.cos(nodes[i]) for i in range(dim)])
        mom = mass*velocity

        q = join_conserved(dim, mass=mass, energy=energy, momentum=mom)
        cv = split_conserved(dim, q)

        grad_q = obj_array_vectorize(discr.grad, q)
        grad_cv = split_conserved(dim, grad_q)

        grad_v = velocity_gradient(discr, cv, grad_cv)

        def exact_grad_row(xdata, gdim, dim):
            exact_grad_row = make_obj_array([zeros for _ in range(dim)])
            exact_grad_row[gdim] = -actx.np.sin(xdata)
            return exact_grad_row

        comp_err = make_obj_array([
            discr.norm(grad_v[i] - exact_grad_row(nodes[i], i, dim), np.inf)
            for i in range(dim)])
        err_max = comp_err.max()
        eoc.add_data_point(h, err_max)

    logger.info(eoc)
    assert (
        eoc.order_estimate() >= order - 0.5
        or eoc.max_error() < 1e-9
    )
Beispiel #7
0
def test_basis_grad(dim, shape_cls, order, basis_getter):
    """Do a simplistic FD-style check on the gradients of the basis."""

    h = 1.0e-4

    shape = shape_cls(dim)
    rng = np.random.Generator(np.random.PCG64(17))
    basis = basis_getter(mp.space_for_shape(shape, order), shape)

    from pytools.convergence import EOCRecorder
    from pytools import wandering_element
    for i_bf, (bf, gradbf) in enumerate(zip(
            basis.functions,
            basis.gradients,
    )):
        eoc_rec = EOCRecorder()
        for h in [1e-2, 1e-3]:
            r = mp.random_nodes_for_shape(shape, nnodes=1000, rng=rng)

            gradbf_v = np.array(gradbf(r))
            gradbf_v_num = np.array([
                (bf(r + h * unit) - bf(r - h * unit)) / (2 * h)
                for unit_tuple in wandering_element(shape.dim)
                for unit in (np.array(unit_tuple).reshape(-1, 1), )
            ])

            ref_norm = la.norm((gradbf_v).reshape(-1), np.inf)
            err = la.norm((gradbf_v_num - gradbf_v).reshape(-1), np.inf)
            if ref_norm > 1e-13:
                err = err / ref_norm

            logger.info("error: %.5", err)
            eoc_rec.add_data_point(h, err)

        tol = 1e-8
        if eoc_rec.max_error() >= tol:
            print(eoc_rec)
        assert (eoc_rec.max_error() < tol or eoc_rec.order_estimate() >= 1.5)
Beispiel #8
0
def test_vortex_rhs(actx_factory, order):
    """Tests the inviscid rhs using the non-trivial
    2D isentropic vortex case configured to yield
    rhs = 0. Checks several different orders
    and refinement levels to check error
    behavior.
    """
    actx = actx_factory()

    dim = 2

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    from meshmode.mesh.generation import generate_regular_rect_mesh

    for nel_1d in [16, 32, 64]:

        mesh = generate_regular_rect_mesh(
            a=(-5, ) * dim,
            b=(5, ) * dim,
            n=(nel_1d, ) * dim,
        )

        logger.info(f"Number of {dim}d elements:  {mesh.nelements}")

        discr = EagerDGDiscretization(actx, mesh, order=order)
        nodes = thaw(actx, discr.nodes())

        # Init soln with Vortex and expected RHS = 0
        vortex = Vortex2D(center=[0, 0], velocity=[0, 0])
        vortex_soln = vortex(0, nodes)
        boundaries = {BTAG_ALL: PrescribedBoundary(vortex)}

        inviscid_rhs = inviscid_operator(discr,
                                         eos=IdealSingleGas(),
                                         boundaries=boundaries,
                                         q=vortex_soln,
                                         t=0.0)

        err_max = discr.norm(inviscid_rhs, np.inf)
        eoc_rec.add_data_point(1.0 / nel_1d, err_max)

    message = (f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")
    logger.info(message)

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-11)
Beispiel #9
0
def test_opposite_face_interpolation(ctx_getter, group_factory,
        mesh_name, dim, mesh_pars):
    logging.basicConfig(level=logging.INFO)

    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
            make_face_restriction, make_opposite_face_connection,
            check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 5

    def f(x):
        return 0.1*cl.clmath.sin(30*x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(
                    FileSource("blob-2d.step"), 2, order=order,
                    force_ambient_dim=2,
                    other_options=[
                        "-string", "Mesh.CharacteristicLengthMax = %s;" % h]
                    )
            print("END GEN")
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par)

            h = 1/mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(cl_ctx, mesh,
                group_factory(order))
        print("h=%s -> %d elements" % (
                h, sum(mgrp.nelements for mgrp in mesh.groups)))

        bdry_connection = make_face_restriction(
                vol_discr, group_factory(order),
                FRESTR_INTERIOR_FACES)
        bdry_discr = bdry_connection.to_discr

        opp_face = make_opposite_face_connection(bdry_connection)
        check_connection(opp_face)

        bdry_x = bdry_discr.nodes()[0].with_queue(queue)
        bdry_f = f(bdry_x)

        bdry_f_2 = opp_face(queue, bdry_f)

        err = la.norm((bdry_f-bdry_f_2).get(), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (
            eoc_rec.order_estimate() >= order-0.5
            or eoc_rec.max_error() < 1e-13)
Beispiel #10
0
def test_multilump_rhs(actx_factory, dim, order, v0, use_overintegration):
    """Test the Euler rhs using the non-trivial 1, 2, and 3D mass lump case.

    The case is tested against the analytic expressions of the RHS. Checks several
    different orders and refinement levels to check error behavior.
    """
    actx = actx_factory()
    nspecies = 10
    tolerance = 1e-8
    maxxerr = 0.0

    from pytools.convergence import EOCRecorder

    eoc_rec = EOCRecorder()

    for nel_1d in [4, 8, 12]:
        from meshmode.mesh.generation import (
            generate_regular_rect_mesh,
        )

        mesh = generate_regular_rect_mesh(
            a=(-1,) * dim, b=(1,) * dim, nelements_per_axis=(nel_1d,) * dim,
        )

        logger.info(f"Number of elements: {mesh.nelements}")

        from grudge.dof_desc import DISCR_TAG_BASE, DISCR_TAG_QUAD
        from meshmode.discretization.poly_element import \
            default_simplex_group_factory, QuadratureSimplexGroupFactory

        discr = EagerDGDiscretization(
            actx, mesh,
            discr_tag_to_group_factory={
                DISCR_TAG_BASE: default_simplex_group_factory(
                    base_dim=dim, order=order),
                DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(2*order + 1)
            }
        )

        if use_overintegration:
            quadrature_tag = DISCR_TAG_QUAD
        else:
            quadrature_tag = None

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

        centers = make_obj_array([np.zeros(shape=(dim,)) for i in range(nspecies)])
        spec_y0s = np.ones(shape=(nspecies,))
        spec_amplitudes = np.ones(shape=(nspecies,))

        velocity = np.zeros(shape=(dim,))
        velocity[0] = v0
        rho0 = 2.0

        lump = MulticomponentLump(dim=dim, nspecies=nspecies, rho0=rho0,
                                  spec_centers=centers, velocity=velocity,
                                  spec_y0s=spec_y0s, spec_amplitudes=spec_amplitudes)

        lump_soln = lump(nodes)
        gas_model = GasModel(eos=IdealSingleGas())
        fluid_state = make_fluid_state(lump_soln, gas_model)

        def _my_boundary(discr, btag, gas_model, state_minus, **kwargs):
            actx = state_minus.array_context
            bnd_discr = discr.discr_from_dd(btag)
            nodes = thaw(bnd_discr.nodes(), actx)
            return make_fluid_state(lump(x_vec=nodes, **kwargs), gas_model)

        boundaries = {
            BTAG_ALL: PrescribedFluidBoundary(boundary_state_func=_my_boundary)
        }

        inviscid_rhs = euler_operator(
            discr, state=fluid_state, gas_model=gas_model, boundaries=boundaries,
            time=0.0, quadrature_tag=quadrature_tag
        )
        expected_rhs = lump.exact_rhs(discr, cv=lump_soln, time=0)

        print(f"inviscid_rhs = {inviscid_rhs}")
        print(f"expected_rhs = {expected_rhs}")

        err_max = actx.to_numpy(
            discr.norm((inviscid_rhs-expected_rhs), np.inf))
        if err_max > maxxerr:
            maxxerr = err_max

        eoc_rec.add_data_point(1.0 / nel_1d, err_max)

        logger.info(f"Max error: {maxxerr}")

    logger.info(
        f"Error for (dim,order) = ({dim},{order}):\n"
        f"{eoc_rec}"
    )

    assert (
        eoc_rec.order_estimate() >= order - 0.5
        or eoc_rec.max_error() < tolerance
    )
Beispiel #11
0
def test_boundary_interpolation(ctx_getter, group_factory, boundary_tag,
                                mesh_name, dim, mesh_pars, per_face_groups):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (make_face_restriction,
                                                    check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 4

    def f(x):
        return 0.1 * cl.clmath.sin(30 * x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(FileSource("blob-2d.step"),
                                 2,
                                 order=order,
                                 force_ambient_dim=2,
                                 other_options=[
                                     "-string",
                                     "Mesh.CharacteristicLengthMax = %s;" % h
                                 ])
            print("END GEN")
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par)

            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(cl_ctx, mesh, group_factory(order))
        print("h=%s -> %d elements" %
              (h, sum(mgrp.nelements for mgrp in mesh.groups)))

        x = vol_discr.nodes()[0].with_queue(queue)
        vol_f = f(x)

        bdry_connection = make_face_restriction(
            vol_discr,
            group_factory(order),
            boundary_tag,
            per_face_groups=per_face_groups)
        check_connection(bdry_connection)
        bdry_discr = bdry_connection.to_discr

        bdry_x = bdry_discr.nodes()[0].with_queue(queue)
        bdry_f = f(bdry_x)
        bdry_f_2 = bdry_connection(queue, vol_f)

        if mesh_name == "blob" and dim == 2:
            mat = bdry_connection.full_resample_matrix(queue).get(queue)
            bdry_f_2_by_mat = mat.dot(vol_f.get())

            mat_error = la.norm(bdry_f_2.get(queue=queue) - bdry_f_2_by_mat)
            assert mat_error < 1e-14, mat_error

        err = la.norm((bdry_f - bdry_f_2).get(), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-14)
Beispiel #12
0
def test_all_faces_interpolation(ctx_getter, mesh_name, dim, mesh_pars,
                                 per_face_groups):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
        make_face_restriction, make_face_to_all_faces_embedding,
        check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 4

    def f(x):
        return 0.1 * cl.clmath.sin(30 * x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(FileSource("blob-2d.step"),
                                 2,
                                 order=order,
                                 force_ambient_dim=2,
                                 other_options=[
                                     "-string",
                                     "Mesh.CharacteristicLengthMax = %s;" % h
                                 ])
            print("END GEN")
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par)

            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(cl_ctx, mesh,
                                   PolynomialWarpAndBlendGroupFactory(order))
        print("h=%s -> %d elements" %
              (h, sum(mgrp.nelements for mgrp in mesh.groups)))

        all_face_bdry_connection = make_face_restriction(
            vol_discr,
            PolynomialWarpAndBlendGroupFactory(order),
            FRESTR_ALL_FACES,
            per_face_groups=per_face_groups)
        all_face_bdry_discr = all_face_bdry_connection.to_discr

        for ito_grp, ceg in enumerate(all_face_bdry_connection.groups):
            for ibatch, batch in enumerate(ceg.batches):
                assert np.array_equal(batch.from_element_indices.get(queue),
                                      np.arange(vol_discr.mesh.nelements))

                if per_face_groups:
                    assert ito_grp == batch.to_element_face
                else:
                    assert ibatch == batch.to_element_face

        all_face_x = all_face_bdry_discr.nodes()[0].with_queue(queue)
        all_face_f = f(all_face_x)

        all_face_f_2 = all_face_bdry_discr.zeros(queue)

        for boundary_tag in [
                BTAG_ALL,
                FRESTR_INTERIOR_FACES,
        ]:
            bdry_connection = make_face_restriction(
                vol_discr,
                PolynomialWarpAndBlendGroupFactory(order),
                boundary_tag,
                per_face_groups=per_face_groups)
            bdry_discr = bdry_connection.to_discr

            bdry_x = bdry_discr.nodes()[0].with_queue(queue)
            bdry_f = f(bdry_x)

            all_face_embedding = make_face_to_all_faces_embedding(
                bdry_connection, all_face_bdry_discr)

            check_connection(all_face_embedding)

            all_face_f_2 += all_face_embedding(queue, bdry_f)

        err = la.norm((all_face_f - all_face_f_2).get(), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-14)
Beispiel #13
0
def test_uniform_rhs(actx_factory, dim, order):
    """Tests the inviscid rhs using a trivial
    constant/uniform state which should
    yield rhs = 0 to FP.  The test is performed
    for 1, 2, and 3 dimensions.
    """
    actx = actx_factory()

    tolerance = 1e-9
    maxxerr = 0.0

    from pytools.convergence import EOCRecorder
    eoc_rec0 = EOCRecorder()
    eoc_rec1 = EOCRecorder()
    # for nel_1d in [4, 8, 12]:
    for nel_1d in [4, 8]:
        from meshmode.mesh.generation import generate_regular_rect_mesh
        mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                          b=(0.5, ) * dim,
                                          n=(nel_1d, ) * dim)

        logger.info(f"Number of {dim}d elements: {mesh.nelements}")

        discr = EagerDGDiscretization(actx, mesh, order=order)

        mass_input = discr.zeros(actx) + 1
        energy_input = discr.zeros(actx) + 2.5

        mom_input = make_obj_array(
            [discr.zeros(actx) for i in range(discr.dim)])
        fields = join_conserved(dim,
                                mass=mass_input,
                                energy=energy_input,
                                momentum=mom_input)

        expected_rhs = make_obj_array(
            [discr.zeros(actx) for i in range(len(fields))])

        boundaries = {BTAG_ALL: DummyBoundary()}
        inviscid_rhs = inviscid_operator(discr,
                                         eos=IdealSingleGas(),
                                         boundaries=boundaries,
                                         q=fields,
                                         t=0.0)
        rhs_resid = inviscid_rhs - expected_rhs

        resid_split = split_conserved(dim, rhs_resid)
        rho_resid = resid_split.mass
        rhoe_resid = resid_split.energy
        mom_resid = resid_split.momentum

        rhs_split = split_conserved(dim, inviscid_rhs)
        rho_rhs = rhs_split.mass
        rhoe_rhs = rhs_split.energy
        rhov_rhs = rhs_split.momentum

        message = (f"rho_rhs  = {rho_rhs}\n"
                   f"rhoe_rhs = {rhoe_rhs}\n"
                   f"rhov_rhs = {rhov_rhs}")
        logger.info(message)

        assert discr.norm(rho_resid, np.inf) < tolerance
        assert discr.norm(rhoe_resid, np.inf) < tolerance
        for i in range(dim):
            assert discr.norm(mom_resid[i], np.inf) < tolerance

            err_max = discr.norm(rhs_resid[i], np.inf)
            eoc_rec0.add_data_point(1.0 / nel_1d, err_max)
            assert (err_max < tolerance)
            if err_max > maxxerr:
                maxxerr = err_max
        # set a non-zero, but uniform velocity component

        for i in range(len(mom_input)):
            mom_input[i] = discr.zeros(actx) + (-1.0)**i

        boundaries = {BTAG_ALL: DummyBoundary()}
        inviscid_rhs = inviscid_operator(discr,
                                         eos=IdealSingleGas(),
                                         boundaries=boundaries,
                                         q=fields,
                                         t=0.0)
        rhs_resid = inviscid_rhs - expected_rhs

        resid_split = split_conserved(dim, rhs_resid)
        rho_resid = resid_split.mass
        rhoe_resid = resid_split.energy
        mom_resid = resid_split.momentum

        assert discr.norm(rho_resid, np.inf) < tolerance
        assert discr.norm(rhoe_resid, np.inf) < tolerance

        for i in range(dim):
            assert discr.norm(mom_resid[i], np.inf) < tolerance
            err_max = discr.norm(rhs_resid[i], np.inf)
            eoc_rec1.add_data_point(1.0 / nel_1d, err_max)
            assert (err_max < tolerance)
            if err_max > maxxerr:
                maxxerr = err_max

    message = (f"V == 0 Errors:\n{eoc_rec0}" f"V != 0 Errors:\n{eoc_rec1}")
    print(message)

    assert (eoc_rec0.order_estimate() >= order - 0.5
            or eoc_rec0.max_error() < 1e-9)
    assert (eoc_rec1.order_estimate() >= order - 0.5
            or eoc_rec1.max_error() < 1e-9)
Beispiel #14
0
def test_boundary_interpolation(actx_factory, group_factory, boundary_tag,
                                mesh_name, dim, mesh_pars, per_face_groups):
    if (group_factory is LegendreGaussLobattoTensorProductGroupFactory
            and mesh_name == "blob"):
        pytest.skip("tensor products not implemented on blobs")

    actx = actx_factory()

    if group_factory is LegendreGaussLobattoTensorProductGroupFactory:
        group_cls = TensorProductElementGroup
    else:
        group_cls = SimplexElementGroup

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (make_face_restriction,
                                                    check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 4

    def f(x):
        return 0.1 * actx.np.sin(30 * x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = float(mesh_par)

            #from meshmode.mesh.io import generate_gmsh, FileSource
            # print("BEGIN GEN")
            # mesh = generate_gmsh(
            #         FileSource("blob-2d.step"), 2, order=order,
            #         force_ambient_dim=2,
            #         other_options=[
            #             "-string", "Mesh.CharacteristicLengthMax = %s;" % h]
            #         )
            # print("END GEN")
            from meshmode.mesh.io import read_gmsh
            mesh = read_gmsh("blob2d-order%d-h%s.msh" % (order, mesh_par),
                             force_ambient_dim=2)
        elif mesh_name == "warp":
            mesh = mgen.generate_warped_rect_mesh(dim,
                                                  order=order,
                                                  nelements_side=mesh_par,
                                                  group_cls=group_cls)

            h = 1 / mesh_par

        elif mesh_name == "rect":
            mesh = mgen.generate_regular_rect_mesh(
                a=(0, ) * dim,
                b=(1, ) * dim,
                order=order,
                nelements_per_axis=(mesh_par, ) * dim,
                group_cls=group_cls)

            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(actx, mesh, group_factory(order))
        print("h=%s -> %d elements" %
              (h, sum(mgrp.nelements for mgrp in mesh.groups)))

        x = thaw(vol_discr.nodes()[0], actx)
        vol_f = f(x)

        bdry_connection = make_face_restriction(
            actx,
            vol_discr,
            group_factory(order),
            boundary_tag,
            per_face_groups=per_face_groups)
        check_connection(actx, bdry_connection)
        bdry_discr = bdry_connection.to_discr

        bdry_x = thaw(bdry_discr.nodes()[0], actx)
        bdry_f = f(bdry_x)
        bdry_f_2 = bdry_connection(vol_f)

        if mesh_name == "blob" and dim == 2 and mesh.nelements < 500:
            from meshmode.discretization.connection.direct import \
                    make_direct_full_resample_matrix
            mat = actx.to_numpy(
                make_direct_full_resample_matrix(actx, bdry_connection))
            bdry_f_2_by_mat = mat.dot(flatten_to_numpy(actx, vol_f))

            mat_error = la.norm(
                flatten_to_numpy(actx, bdry_f_2) - bdry_f_2_by_mat)
            assert mat_error < 1e-14, mat_error

        err = flat_norm(bdry_f - bdry_f_2, np.inf)
        eoc_rec.add_data_point(h, err)

    order_slack = 0.75 if mesh_name == "blob" else 0.5
    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - order_slack
            or eoc_rec.max_error() < 3.6e-13)
Beispiel #15
0
def test_all_faces_interpolation(actx_factory, group_factory, mesh_name, dim,
                                 mesh_pars, per_face_groups):
    if (group_factory is LegendreGaussLobattoTensorProductGroupFactory
            and mesh_name == "blob"):
        pytest.skip("tensor products not implemented on blobs")

    actx = actx_factory()

    if group_factory is LegendreGaussLobattoTensorProductGroupFactory:
        group_cls = TensorProductElementGroup
    else:
        group_cls = SimplexElementGroup

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
        make_face_restriction, make_face_to_all_faces_embedding,
        check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 4

    def f(x):
        return 0.1 * actx.np.sin(30 * x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(
                FileSource("blob-2d.step"),
                2,
                order=order,
                force_ambient_dim=2,
                other_options=[
                    "-string",
                    "Mesh.CharacteristicLengthMax = %s;" % h
                ],
                target_unit="MM",
            )
            print("END GEN")
        elif mesh_name == "warp":
            mesh = mgen.generate_warped_rect_mesh(dim,
                                                  order=4,
                                                  nelements_side=mesh_par,
                                                  group_cls=group_cls)

            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(actx, mesh, group_factory(order))
        print("h=%s -> %d elements" %
              (h, sum(mgrp.nelements for mgrp in mesh.groups)))

        all_face_bdry_connection = make_face_restriction(
            actx,
            vol_discr,
            group_factory(order),
            FACE_RESTR_ALL,
            per_face_groups=per_face_groups)
        all_face_bdry_discr = all_face_bdry_connection.to_discr

        for ito_grp, ceg in enumerate(all_face_bdry_connection.groups):
            for ibatch, batch in enumerate(ceg.batches):
                assert np.array_equal(
                    actx.to_numpy(actx.thaw(batch.from_element_indices)),
                    np.arange(vol_discr.mesh.nelements))

                if per_face_groups:
                    assert ito_grp == batch.to_element_face
                else:
                    assert ibatch == batch.to_element_face

        all_face_x = thaw(all_face_bdry_discr.nodes()[0], actx)
        all_face_f = f(all_face_x)

        all_face_f_2 = all_face_bdry_discr.zeros(actx)

        for boundary_tag in [
                BTAG_ALL,
                FACE_RESTR_INTERIOR,
        ]:
            bdry_connection = make_face_restriction(
                actx,
                vol_discr,
                group_factory(order),
                boundary_tag,
                per_face_groups=per_face_groups)
            bdry_discr = bdry_connection.to_discr

            bdry_x = thaw(bdry_discr.nodes()[0], actx)
            bdry_f = f(bdry_x)

            all_face_embedding = make_face_to_all_faces_embedding(
                actx, bdry_connection, all_face_bdry_discr)

            check_connection(actx, all_face_embedding)

            all_face_f_2 = all_face_f_2 + all_face_embedding(bdry_f)

        err = flat_norm(all_face_f - all_face_f_2, np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-14)
Beispiel #16
0
def test_slipwall_flux(actx_factory, dim, order):
    """Check for zero boundary flux.

    Check for vanishing flux across the slipwall.
    """
    actx = actx_factory()

    wall = AdiabaticSlipBoundary()
    eos = IdealSingleGas()

    from pytools.convergence import EOCRecorder
    eoc = EOCRecorder()

    for nel_1d in [4, 8, 12]:
        from meshmode.mesh.generation import generate_regular_rect_mesh

        mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                          b=(0.5, ) * dim,
                                          nelements_per_axis=(nel_1d, ) * dim)

        discr = EagerDGDiscretization(actx, mesh, order=order)
        nodes = thaw(actx, discr.nodes())
        nhat = thaw(actx, discr.normal(BTAG_ALL))
        h = 1.0 / nel_1d

        from functools import partial
        bnd_norm = partial(discr.norm, p=np.inf, dd=BTAG_ALL)

        logger.info(f"Number of {dim}d elems: {mesh.nelements}")
        # for velocities in each direction
        err_max = 0.0
        for vdir in range(dim):
            vel = np.zeros(shape=(dim, ))

            # for velocity directions +1, and -1
            for parity in [1.0, -1.0]:
                vel[vdir] = parity
                from mirgecom.initializers import Uniform
                initializer = Uniform(dim=dim, velocity=vel)
                uniform_state = initializer(nodes)
                bnd_pair = wall.boundary_pair(discr,
                                              btag=BTAG_ALL,
                                              eos=eos,
                                              cv=uniform_state)

                # Check the total velocity component normal
                # to each surface.  It should be zero.  The
                # numerical fluxes cannot be zero.
                avg_state = 0.5 * (bnd_pair.int + bnd_pair.ext)
                err_max = max(err_max,
                              bnd_norm(np.dot(avg_state.momentum, nhat)))

                from mirgecom.euler import _facial_flux
                bnd_flux = _facial_flux(discr,
                                        eos,
                                        cv_tpair=bnd_pair,
                                        local=True)
                err_max = max(err_max, bnd_norm(bnd_flux.mass),
                              bnd_norm(bnd_flux.energy))

        eoc.add_data_point(h, err_max)

    message = (f"EOC:\n{eoc}")
    logger.info(message)
    assert (eoc.order_estimate() >= order - 0.5 or eoc.max_error() < 1e-12)
Beispiel #17
0
def test_facial_flux(actx_factory, nspecies, order, dim):
    """Check the flux across element faces.

    The flux is checked by prescribing states (q) with known fluxes. Only uniform
    states are tested currently - ensuring that the Lax-Friedrichs flux terms which
    are proportional to jumps in state data vanish.

    Since the returned fluxes use state data which has been interpolated
    to-and-from the element faces, this test is grid-dependent.
    """
    actx = actx_factory()

    tolerance = 1e-14
    p0 = 1.0

    from meshmode.mesh.generation import generate_regular_rect_mesh
    from pytools.convergence import EOCRecorder

    eoc_rec0 = EOCRecorder()
    eoc_rec1 = EOCRecorder()
    for nel_1d in [4, 8, 12]:

        mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                          b=(0.5, ) * dim,
                                          nelements_per_axis=(nel_1d, ) * dim)

        logger.info(f"Number of elements: {mesh.nelements}")

        discr = EagerDGDiscretization(actx, mesh, order=order)
        zeros = discr.zeros(actx)
        ones = zeros + 1.0

        mass_input = discr.zeros(actx) + 1.0
        energy_input = discr.zeros(actx) + 2.5
        mom_input = flat_obj_array(
            [discr.zeros(actx) for i in range(discr.dim)])
        mass_frac_input = flat_obj_array(
            [ones / ((i + 1) * 10) for i in range(nspecies)])
        species_mass_input = mass_input * mass_frac_input

        cv = make_conserved(dim,
                            mass=mass_input,
                            energy=energy_input,
                            momentum=mom_input,
                            species_mass=species_mass_input)
        from grudge.trace_pair import interior_trace_pairs
        cv_interior_pairs = interior_trace_pairs(discr, cv)
        # Check the boundary facial fluxes as called on an interior boundary
        # eos = IdealSingleGas()
        from mirgecom.gas_model import (GasModel, make_fluid_state)
        gas_model = GasModel(eos=IdealSingleGas())
        from mirgecom.gas_model import make_fluid_state_trace_pairs
        state_tpairs = make_fluid_state_trace_pairs(cv_interior_pairs,
                                                    gas_model)
        interior_state_pair = state_tpairs[0]
        from mirgecom.inviscid import inviscid_facial_flux
        interior_face_flux = \
            inviscid_facial_flux(discr, state_tpair=interior_state_pair)

        def inf_norm(data):
            if len(data) > 0:
                return actx.to_numpy(discr.norm(data, np.inf, dd="all_faces"))
            else:
                return 0.0

        assert inf_norm(interior_face_flux.mass) < tolerance
        assert inf_norm(interior_face_flux.energy) < tolerance
        assert inf_norm(interior_face_flux.species_mass) < tolerance

        # The expected pressure is 1.0 (by design). And the flux diagonal is
        # [rhov_x*v_x + p] (etc) since we have zero velocities it's just p.
        #
        # The off-diagonals are zero. We get a {ndim}-vector for each
        # dimension, the flux for the x-component of momentum (for example) is:
        # f_momx = < 1.0, 0 , 0> , then we return f_momx .dot. normal, which
        # can introduce negative values.
        #
        # (Explanation courtesy of Mike Campbell,
        # https://github.com/illinois-ceesd/mirgecom/pull/44#discussion_r463304292)

        nhat = thaw(actx, discr.normal("int_faces"))
        mom_flux_exact = discr.project("int_faces", "all_faces", p0 * nhat)
        print(f"{mom_flux_exact=}")
        print(f"{interior_face_flux.momentum=}")
        momerr = inf_norm(interior_face_flux.momentum - mom_flux_exact)
        assert momerr < tolerance
        eoc_rec0.add_data_point(1.0 / nel_1d, momerr)

        # Check the boundary facial fluxes as called on a domain boundary
        dir_mass = discr.project("vol", BTAG_ALL, mass_input)
        dir_e = discr.project("vol", BTAG_ALL, energy_input)
        dir_mom = discr.project("vol", BTAG_ALL, mom_input)
        dir_mf = discr.project("vol", BTAG_ALL, species_mass_input)

        dir_bc = make_conserved(dim,
                                mass=dir_mass,
                                energy=dir_e,
                                momentum=dir_mom,
                                species_mass=dir_mf)
        dir_bval = make_conserved(dim,
                                  mass=dir_mass,
                                  energy=dir_e,
                                  momentum=dir_mom,
                                  species_mass=dir_mf)
        state_tpair = TracePair(BTAG_ALL,
                                interior=make_fluid_state(dir_bval, gas_model),
                                exterior=make_fluid_state(dir_bc, gas_model))
        boundary_flux = inviscid_facial_flux(discr, state_tpair=state_tpair)

        assert inf_norm(boundary_flux.mass) < tolerance
        assert inf_norm(boundary_flux.energy) < tolerance
        assert inf_norm(boundary_flux.species_mass) < tolerance

        nhat = thaw(actx, discr.normal(BTAG_ALL))
        mom_flux_exact = discr.project(BTAG_ALL, "all_faces", p0 * nhat)
        momerr = inf_norm(boundary_flux.momentum - mom_flux_exact)
        assert momerr < tolerance

        eoc_rec1.add_data_point(1.0 / nel_1d, momerr)

    logger.info(f"standalone Errors:\n{eoc_rec0}"
                f"boundary Errors:\n{eoc_rec1}")
    assert (eoc_rec0.order_estimate() >= order - 0.5
            or eoc_rec0.max_error() < 1e-9)
    assert (eoc_rec1.order_estimate() >= order - 0.5
            or eoc_rec1.max_error() < 1e-9)
Beispiel #18
0
def test_refinement_connection(ctx_getter,
                               group_factory,
                               mesh_name,
                               dim,
                               mesh_pars,
                               mesh_order,
                               refine_flags,
                               plot_mesh=False):
    from random import seed
    seed(13)

    # Discretization order
    order = 5

    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (make_refinement_connection,
                                                    check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    def f(x):
        from six.moves import reduce
        return 0.1 * reduce(lambda x, y: x * cl.clmath.sin(5 * y), x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "circle":
            assert dim == 1
            h = 1 / mesh_par
            mesh = make_curve_mesh(partial(ellipse, 1),
                                   np.linspace(0, 1, mesh_par + 1),
                                   order=mesh_order)
        elif mesh_name == "blob":
            if mesh_order == 5:
                pytest.xfail(
                    "https://gitlab.tiker.net/inducer/meshmode/issues/2")
            assert dim == 2
            h = mesh_par
            mesh = gen_blob_mesh(h, mesh_order)
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=mesh_order, n=mesh_par)
            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        discr = Discretization(cl_ctx, mesh, group_factory(order))

        refiner = Refiner(mesh)
        flags = refine_flags(mesh)
        refiner.refine(flags)

        connection = make_refinement_connection(refiner, discr,
                                                group_factory(order))
        check_connection(connection)

        fine_discr = connection.to_discr

        x = discr.nodes().with_queue(queue)
        x_fine = fine_discr.nodes().with_queue(queue)
        f_coarse = f(x)
        f_interp = connection(queue, f_coarse).with_queue(queue)
        f_true = f(x_fine).with_queue(queue)

        if plot_mesh:
            import matplotlib.pyplot as plt
            x = x.get(queue)
            err = np.array(np.log10(1e-16 +
                                    np.abs((f_interp - f_true).get(queue))),
                           dtype=float)
            import matplotlib.cm as cm
            cmap = cm.ScalarMappable(cmap=cm.jet)
            cmap.set_array(err)
            plt.scatter(x[0], x[1], c=cmap.to_rgba(err), s=20, cmap=cmap)
            plt.colorbar(cmap)
            plt.show()

        import numpy.linalg as la
        err = la.norm((f_interp - f_true).get(queue), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-14)
Beispiel #19
0
def test_uniform_rhs(actx_factory, nspecies, dim, order):
    """Test the inviscid rhs using a trivial constant/uniform state.

    This state should yield rhs = 0 to FP.  The test is performed for 1, 2,
    and 3 dimensions, with orders 1, 2, and 3, with and without passive species.
    """
    actx = actx_factory()

    tolerance = 1e-9

    from pytools.convergence import EOCRecorder
    eoc_rec0 = EOCRecorder()
    eoc_rec1 = EOCRecorder()
    # for nel_1d in [4, 8, 12]:
    for nel_1d in [4, 8]:
        from meshmode.mesh.generation import generate_regular_rect_mesh
        mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                          b=(0.5, ) * dim,
                                          nelements_per_axis=(nel_1d, ) * dim)

        logger.info(f"Number of {dim}d elements: {mesh.nelements}")

        discr = EagerDGDiscretization(actx, mesh, order=order)
        zeros = discr.zeros(actx)
        ones = zeros + 1.0

        mass_input = discr.zeros(actx) + 1
        energy_input = discr.zeros(actx) + 2.5

        mom_input = make_obj_array(
            [discr.zeros(actx) for i in range(discr.dim)])

        mass_frac_input = flat_obj_array(
            [ones / ((i + 1) * 10) for i in range(nspecies)])
        species_mass_input = mass_input * mass_frac_input
        num_equations = dim + 2 + len(species_mass_input)

        cv = make_conserved(dim,
                            mass=mass_input,
                            energy=energy_input,
                            momentum=mom_input,
                            species_mass=species_mass_input)

        expected_rhs = make_conserved(
            dim,
            q=make_obj_array([discr.zeros(actx)
                              for i in range(num_equations)]))

        boundaries = {BTAG_ALL: DummyBoundary()}
        inviscid_rhs = euler_operator(discr,
                                      eos=IdealSingleGas(),
                                      boundaries=boundaries,
                                      cv=cv,
                                      time=0.0)
        rhs_resid = inviscid_rhs - expected_rhs

        rho_resid = rhs_resid.mass
        rhoe_resid = rhs_resid.energy
        mom_resid = rhs_resid.momentum
        rhoy_resid = rhs_resid.species_mass

        rho_rhs = inviscid_rhs.mass
        rhoe_rhs = inviscid_rhs.energy
        rhov_rhs = inviscid_rhs.momentum
        rhoy_rhs = inviscid_rhs.species_mass

        logger.info(f"rho_rhs  = {rho_rhs}\n"
                    f"rhoe_rhs = {rhoe_rhs}\n"
                    f"rhov_rhs = {rhov_rhs}\n"
                    f"rhoy_rhs = {rhoy_rhs}\n")

        assert discr.norm(rho_resid, np.inf) < tolerance
        assert discr.norm(rhoe_resid, np.inf) < tolerance
        for i in range(dim):
            assert discr.norm(mom_resid[i], np.inf) < tolerance
        for i in range(nspecies):
            assert discr.norm(rhoy_resid[i], np.inf) < tolerance

        err_max = discr.norm(rho_resid, np.inf)
        eoc_rec0.add_data_point(1.0 / nel_1d, err_max)

        # set a non-zero, but uniform velocity component
        for i in range(len(mom_input)):
            mom_input[i] = discr.zeros(actx) + (-1.0)**i

        cv = make_conserved(dim,
                            mass=mass_input,
                            energy=energy_input,
                            momentum=mom_input,
                            species_mass=species_mass_input)

        boundaries = {BTAG_ALL: DummyBoundary()}
        inviscid_rhs = euler_operator(discr,
                                      eos=IdealSingleGas(),
                                      boundaries=boundaries,
                                      cv=cv,
                                      time=0.0)
        rhs_resid = inviscid_rhs - expected_rhs

        rho_resid = rhs_resid.mass
        rhoe_resid = rhs_resid.energy
        mom_resid = rhs_resid.momentum
        rhoy_resid = rhs_resid.species_mass

        assert discr.norm(rho_resid, np.inf) < tolerance
        assert discr.norm(rhoe_resid, np.inf) < tolerance

        for i in range(dim):
            assert discr.norm(mom_resid[i], np.inf) < tolerance
        for i in range(nspecies):
            assert discr.norm(rhoy_resid[i], np.inf) < tolerance

        err_max = discr.norm(rho_resid, np.inf)
        eoc_rec1.add_data_point(1.0 / nel_1d, err_max)

    logger.info(f"V == 0 Errors:\n{eoc_rec0}" f"V != 0 Errors:\n{eoc_rec1}")

    assert (eoc_rec0.order_estimate() >= order - 0.5
            or eoc_rec0.max_error() < 1e-9)
    assert (eoc_rec1.order_estimate() >= order - 0.5
            or eoc_rec1.max_error() < 1e-9)
Beispiel #20
0
def test_multilump_rhs(actx_factory, dim, order, v0):
    """Test the Euler rhs using the non-trivial 1, 2, and 3D mass lump case.

    The case is tested against the analytic expressions of the RHS. Checks several
    different orders and refinement levels to check error behavior.
    """
    actx = actx_factory()
    nspecies = 10
    tolerance = 1e-8
    maxxerr = 0.0

    from pytools.convergence import EOCRecorder

    eoc_rec = EOCRecorder()

    for nel_1d in [4, 8, 16]:
        from meshmode.mesh.generation import (
            generate_regular_rect_mesh, )

        mesh = generate_regular_rect_mesh(
            a=(-1, ) * dim,
            b=(1, ) * dim,
            nelements_per_axis=(nel_1d, ) * dim,
        )

        logger.info(f"Number of elements: {mesh.nelements}")

        discr = EagerDGDiscretization(actx, mesh, order=order)
        nodes = thaw(actx, discr.nodes())

        centers = make_obj_array(
            [np.zeros(shape=(dim, )) for i in range(nspecies)])
        spec_y0s = np.ones(shape=(nspecies, ))
        spec_amplitudes = np.ones(shape=(nspecies, ))

        velocity = np.zeros(shape=(dim, ))
        velocity[0] = v0
        rho0 = 2.0

        lump = MulticomponentLump(dim=dim,
                                  nspecies=nspecies,
                                  rho0=rho0,
                                  spec_centers=centers,
                                  velocity=velocity,
                                  spec_y0s=spec_y0s,
                                  spec_amplitudes=spec_amplitudes)

        lump_soln = lump(nodes)
        boundaries = {
            BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=lump)
        }

        inviscid_rhs = euler_operator(discr,
                                      eos=IdealSingleGas(),
                                      boundaries=boundaries,
                                      cv=lump_soln,
                                      time=0.0)
        expected_rhs = lump.exact_rhs(discr, cv=lump_soln, time=0)

        print(f"inviscid_rhs = {inviscid_rhs}")
        print(f"expected_rhs = {expected_rhs}")
        err_max = discr.norm((inviscid_rhs - expected_rhs).join(), np.inf)
        if err_max > maxxerr:
            maxxerr = err_max

        eoc_rec.add_data_point(1.0 / nel_1d, err_max)

        logger.info(f"Max error: {maxxerr}")

    logger.info(f"Error for (dim,order) = ({dim},{order}):\n" f"{eoc_rec}")

    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < tolerance)
Beispiel #21
0
def test_vortex_rhs(actx_factory, order, use_overintegration):
    """Test the inviscid rhs using the non-trivial 2D isentropic vortex.

    The case is configured to yield rhs = 0. Checks several different orders
    and refinement levels to check error behavior.
    """
    actx = actx_factory()

    dim = 2

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    from meshmode.mesh.generation import generate_regular_rect_mesh

    for nel_1d in [32, 48, 64]:

        mesh = generate_regular_rect_mesh(
            a=(-5,) * dim, b=(5,) * dim, nelements_per_axis=(nel_1d,) * dim,
        )

        logger.info(
            f"Number of {dim}d elements:  {mesh.nelements}"
        )

        from grudge.dof_desc import DISCR_TAG_BASE, DISCR_TAG_QUAD
        from meshmode.discretization.poly_element import \
            default_simplex_group_factory, QuadratureSimplexGroupFactory

        discr = EagerDGDiscretization(
            actx, mesh,
            discr_tag_to_group_factory={
                DISCR_TAG_BASE: default_simplex_group_factory(
                    base_dim=dim, order=order),
                DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(2*order + 1)
            }
        )

        if use_overintegration:
            quadrature_tag = DISCR_TAG_QUAD
        else:
            quadrature_tag = None

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

        # Init soln with Vortex and expected RHS = 0
        vortex = Vortex2D(center=[0, 0], velocity=[0, 0])
        vortex_soln = vortex(nodes)
        gas_model = GasModel(eos=IdealSingleGas())
        fluid_state = make_fluid_state(vortex_soln, gas_model)

        def _vortex_boundary(discr, btag, gas_model, state_minus, **kwargs):
            actx = state_minus.array_context
            bnd_discr = discr.discr_from_dd(btag)
            nodes = thaw(bnd_discr.nodes(), actx)
            return make_fluid_state(vortex(x_vec=nodes, **kwargs), gas_model)

        boundaries = {
            BTAG_ALL: PrescribedFluidBoundary(boundary_state_func=_vortex_boundary)
        }

        inviscid_rhs = euler_operator(
            discr, state=fluid_state, gas_model=gas_model, boundaries=boundaries,
            time=0.0, quadrature_tag=quadrature_tag)

        err_max = max_component_norm(discr, inviscid_rhs, np.inf)

        eoc_rec.add_data_point(1.0 / nel_1d, err_max)

    logger.info(
        f"Error for (dim,order) = ({dim},{order}):\n"
        f"{eoc_rec}"
    )

    assert (
        eoc_rec.order_estimate() >= order - 0.5
        or eoc_rec.max_error() < 1e-11
    )
Beispiel #22
0
def test_boundary_interpolation(ctx_getter, group_factory, boundary_tag,
        mesh_name, dim, mesh_pars, per_face_groups):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
            make_face_restriction, check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 4

    def f(x):
        return 0.1*cl.clmath.sin(30*x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(
                    FileSource("blob-2d.step"), 2, order=order,
                    force_ambient_dim=2,
                    other_options=[
                        "-string", "Mesh.CharacteristicLengthMax = %s;" % h]
                    )
            print("END GEN")
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par)

            h = 1/mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(cl_ctx, mesh,
                group_factory(order))
        print("h=%s -> %d elements" % (
                h, sum(mgrp.nelements for mgrp in mesh.groups)))

        x = vol_discr.nodes()[0].with_queue(queue)
        vol_f = f(x)

        bdry_connection = make_face_restriction(
                vol_discr, group_factory(order),
                boundary_tag, per_face_groups=per_face_groups)
        check_connection(bdry_connection)
        bdry_discr = bdry_connection.to_discr

        bdry_x = bdry_discr.nodes()[0].with_queue(queue)
        bdry_f = f(bdry_x)
        bdry_f_2 = bdry_connection(queue, vol_f)

        if mesh_name == "blob" and dim == 2:
            mat = bdry_connection.full_resample_matrix(queue).get(queue)
            bdry_f_2_by_mat = mat.dot(vol_f.get())

            mat_error = la.norm(bdry_f_2.get(queue=queue) - bdry_f_2_by_mat)
            assert mat_error < 1e-14, mat_error

        err = la.norm((bdry_f-bdry_f_2).get(), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (
            eoc_rec.order_estimate() >= order-0.5
            or eoc_rec.max_error() < 1e-14)
Beispiel #23
0
def test_refinement_connection(actx_factory,
                               refiner_cls,
                               group_factory,
                               mesh_name,
                               dim,
                               mesh_pars,
                               mesh_order,
                               refine_flags,
                               visualize=False):
    group_cls = group_factory.mesh_group_class
    if issubclass(group_cls, TensorProductElementGroup):
        if mesh_name in ["circle", "blob"]:
            pytest.skip("mesh does not have tensor product support")

    from random import seed
    seed(13)

    actx = actx_factory()

    # discretization order
    order = 5

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (make_refinement_connection,
                                                    check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "circle":
            assert dim == 1
            h = 1 / mesh_par
            mesh = make_curve_mesh(partial(ellipse, 1),
                                   np.linspace(0, 1, mesh_par + 1),
                                   order=mesh_order)
        elif mesh_name == "blob":
            if mesh_order == 5:
                pytest.xfail(
                    "https://gitlab.tiker.net/inducer/meshmode/issues/2")
            assert dim == 2
            mesh = get_blob_mesh(mesh_par, mesh_order)
            h = float(mesh_par)
        elif mesh_name == "warp":
            mesh = mgen.generate_warped_rect_mesh(dim,
                                                  order=mesh_order,
                                                  n=mesh_par,
                                                  group_cls=group_cls)
            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        from meshmode.mesh.processing import find_bounding_box
        mesh_bbox_low, mesh_bbox_high = find_bounding_box(mesh)
        mesh_ext = mesh_bbox_high - mesh_bbox_low

        def f(x):
            result = 1
            if mesh_name == "blob":
                factor = 15
            else:
                factor = 9

            for iaxis in range(len(x)):
                result = result * actx.np.sin(factor *
                                              (x[iaxis] / mesh_ext[iaxis]))

            return result

        discr = Discretization(actx, mesh, group_factory(order))

        refiner = refiner_cls(mesh)
        flags = refine_flags(mesh)
        refiner.refine(flags)

        connection = make_refinement_connection(actx, refiner, discr,
                                                group_factory(order))
        check_connection(actx, connection)

        fine_discr = connection.to_discr

        x = thaw(actx, discr.nodes())
        x_fine = thaw(actx, fine_discr.nodes())
        f_coarse = f(x)
        f_interp = connection(f_coarse)
        f_true = f(x_fine)

        if visualize == "dots":
            import matplotlib.pyplot as plt
            x = x.get(actx.queue)
            err = np.array(
                np.log10(1e-16 + np.abs((f_interp - f_true).get(actx.queue))),
                dtype=float)
            import matplotlib.cm as cm
            cmap = cm.ScalarMappable(cmap=cm.jet)
            cmap.set_array(err)
            plt.scatter(x[0], x[1], c=cmap.to_rgba(err), s=20, cmap=cmap)
            plt.colorbar(cmap)
            plt.show()

        elif visualize == "vtk":
            from meshmode.discretization.visualization import make_visualizer
            fine_vis = make_visualizer(actx, fine_discr, mesh_order)

            fine_vis.write_vtk_file(
                "refine-fine-%s-%dd-%s.vtu" % (mesh_name, dim, mesh_par), [
                    ("f_interp", f_interp),
                    ("f_true", f_true),
                ])

        err = actx.np.linalg.norm(f_interp - f_true, np.inf)
        eoc_rec.add_data_point(h, err)

    order_slack = 0.5
    if mesh_name == "blob" and order > 1:
        order_slack = 1

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - order_slack
            or eoc_rec.max_error() < 1e-14)
Beispiel #24
0
def test_mass_surface_area(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)
        surface_area = _ellipse_surface_area(builder.radius,
                                             builder.aspect_ratio)
    elif name == "spheroid":
        from mesh_data import SpheroidMeshBuilder
        builder = SpheroidMeshBuilder()
        surface_area = _spheroid_surface_area(builder.radius,
                                              builder.aspect_ratio)
    elif name == "box2d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=2)
        surface_area = 1.0
    elif name == "box3d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=3)
        surface_area = 1.0
    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 surface area

        dd = dof_desc.DD_VOLUME
        sym_op = sym.NodalSum(dd)(sym.MassOperator(dd, dd)(sym.Ones(dd)))
        approx_surface_area = bind(discr, sym_op)(actx)

        logger.info("surface: got {:.5e} / expected {:.5e}".format(
            approx_surface_area, surface_area))
        area_error = abs(approx_surface_area -
                         surface_area) / abs(surface_area)

        # }}}

        h_max = bind(
            discr,
            sym.h_max_from_volume(discr.ambient_dim, dim=discr.dim,
                                  dd=dd))(actx)
        eoc.add_data_point(h_max, area_error + 1.0e-16)

    # }}}

    logger.info("surface area error\n%s", str(eoc))

    assert eoc.max_error() < 1.0e-14 \
            or eoc.order_estimate() > builder.order
Beispiel #25
0
def test_opposite_face_interpolation(actx_factory, group_factory, mesh_name,
                                     dim, mesh_pars):
    if (group_factory is LegendreGaussLobattoTensorProductGroupFactory
            and mesh_name in ["segment", "blob"]):
        pytest.skip("tensor products not implemented on blobs")

    logging.basicConfig(level=logging.INFO)
    actx = actx_factory()

    if group_factory is LegendreGaussLobattoTensorProductGroupFactory:
        group_cls = TensorProductElementGroup
    else:
        group_cls = SimplexElementGroup

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
        make_face_restriction, make_opposite_face_connection, check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 5

    def f(x):
        return 0.1 * actx.np.sin(30 * x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "segment":
            assert dim == 1

            mesh = mgen.generate_box_mesh([np.linspace(-0.5, 0.5, mesh_par)],
                                          order=order,
                                          group_cls=group_cls)
            h = 1.0 / mesh_par
        elif mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(
                FileSource("blob-2d.step"),
                2,
                order=order,
                force_ambient_dim=2,
                other_options=[
                    "-string",
                    "Mesh.CharacteristicLengthMax = %s;" % h
                ],
                target_unit="MM",
            )
            print("END GEN")
        elif mesh_name == "warp":
            mesh = mgen.generate_warped_rect_mesh(dim,
                                                  order=order,
                                                  nelements_side=mesh_par,
                                                  group_cls=group_cls)

            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(actx, mesh, group_factory(order))
        print("h=%s -> %d elements" %
              (h, sum(mgrp.nelements for mgrp in mesh.groups)))

        bdry_connection = make_face_restriction(actx, vol_discr,
                                                group_factory(order),
                                                FACE_RESTR_INTERIOR)
        bdry_discr = bdry_connection.to_discr

        opp_face = make_opposite_face_connection(actx, bdry_connection)
        check_connection(actx, opp_face)

        bdry_x = thaw(bdry_discr.nodes()[0], actx)
        bdry_f = f(bdry_x)
        bdry_f_2 = opp_face(bdry_f)

        err = flat_norm(bdry_f - bdry_f_2, np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1.7e-13)
Beispiel #26
0
def test_refinement_connection(
        ctx_getter, refiner_cls, group_factory,
        mesh_name, dim, mesh_pars, mesh_order, refine_flags, visualize=False):
    from random import seed
    seed(13)

    # Discretization order
    order = 5

    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
            make_refinement_connection, check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "circle":
            assert dim == 1
            h = 1 / mesh_par
            mesh = make_curve_mesh(
                partial(ellipse, 1), np.linspace(0, 1, mesh_par + 1),
                order=mesh_order)
        elif mesh_name == "blob":
            if mesh_order == 5:
                pytest.xfail("https://gitlab.tiker.net/inducer/meshmode/issues/2")
            assert dim == 2
            mesh = get_blob_mesh(mesh_par, mesh_order)
            h = float(mesh_par)
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=mesh_order, n=mesh_par)
            h = 1/mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        from meshmode.mesh.processing import find_bounding_box
        mesh_bbox_low, mesh_bbox_high = find_bounding_box(mesh)
        mesh_ext = mesh_bbox_high-mesh_bbox_low

        def f(x):
            result = 1
            if mesh_name == "blob":
                factor = 15
            else:
                factor = 9

            for iaxis in range(len(x)):
                result = result * cl.clmath.sin(factor * (x[iaxis]/mesh_ext[iaxis]))

            return result

        discr = Discretization(cl_ctx, mesh, group_factory(order))

        refiner = refiner_cls(mesh)
        flags = refine_flags(mesh)
        refiner.refine(flags)

        connection = make_refinement_connection(
            refiner, discr, group_factory(order))
        check_connection(connection)

        fine_discr = connection.to_discr

        x = discr.nodes().with_queue(queue)
        x_fine = fine_discr.nodes().with_queue(queue)
        f_coarse = f(x)
        f_interp = connection(queue, f_coarse).with_queue(queue)
        f_true = f(x_fine).with_queue(queue)

        if visualize == "dots":
            import matplotlib.pyplot as plt
            x = x.get(queue)
            err = np.array(np.log10(
                1e-16 + np.abs((f_interp - f_true).get(queue))), dtype=float)
            import matplotlib.cm as cm
            cmap = cm.ScalarMappable(cmap=cm.jet)
            cmap.set_array(err)
            plt.scatter(x[0], x[1], c=cmap.to_rgba(err), s=20, cmap=cmap)
            plt.colorbar(cmap)
            plt.show()

        elif visualize == "vtk":
            from meshmode.discretization.visualization import make_visualizer
            fine_vis = make_visualizer(queue, fine_discr, mesh_order)

            fine_vis.write_vtk_file(
                    "refine-fine-%s-%dd-%s.vtu" % (mesh_name, dim, mesh_par), [
                        ("f_interp", f_interp),
                        ("f_true", f_true),
                        ])

        import numpy.linalg as la
        err = la.norm((f_interp - f_true).get(queue), np.inf)
        eoc_rec.add_data_point(h, err)

    order_slack = 0.5
    if mesh_name == "blob" and order > 1:
        order_slack = 1

    print(eoc_rec)
    assert (
            eoc_rec.order_estimate() >= order-order_slack
            or eoc_rec.max_error() < 1e-14)
Beispiel #27
0
def test_facial_flux(actx_factory, order, dim):
    """Check the flux across element faces by
    prescribing states (q) with known fluxes. Only
    uniform states are tested currently - ensuring
    that the Lax-Friedrichs flux terms which are
    proportional to jumps in state data vanish.

    Since the returned fluxes use state data which
    has been interpolated to-and-from the element
    faces, this test is grid-dependent.
    """
    actx = actx_factory()

    tolerance = 1e-14
    p0 = 1.0

    from meshmode.mesh.generation import generate_regular_rect_mesh
    from pytools.convergence import EOCRecorder

    eoc_rec0 = EOCRecorder()
    eoc_rec1 = EOCRecorder()
    for nel_1d in [4, 8, 12]:

        mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                          b=(0.5, ) * dim,
                                          n=(nel_1d, ) * dim)

        logger.info(f"Number of elements: {mesh.nelements}")

        discr = EagerDGDiscretization(actx, mesh, order=order)

        mass_input = discr.zeros(actx) + 1.0
        energy_input = discr.zeros(actx) + 2.5
        mom_input = flat_obj_array(
            [discr.zeros(actx) for i in range(discr.dim)])

        fields = join_conserved(dim,
                                mass=mass_input,
                                energy=energy_input,
                                momentum=mom_input)

        from mirgecom.euler import _facial_flux

        interior_face_flux = _facial_flux(discr,
                                          eos=IdealSingleGas(),
                                          q_tpair=interior_trace_pair(
                                              discr, fields))

        from functools import partial
        fnorm = partial(discr.norm, p=np.inf, dd="all_faces")

        iff_split = split_conserved(dim, interior_face_flux)
        assert fnorm(iff_split.mass) < tolerance
        assert fnorm(iff_split.energy) < tolerance

        # The expected pressure 1.0 (by design). And the flux diagonal is
        # [rhov_x*v_x + p] (etc) since we have zero velocities it's just p.
        #
        # The off-diagonals are zero. We get a {ndim}-vector for each
        # dimension, the flux for the x-component of momentum (for example) is:
        # f_momx = < 1.0, 0 , 0> , then we return f_momx .dot. normal, which
        # can introduce negative values.
        #
        # (Explanation courtesy of Mike Campbell,
        # https://github.com/illinois-ceesd/mirgecom/pull/44#discussion_r463304292)

        momerr = fnorm(iff_split.momentum) - p0
        assert momerr < tolerance

        eoc_rec0.add_data_point(1.0 / nel_1d, momerr)

        # Check the boundary facial fluxes as called on a boundary
        dir_mass = discr.project("vol", BTAG_ALL, mass_input)
        dir_e = discr.project("vol", BTAG_ALL, energy_input)
        dir_mom = discr.project("vol", BTAG_ALL, mom_input)

        dir_bval = join_conserved(dim,
                                  mass=dir_mass,
                                  energy=dir_e,
                                  momentum=dir_mom)
        dir_bc = join_conserved(dim,
                                mass=dir_mass,
                                energy=dir_e,
                                momentum=dir_mom)

        boundary_flux = _facial_flux(discr,
                                     eos=IdealSingleGas(),
                                     q_tpair=TracePair(BTAG_ALL,
                                                       interior=dir_bval,
                                                       exterior=dir_bc))

        bf_split = split_conserved(dim, boundary_flux)
        assert fnorm(bf_split.mass) < tolerance
        assert fnorm(bf_split.energy) < tolerance

        momerr = fnorm(bf_split.momentum) - p0
        assert momerr < tolerance

        eoc_rec1.add_data_point(1.0 / nel_1d, momerr)

    message = (f"standalone Errors:\n{eoc_rec0}"
               f"boundary Errors:\n{eoc_rec1}")
    logger.info(message)
    assert (eoc_rec0.order_estimate() >= order - 0.5
            or eoc_rec0.max_error() < 1e-9)
    assert (eoc_rec1.order_estimate() >= order - 0.5
            or eoc_rec1.max_error() < 1e-9)
Beispiel #28
0
def test_mass_surface_area(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)
        surface_area = _ellipse_surface_area(builder.radius,
                                             builder.aspect_ratio)
    elif name == "spheroid":
        from mesh_data import SpheroidMeshBuilder
        builder = SpheroidMeshBuilder()
        surface_area = _spheroid_surface_area(builder.radius,
                                              builder.aspect_ratio)
    elif name == "box2d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=2)
        surface_area = 1.0
    elif name == "box3d":
        from mesh_data import BoxMeshBuilder
        builder = BoxMeshBuilder(ambient_dim=3)
        surface_area = 1.0
    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)
        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 surface area

        dd = dof_desc.DD_VOLUME
        ones_volm = volume_discr.zeros(actx) + 1
        approx_surface_area = actx.to_numpy(op.integral(dcoll, dd, ones_volm))

        logger.info("surface: got {:.5e} / expected {:.5e}".format(
            approx_surface_area, surface_area))
        area_error = abs(approx_surface_area -
                         surface_area) / abs(surface_area)

        # }}}

        # 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, area_error)

    # }}}

    logger.info("surface area error\n%s", str(eoc))

    assert eoc.max_error() < 3e-13 or eoc.order_estimate() > builder.order
Beispiel #29
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)

    # }}}

    # {{{ convergence

    def f(x):
        return flat_obj_array(
            actx.np.sin(3 * x[1]) + actx.np.cos(3 * x[0]) + 1.0,
            actx.np.sin(2 * x[0]) + actx.np.cos(x[1]),
            3.0 * actx.np.cos(x[0] / 2) + actx.np.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
        from meshmode.discretization.connection import FACE_RESTR_ALL

        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

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

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

        dd = dof_desc.DD_VOLUME
        dq = dd.with_discr_tag(qtag)
        df = dof_desc.as_dofdesc(FACE_RESTR_ALL)
        ambient_dim = dcoll.ambient_dim

        # variables
        f_num = f(thaw(dcoll.nodes(dd=dd), actx))
        f_quad_num = f(thaw(dcoll.nodes(dd=dq), actx))

        from grudge.geometry import normal, summed_curvature

        kappa = summed_curvature(actx, dcoll, dd=dq)
        normal = normal(actx, dcoll, dd=dq)
        face_normal = thaw(dcoll.normal(df), actx)
        face_f = op.project(dcoll, dd, df, f_num)

        # operators
        stiff = op.mass(
            dcoll,
            sum(
                op.local_d_dx(dcoll, i, f_num_i)
                for i, f_num_i in enumerate(f_num)))
        stiff_t = sum(
            op.weak_local_d_dx(dcoll, i, f_num_i)
            for i, f_num_i in enumerate(f_num))
        kterm = op.mass(dcoll, dq, kappa * f_quad_num.dot(normal))
        flux = op.face_mass(dcoll, face_f.dot(face_normal))

        # sum everything up
        op_global = op.nodal_sum(dcoll, dd, stiff - (stiff_t + kterm))
        op_local = op.elementwise_sum(dcoll, dd,
                                      stiff - (stiff_t + kterm + flux))

        err_global = abs(op_global)
        err_local = op.norm(dcoll, op_local, np.inf)
        logger.info("errors: global %.5e local %.5e", err_global, err_local)

        # compute max element size
        from grudge.dt_utils import h_max_from_volume

        h_max = h_max_from_volume(dcoll)

        eoc_global.add_data_point(h_max, actx.to_numpy(err_global))
        eoc_local.add_data_point(h_max, err_local)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(dcoll)

            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
Beispiel #30
0
def test_diffusion_accuracy(actx_factory,
                            problem,
                            nsteps,
                            dt,
                            scales,
                            order,
                            visualize=False):
    """
    Checks the accuracy of the diffusion operator by solving the heat equation for a
    given problem setup.
    """
    actx = actx_factory()

    p = problem

    sym_diffusion_u = sym_diffusion(p.dim, p.sym_alpha, p.sym_u)

    # In order to support manufactured solutions, we modify the heat equation
    # to add a source term f. If the solution is exact, this term should be 0.
    sym_t = pmbl.var("t")
    sym_f = sym.diff(sym_t)(p.sym_u) - sym_diffusion_u

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for n in scales:
        mesh = p.get_mesh(n)

        from grudge.eager import EagerDGDiscretization
        from meshmode.discretization.poly_element import \
                QuadratureSimplexGroupFactory, \
                PolynomialWarpAndBlendGroupFactory
        discr = EagerDGDiscretization(
            actx,
            mesh,
            discr_tag_to_group_factory={
                DISCR_TAG_BASE: PolynomialWarpAndBlendGroupFactory(order),
                DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(3 * order),
            })

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

        def sym_eval(expr, t):
            return sym.EvaluationMapper({"x": nodes, "t": t})(expr)

        alpha = sym_eval(p.sym_alpha, 0.)

        if isinstance(alpha, DOFArray):
            discr_tag = DISCR_TAG_QUAD
        else:
            discr_tag = DISCR_TAG_BASE

        def get_rhs(t, u):
            return (
                diffusion_operator(discr,
                                   quad_tag=discr_tag,
                                   alpha=alpha,
                                   boundaries=p.get_boundaries(discr, actx, t),
                                   u=u) + sym_eval(sym_f, t))

        t = 0.

        u = sym_eval(p.sym_u, t)

        from mirgecom.integrators import rk4_step

        for _ in range(nsteps):
            u = rk4_step(u, t, dt, get_rhs)
            t += dt

        expected_u = sym_eval(p.sym_u, t)

        rel_linf_err = (discr.norm(u - expected_u, np.inf) /
                        discr.norm(expected_u, np.inf))
        eoc_rec.add_data_point(1. / n, rel_linf_err)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(discr, discr.order + 3)
            vis.write_vtk_file(
                "diffusion_accuracy_{order}_{n}.vtu".format(order=order, n=n),
                [
                    ("u", u),
                    ("expected_u", expected_u),
                ])

    print("L^inf error:")
    print(eoc_rec)
    # Expected convergence rates from Hesthaven/Warburton book
    expected_order = order + 1 if order % 2 == 0 else order
    assert (eoc_rec.order_estimate() >= expected_order - 0.5
            or eoc_rec.max_error() < 1e-11)
Beispiel #31
0
def test_opposite_face_interpolation(ctx_getter, group_factory, mesh_name, dim,
                                     mesh_pars):
    logging.basicConfig(level=logging.INFO)

    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
        make_face_restriction, make_opposite_face_connection, check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 5

    def f(x):
        return 0.1 * cl.clmath.sin(30 * x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(FileSource("blob-2d.step"),
                                 2,
                                 order=order,
                                 force_ambient_dim=2,
                                 other_options=[
                                     "-string",
                                     "Mesh.CharacteristicLengthMax = %s;" % h
                                 ])
            print("END GEN")
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par)

            h = 1 / mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(cl_ctx, mesh, group_factory(order))
        print("h=%s -> %d elements" %
              (h, sum(mgrp.nelements for mgrp in mesh.groups)))

        bdry_connection = make_face_restriction(vol_discr,
                                                group_factory(order),
                                                FRESTR_INTERIOR_FACES)
        bdry_discr = bdry_connection.to_discr

        opp_face = make_opposite_face_connection(bdry_connection)
        check_connection(opp_face)

        bdry_x = bdry_discr.nodes()[0].with_queue(queue)
        bdry_f = f(bdry_x)

        bdry_f_2 = opp_face(queue, bdry_f)

        err = la.norm((bdry_f - bdry_f_2).get(), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-13)
Beispiel #32
0
def test_all_faces_interpolation(ctx_getter, mesh_name, dim, mesh_pars,
        per_face_groups):
    cl_ctx = ctx_getter()
    queue = cl.CommandQueue(cl_ctx)

    from meshmode.discretization import Discretization
    from meshmode.discretization.connection import (
            make_face_restriction, make_face_to_all_faces_embedding,
            check_connection)

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    order = 4

    def f(x):
        return 0.1*cl.clmath.sin(30*x)

    for mesh_par in mesh_pars:
        # {{{ get mesh

        if mesh_name == "blob":
            assert dim == 2

            h = mesh_par

            from meshmode.mesh.io import generate_gmsh, FileSource
            print("BEGIN GEN")
            mesh = generate_gmsh(
                    FileSource("blob-2d.step"), 2, order=order,
                    force_ambient_dim=2,
                    other_options=[
                        "-string", "Mesh.CharacteristicLengthMax = %s;" % h]
                    )
            print("END GEN")
        elif mesh_name == "warp":
            from meshmode.mesh.generation import generate_warped_rect_mesh
            mesh = generate_warped_rect_mesh(dim, order=4, n=mesh_par)

            h = 1/mesh_par
        else:
            raise ValueError("mesh_name not recognized")

        # }}}

        vol_discr = Discretization(cl_ctx, mesh,
                PolynomialWarpAndBlendGroupFactory(order))
        print("h=%s -> %d elements" % (
                h, sum(mgrp.nelements for mgrp in mesh.groups)))

        all_face_bdry_connection = make_face_restriction(
                vol_discr, PolynomialWarpAndBlendGroupFactory(order),
                FRESTR_ALL_FACES, per_face_groups=per_face_groups)
        all_face_bdry_discr = all_face_bdry_connection.to_discr

        for ito_grp, ceg in enumerate(all_face_bdry_connection.groups):
            for ibatch, batch in enumerate(ceg.batches):
                assert np.array_equal(
                        batch.from_element_indices.get(queue),
                        np.arange(vol_discr.mesh.nelements))

                if per_face_groups:
                    assert ito_grp == batch.to_element_face
                else:
                    assert ibatch == batch.to_element_face

        all_face_x = all_face_bdry_discr.nodes()[0].with_queue(queue)
        all_face_f = f(all_face_x)

        all_face_f_2 = all_face_bdry_discr.zeros(queue)

        for boundary_tag in [
                BTAG_ALL,
                FRESTR_INTERIOR_FACES,
                ]:
            bdry_connection = make_face_restriction(
                    vol_discr, PolynomialWarpAndBlendGroupFactory(order),
                    boundary_tag, per_face_groups=per_face_groups)
            bdry_discr = bdry_connection.to_discr

            bdry_x = bdry_discr.nodes()[0].with_queue(queue)
            bdry_f = f(bdry_x)

            all_face_embedding = make_face_to_all_faces_embedding(
                    bdry_connection, all_face_bdry_discr)

            check_connection(all_face_embedding)

            all_face_f_2 += all_face_embedding(queue, bdry_f)

        err = la.norm((all_face_f-all_face_f_2).get(), np.inf)
        eoc_rec.add_data_point(h, err)

    print(eoc_rec)
    assert (
            eoc_rec.order_estimate() >= order-0.5
            or eoc_rec.max_error() < 1e-14)
Beispiel #33
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
        from meshmode.discretization.connection import FACE_RESTR_ALL

        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 = DiscretizationCollection(actx,
                                         mesh,
                                         order=builder.order,
                                         discr_tag_to_group_factory={
                                             "product":
                                             QuadratureSimplexGroupFactory(
                                                 2 * builder.order)
                                         })

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

        dd = dof_desc.DD_VOLUME
        dq = dd.with_discr_tag("product")
        df = dof_desc.as_dofdesc(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
Beispiel #34
0
def test_uniform_rhs(actx_factory, nspecies, dim, order, use_overintegration):
    """Test the inviscid rhs using a trivial constant/uniform state.

    This state should yield rhs = 0 to FP.  The test is performed for 1, 2,
    and 3 dimensions, with orders 1, 2, and 3, with and without passive species.
    """
    actx = actx_factory()

    tolerance = 1e-9

    from pytools.convergence import EOCRecorder
    eoc_rec0 = EOCRecorder()
    eoc_rec1 = EOCRecorder()
    # for nel_1d in [4, 8, 12]:
    for nel_1d in [4, 8]:
        from meshmode.mesh.generation import generate_regular_rect_mesh
        mesh = generate_regular_rect_mesh(
            a=(-0.5,) * dim, b=(0.5,) * dim, nelements_per_axis=(nel_1d,) * dim
        )

        logger.info(
            f"Number of {dim}d elements: {mesh.nelements}"
        )

        from grudge.dof_desc import DISCR_TAG_BASE, DISCR_TAG_QUAD
        from meshmode.discretization.poly_element import \
            default_simplex_group_factory, QuadratureSimplexGroupFactory

        discr = EagerDGDiscretization(
            actx, mesh,
            discr_tag_to_group_factory={
                DISCR_TAG_BASE: default_simplex_group_factory(
                    base_dim=dim, order=order),
                DISCR_TAG_QUAD: QuadratureSimplexGroupFactory(2*order + 1)
            }
        )

        if use_overintegration:
            quadrature_tag = DISCR_TAG_QUAD
        else:
            quadrature_tag = None

        zeros = discr.zeros(actx)
        ones = zeros + 1.0

        mass_input = discr.zeros(actx) + 1
        energy_input = discr.zeros(actx) + 2.5

        mom_input = make_obj_array(
            [discr.zeros(actx) for i in range(discr.dim)]
        )

        mass_frac_input = flat_obj_array(
            [ones / ((i + 1) * 10) for i in range(nspecies)]
        )
        species_mass_input = mass_input * mass_frac_input
        num_equations = dim + 2 + len(species_mass_input)

        cv = make_conserved(
            dim, mass=mass_input, energy=energy_input, momentum=mom_input,
            species_mass=species_mass_input)
        gas_model = GasModel(eos=IdealSingleGas())
        fluid_state = make_fluid_state(cv, gas_model)

        expected_rhs = make_conserved(
            dim, q=make_obj_array([discr.zeros(actx)
                                   for i in range(num_equations)])
        )

        boundaries = {BTAG_ALL: DummyBoundary()}
        inviscid_rhs = euler_operator(discr, state=fluid_state, gas_model=gas_model,
                                      boundaries=boundaries, time=0.0,
                                      quadrature_tag=quadrature_tag)

        rhs_resid = inviscid_rhs - expected_rhs

        rho_resid = rhs_resid.mass
        rhoe_resid = rhs_resid.energy
        mom_resid = rhs_resid.momentum
        rhoy_resid = rhs_resid.species_mass

        rho_rhs = inviscid_rhs.mass
        rhoe_rhs = inviscid_rhs.energy
        rhov_rhs = inviscid_rhs.momentum
        rhoy_rhs = inviscid_rhs.species_mass

        logger.info(
            f"rho_rhs  = {rho_rhs}\n"
            f"rhoe_rhs = {rhoe_rhs}\n"
            f"rhov_rhs = {rhov_rhs}\n"
            f"rhoy_rhs = {rhoy_rhs}\n"
        )

        def inf_norm(x):
            return actx.to_numpy(discr.norm(x, np.inf))

        assert inf_norm(rho_resid) < tolerance
        assert inf_norm(rhoe_resid) < tolerance
        for i in range(dim):
            assert inf_norm(mom_resid[i]) < tolerance
        for i in range(nspecies):
            assert inf_norm(rhoy_resid[i]) < tolerance

        err_max = inf_norm(rho_resid)
        eoc_rec0.add_data_point(1.0 / nel_1d, err_max)

        # set a non-zero, but uniform velocity component
        for i in range(len(mom_input)):
            mom_input[i] = discr.zeros(actx) + (-1.0) ** i

        cv = make_conserved(
            dim, mass=mass_input, energy=energy_input, momentum=mom_input,
            species_mass=species_mass_input)
        gas_model = GasModel(eos=IdealSingleGas())
        fluid_state = make_fluid_state(cv, gas_model)

        boundaries = {BTAG_ALL: DummyBoundary()}
        inviscid_rhs = euler_operator(discr, state=fluid_state, gas_model=gas_model,
                                      boundaries=boundaries, time=0.0)
        rhs_resid = inviscid_rhs - expected_rhs

        rho_resid = rhs_resid.mass
        rhoe_resid = rhs_resid.energy
        mom_resid = rhs_resid.momentum
        rhoy_resid = rhs_resid.species_mass

        assert inf_norm(rho_resid) < tolerance
        assert inf_norm(rhoe_resid) < tolerance

        for i in range(dim):
            assert inf_norm(mom_resid[i]) < tolerance
        for i in range(nspecies):
            assert inf_norm(rhoy_resid[i]) < tolerance

        err_max = inf_norm(rho_resid)
        eoc_rec1.add_data_point(1.0 / nel_1d, err_max)

    logger.info(
        f"V == 0 Errors:\n{eoc_rec0}"
        f"V != 0 Errors:\n{eoc_rec1}"
    )

    assert (
        eoc_rec0.order_estimate() >= order - 0.5
        or eoc_rec0.max_error() < 1e-9
    )
    assert (
        eoc_rec1.order_estimate() >= order - 0.5
        or eoc_rec1.max_error() < 1e-9
    )