예제 #1
0
def test_inviscid_flux(actx_factory, dim):
    """Identity test - directly check inviscid flux
    routine :func:`mirgecom.euler.inviscid_flux` against the exact
    expected result. This test is designed to fail
    if the flux routine is broken.
    The expected inviscid flux is:
      F(q) = <rhoV, (E+p)V, rho(V.x.V) + pI>
    """
    actx = actx_factory()

    nel_1d = 16

    from meshmode.mesh.generation import generate_regular_rect_mesh

    #    for dim in [1, 2, 3]:
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                      b=(0.5, ) * dim,
                                      n=(nel_1d, ) * dim)

    order = 3
    discr = EagerDGDiscretization(actx, mesh, order=order)
    eos = IdealSingleGas()

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

    mass = cl.clrandom.rand(actx.queue, (mesh.nelements, ), dtype=np.float64)
    energy = cl.clrandom.rand(actx.queue, (mesh.nelements, ), dtype=np.float64)
    mom = make_obj_array([
        cl.clrandom.rand(actx.queue, (mesh.nelements, ), dtype=np.float64)
        for i in range(dim)
    ])

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

    # {{{ create the expected result

    p = eos.pressure(cv)
    escale = (energy + p) / mass

    expected_flux = np.zeros((dim + 2, dim), dtype=object)
    expected_flux[0] = mom
    expected_flux[1] = mom * make_obj_array([escale])

    for i in range(dim):
        for j in range(dim):
            expected_flux[2 + i,
                          j] = (mom[i] * mom[j] / mass + (p if i == j else 0))

    # }}}

    from mirgecom.euler import inviscid_flux

    flux = inviscid_flux(discr, eos, q)
    flux_resid = flux - expected_flux

    for i in range(dim + 2, dim):
        for j in range(dim):
            assert (la.norm(flux_resid[i, j].get())) == 0.0
예제 #2
0
def test_inviscid_flux_components(actx_factory, dim):
    """Test uniform pressure case.

    Checks that the Euler-internal inviscid flux routine
    :func:`mirgecom.inviscid.inviscid_flux` returns exactly the expected result
    with a constant pressure and no flow.

    Expected inviscid flux is:
      F(q) = <rhoV, (E+p)V, rho(V.x.V) + pI>

    Checks that only diagonal terms of the momentum flux:
      [ rho(V.x.V) + pI ] are non-zero and return the correctly calculated p.
    """
    actx = actx_factory()

    eos = IdealSingleGas()

    p0 = 1.0

    nel_1d = 4

    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)

    order = 3
    discr = EagerDGDiscretization(actx, mesh, order=order)
    eos = IdealSingleGas()

    logger.info(f"Number of {dim}d elems: {mesh.nelements}")
    # === this next block tests 1,2,3 dimensions,
    # with single and multiple nodes/states. The
    # purpose of this block is to ensure that when
    # all components of V = 0, the flux recovers
    # the expected values (and p0 within tolerance)
    # === with V = 0, fixed P = p0
    tolerance = 1e-15
    nodes = thaw(actx, discr.nodes())
    mass = discr.zeros(actx) + np.dot(nodes, nodes) + 1.0
    mom = make_obj_array([discr.zeros(actx) for _ in range(dim)])
    p_exact = discr.zeros(actx) + p0
    energy = p_exact / 0.4 + 0.5 * np.dot(mom, mom) / mass
    cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
    p = eos.pressure(cv)
    flux = inviscid_flux(discr, eos, cv)
    assert discr.norm(p - p_exact, np.inf) < tolerance
    logger.info(f"{dim}d flux = {flux}")

    # for velocity zero, these components should be == zero
    assert discr.norm(flux.mass, 2) == 0.0
    assert discr.norm(flux.energy, 2) == 0.0

    # The momentum diagonal should be p
    # Off-diagonal should be identically 0
    assert discr.norm(flux.momentum - p0 * np.identity(dim),
                      np.inf) < tolerance
예제 #3
0
def test_idealsingle_lump(ctx_factory):
    """Test EOS with mass lump.

    Tests that the IdealSingleGas EOS returns
    the correct (uniform) pressure for the Lump
    solution field.
    """
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    dim = 2
    nel_1d = 4

    from meshmode.mesh.generation import generate_regular_rect_mesh

    mesh = generate_regular_rect_mesh(a=[(0.0, ), (-5.0, )],
                                      b=[(10.0, ), (5.0, )],
                                      n=(nel_1d, ) * dim)

    order = 3
    logger.info(f"Number of elements {mesh.nelements}")

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

    # Init soln with Vortex
    center = np.zeros(shape=(dim, ))
    velocity = np.zeros(shape=(dim, ))
    center[0] = 5
    velocity[0] = 1
    lump = Lump(center=center, velocity=velocity)
    eos = IdealSingleGas()
    lump_soln = lump(0, nodes)

    cv = split_conserved(dim, lump_soln)
    p = eos.pressure(cv)
    exp_p = 1.0
    errmax = discr.norm(p - exp_p, np.inf)

    exp_ke = 0.5 * cv.mass
    ke = eos.kinetic_energy(cv)
    kerr = discr.norm(ke - exp_ke, np.inf)

    te = eos.total_energy(cv, p)
    terr = discr.norm(te - cv.energy, np.inf)

    logger.info(f"lump_soln = {lump_soln}")
    logger.info(f"pressure = {p}")

    assert errmax < 1e-15
    assert kerr < 1e-15
    assert terr < 1e-15
예제 #4
0
def test_inviscid_mom_flux_components(actx_factory, dim, livedim):
    r"""Test components of the momentum flux with constant pressure, V != 0.

    Checks that the flux terms are returned in the proper order by running
    only 1 non-zero velocity component at-a-time.
    """
    actx = actx_factory()

    eos = IdealSingleGas()

    p0 = 1.0

    nel_1d = 4

    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)

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

    tolerance = 1e-15
    for livedim in range(dim):
        mass = discr.zeros(actx) + 1.0 + np.dot(nodes, nodes)
        mom = make_obj_array([discr.zeros(actx) for _ in range(dim)])
        mom[livedim] = mass
        p_exact = discr.zeros(actx) + p0
        energy = (p_exact / (eos.gamma() - 1.0) +
                  0.5 * np.dot(mom, mom) / mass)
        cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
        p = eos.pressure(cv)
        from mirgecom.gas_model import GasModel, make_fluid_state
        state = make_fluid_state(cv, GasModel(eos=eos))

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

        assert inf_norm(p - p_exact) < tolerance
        flux = inviscid_flux(state)
        logger.info(f"{dim}d flux = {flux}")
        vel_exact = mom / mass

        # first two components should be nonzero in livedim only
        assert inf_norm(flux.mass - mom) == 0
        eflux_exact = (energy + p_exact) * vel_exact
        assert inf_norm(flux.energy - eflux_exact) == 0

        logger.info("Testing momentum")
        xpmomflux = mass * np.outer(vel_exact,
                                    vel_exact) + p_exact * np.identity(dim)
        assert inf_norm(flux.momentum - xpmomflux) < tolerance
예제 #5
0
def test_idealsingle_lump(ctx_factory, dim):
    """Test IdealSingle EOS with mass lump.

    Tests that the IdealSingleGas EOS returns the correct (uniform) pressure for the
    Lump solution field.
    """
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    nel_1d = 4

    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)

    order = 3
    logger.info(f"Number of elements {mesh.nelements}")

    discr = EagerDGDiscretization(actx, mesh, order=order)
    from meshmode.dof_array import thaw
    nodes = thaw(actx, discr.nodes())

    # Init soln with Vortex
    center = np.zeros(shape=(dim, ))
    velocity = np.zeros(shape=(dim, ))
    velocity[0] = 1
    lump = Lump(dim=dim, center=center, velocity=velocity)
    eos = IdealSingleGas()
    cv = lump(nodes)

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

    p = eos.pressure(cv)
    exp_p = 1.0
    errmax = inf_norm(p - exp_p)

    exp_ke = 0.5 * cv.mass
    ke = eos.kinetic_energy(cv)
    kerr = inf_norm(ke - exp_ke)

    te = eos.total_energy(cv, p)
    terr = inf_norm(te - cv.energy)

    logger.info(f"lump_soln = {cv}")
    logger.info(f"pressure = {p}")

    assert errmax < 1e-15
    assert kerr < 1e-15
    assert terr < 1e-15
예제 #6
0
def test_idealsingle_vortex(ctx_factory):
    r"""Test EOS with isentropic vortex.

    Tests that the IdealSingleGas EOS returns the correct pressure (p) for the
    Vortex2D solution field (i.e. $p = \rho^{\gamma}$).
    """
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    dim = 2
    nel_1d = 4

    from meshmode.mesh.generation import generate_regular_rect_mesh

    mesh = generate_regular_rect_mesh(a=[(0.0, ), (-5.0, )],
                                      b=[(10.0, ), (5.0, )],
                                      nelements_per_axis=(nel_1d, ) * dim)

    order = 3
    logger.info(f"Number of elements {mesh.nelements}")

    discr = EagerDGDiscretization(actx, mesh, order=order)
    from meshmode.dof_array import thaw
    nodes = thaw(actx, discr.nodes())
    eos = IdealSingleGas()
    # Init soln with Vortex
    vortex = Vortex2D()
    cv = vortex(nodes)

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

    gamma = eos.gamma()
    p = eos.pressure(cv)
    exp_p = cv.mass**gamma
    errmax = inf_norm(p - exp_p)

    exp_ke = 0.5 * np.dot(cv.momentum, cv.momentum) / cv.mass
    ke = eos.kinetic_energy(cv)
    kerr = inf_norm(ke - exp_ke)

    te = eos.total_energy(cv, p)
    terr = inf_norm(te - cv.energy)

    logger.info(f"vortex_soln = {cv}")
    logger.info(f"pressure = {p}")

    assert errmax < 1e-15
    assert kerr < 1e-15
    assert terr < 1e-15
예제 #7
0
def test_uniform(ctx_factory, dim):
    """
    Simple test to check that Uniform initializer
    creates the expected solution field.
    """
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    nel_1d = 2

    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)

    order = 1
    print(f"Number of elements: {mesh.nelements}")

    discr = EagerDGDiscretization(actx, mesh, order=order)
    nodes = thaw(actx, discr.nodes())
    print(f"DIM = {dim}, {len(nodes)}")
    print(f"Nodes={nodes}")

    from mirgecom.initializers import Uniform
    initr = Uniform(dim=dim)
    initsoln = initr(time=0.0, x_vec=nodes)
    tol = 1e-15

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

    assert inf_norm(initsoln.mass - 1.0) < tol
    assert inf_norm(initsoln.energy - 2.5) < tol

    print(f"Uniform Soln:{initsoln}")
    eos = IdealSingleGas()
    p = eos.pressure(initsoln)
    print(f"Press:{p}")

    assert inf_norm(p - 1.0) < tol
예제 #8
0
def test_idealsingle_vortex(ctx_factory):
    r"""
    Tests that the IdealSingleGas EOS returns
    the correct pressure (p) for the Vortex2D solution
    field (i.e. :math:'p = \rho^{\gamma}').
    """
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    dim = 2
    nel_1d = 4

    from meshmode.mesh.generation import generate_regular_rect_mesh

    mesh = generate_regular_rect_mesh(a=[(0.0, ), (-5.0, )],
                                      b=[(10.0, ), (5.0, )],
                                      n=(nel_1d, ) * dim)

    order = 3
    logger.info(f"Number of elements {mesh.nelements}")

    discr = EagerDGDiscretization(actx, mesh, order=order)
    nodes = thaw(actx, discr.nodes())
    eos = IdealSingleGas()
    # Init soln with Vortex
    vortex = Vortex2D()
    vortex_soln = vortex(0, nodes)
    cv = split_conserved(dim, vortex_soln)
    gamma = eos.gamma()
    p = eos.pressure(cv)
    exp_p = cv.mass**gamma
    errmax = discr.norm(p - exp_p, np.inf)

    logger.info(f"vortex_soln = {vortex_soln}")
    logger.info(f"pressure = {p}")

    assert errmax < 1e-15
예제 #9
0
def test_shock_init(ctx_factory):
    """
    Simple test to check that Shock1D initializer
    creates the expected solution field.
    """
    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    nel_1d = 10
    dim = 2

    from meshmode.mesh.generation import generate_regular_rect_mesh

    mesh = generate_regular_rect_mesh(a=[(0.0, ), (1.0, )],
                                      b=[(-0.5, ), (0.5, )],
                                      nelements_per_axis=(nel_1d, ) * dim)

    order = 3
    print(f"Number of elements: {mesh.nelements}")

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

    initr = SodShock1D()
    initsoln = initr(time=0.0, x_vec=nodes)
    print("Sod Soln:", initsoln)

    xpl = 1.0
    xpr = 0.1
    tol = 1e-15
    nodes_x = nodes[0]
    eos = IdealSingleGas()
    p = eos.pressure(initsoln)

    assert actx.to_numpy(
        discr.norm(actx.np.where(nodes_x < 0.5, p - xpl, p - xpr),
                   np.inf)) < tol
예제 #10
0
def test_inviscid_mom_flux_components(actx_factory, dim, livedim):
    r"""Constant pressure, V != 0:
    Checks that the flux terms are returned in the proper
    order by running only 1 non-zero velocity component at-a-time.
    """
    actx = actx_factory()

    eos = IdealSingleGas()

    p0 = 1.0

    from mirgecom.euler import inviscid_flux

    tolerance = 1e-15
    for livedim in range(dim):
        for ntestnodes in [1, 10]:
            discr = MyDiscr(dim, ntestnodes)
            mass = discr.zeros(actx)
            mass_values = np.empty((1, ntestnodes), dtype=np.float64)
            mass_values[0] = np.linspace(1.,
                                         ntestnodes,
                                         ntestnodes,
                                         dtype=np.float64)
            mass[0].set(mass_values)
            mom = make_obj_array([discr.zeros(actx) for _ in range(dim)])
            mom[livedim] = mass
            p = discr.zeros(actx) + p0
            energy = (p / (eos.gamma() - 1.0) + 0.5 * np.dot(mom, mom) / mass)
            q = join_conserved(dim, mass=mass, energy=energy, momentum=mom)
            cv = split_conserved(dim, q)
            p = eos.pressure(cv)

            flux = inviscid_flux(discr, eos, q)

            logger.info(f"{dim}d flux = {flux}")

            # first two components should be nonzero in livedim only
            expected_flux = mom
            logger.info("Testing continuity")
            for i in range(dim):
                assert la.norm((flux[0, i] - expected_flux[i])[0].get()) == 0.0
                if i != livedim:
                    assert la.norm(flux[0, i][0].get()) == 0.0
                else:
                    assert la.norm(flux[0, i][0].get()) > 0.0

            logger.info("Testing energy")
            expected_flux = mom * (energy + p) / mass
            for i in range(dim):
                assert la.norm((flux[1, i] - expected_flux[i])[0].get()) == 0.0
                if i != livedim:
                    assert la.norm(flux[1, i][0].get()) == 0.0
                else:
                    assert la.norm(flux[1, i][0].get()) > 0.0

            logger.info("Testing momentum")
            xpmomflux = make_obj_array([
                (mom[i] * mom[j] / mass + (p if i == j else 0))
                for i in range(dim) for j in range(dim)
            ])

            for i in range(dim):
                expected_flux = xpmomflux[i * dim:(i + 1) * dim]
                for j in range(dim):
                    assert la.norm(
                        (flux[2 + i, j] - expected_flux[j])[0].get()) == 0
                    if i == j:
                        if i == livedim:
                            assert (la.norm(flux[2 + i, j][0].get()) > 0.0)
                        else:
                            # just for sanity - make sure the flux recovered the
                            # prescribed value of p0 (within fp tol)
                            assert (np.abs(flux[2 + i, j][0].get() - p0) <
                                    tolerance).all()
                    else:
                        assert la.norm(flux[2 + i, j][0].get()) == 0.0
예제 #11
0
def test_inviscid_flux_components(actx_factory, dim):
    """Uniform pressure test

    Checks that the Euler-internal inviscid flux
    routine :func:`mirgecom.euler.inviscid_flux` returns exactly the
    expected result with a constant pressure and
    no flow.
    Expected inviscid flux is:
      F(q) = <rhoV, (E+p)V, rho(V.x.V) + pI>

    Checks that only diagonal terms of the momentum flux:
      [ rho(V.x.V) + pI ]
    are non-zero and return the correctly calculated p.
    """
    actx = actx_factory()

    eos = IdealSingleGas()

    from mirgecom.euler import inviscid_flux

    p0 = 1.0

    # === this next block tests 1,2,3 dimensions,
    # with single and multiple nodes/states. The
    # purpose of this block is to ensure that when
    # all components of V = 0, the flux recovers
    # the expected values (and p0 within tolerance)
    # === with V = 0, fixed P = p0
    tolerance = 1e-15
    for ntestnodes in [1, 10]:
        discr = MyDiscr(dim, ntestnodes)
        mass = discr.zeros(actx)
        mass_values = np.empty((1, ntestnodes), dtype=np.float64)
        mass_values[0] = np.linspace(1.,
                                     ntestnodes,
                                     ntestnodes,
                                     dtype=np.float64)
        mass[0].set(mass_values)
        mom = make_obj_array([discr.zeros(actx) for _ in range(dim)])
        p = discr.zeros(actx) + p0
        energy = p / 0.4 + 0.5 * np.dot(mom, mom) / mass
        q = join_conserved(dim, mass=mass, energy=energy, momentum=mom)
        cv = split_conserved(dim, q)
        p = eos.pressure(cv)
        flux = inviscid_flux(discr, eos, q)

        logger.info(f"{dim}d flux = {flux}")

        # for velocity zero, these components should be == zero
        for i in range(2):
            for j in range(dim):
                assert (flux[i, j][0].get() == 0.0).all()

        # The momentum diagonal should be p
        # Off-diagonal should be identically 0
        for i in range(dim):
            for j in range(dim):
                print(f"(i,j) = ({i},{j})")
                if i != j:
                    assert (flux[2 + i, j][0].get() == 0.0).all()
                else:
                    assert (flux[2 + i, j] == p)[0].get().all()
                    assert (np.abs(flux[2 + i, j][0].get() - p0) <
                            tolerance).all()
예제 #12
0
def test_basic_cfd_healthcheck(actx_factory):
    """Quick test of some health checking utilities."""
    actx = actx_factory()
    nel_1d = 4
    dim = 2

    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
    )

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

    # Let's make a very bad state (negative mass)
    mass = -1*ones
    velocity = 2 * nodes
    mom = mass * velocity
    energy = zeros + .5*np.dot(mom, mom)/mass

    eos = IdealSingleGas()
    cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
    pressure = eos.pressure(cv)

    from mirgecom.simutil import check_range_local
    assert check_range_local(discr, "vol", mass, min_value=0, max_value=np.inf)
    assert check_range_local(discr, "vol", pressure, min_value=1e-6,
                             max_value=np.inf)

    # Let's make another very bad state (nans)
    mass = 1*ones
    energy = zeros + 2.5
    velocity = np.nan * nodes
    mom = mass * velocity

    cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
    pressure = eos.pressure(cv)

    from mirgecom.simutil import check_naninf_local
    assert check_naninf_local(discr, "vol", pressure)

    # Let's make one last very bad state (inf)
    mass = 1*ones
    energy = np.inf * ones
    velocity = 2 * nodes
    mom = mass * velocity

    cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
    pressure = eos.pressure(cv)

    assert check_naninf_local(discr, "vol", pressure)

    # What the hey, test a good one
    energy = 2.5 + .5*np.dot(mom, mom)
    cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
    pressure = eos.pressure(cv)

    assert not check_naninf_local(discr, "vol", pressure)
    assert not check_range_local(discr, "vol", pressure, min_value=0,
                                 max_value=np.inf)
예제 #13
0
def test_inviscid_mom_flux_components(actx_factory, dim, livedim):
    r"""Constant pressure, V != 0:
    Checks that the flux terms are returned in the proper
    order by running only 1 non-zero velocity component at-a-time.
    """

    queue = actx_factory().queue

    eos = IdealSingleGas()

    class MyDiscr:
        def __init__(self, dim=1):
            self.dim = dim

    p0 = 1.0

    from mirgecom.euler import inviscid_flux

    tolerance = 1e-15
    for livedim in range(dim):
        for ntestnodes in [1, 10]:
            fake_dis = MyDiscr(dim)
            mass = cl.clrandom.rand(queue, (ntestnodes, ), dtype=np.float64)
            energy = cl.clrandom.rand(queue, (ntestnodes, ), dtype=np.float64)
            mom = make_obj_array([
                cl.clrandom.rand(queue, (ntestnodes, ), dtype=np.float64)
                for i in range(dim)
            ])
            p = cl.clrandom.rand(queue, (ntestnodes, ), dtype=np.float64)

            for i in range(ntestnodes):
                mass[i] = 1.0 + i
                p[i] = p0
                for j in range(dim):
                    mom[j][i] = 0.0 * mass[i]
                    mom[livedim][i] = mass[i]
            energy = (p / (eos.gamma() - 1.0) + 0.5 * np.dot(mom, mom) / mass)
            q = join_conserved(dim, mass=mass, energy=energy, momentum=mom)
            cv = split_conserved(dim, q)
            p = eos.pressure(cv)

            flux = inviscid_flux(fake_dis, eos, q)

            logger.info(f"{dim}d flux = {flux}")

            # first two components should be nonzero in livedim only
            expected_flux = mom
            logger.info("Testing continuity")
            for i in range(dim):
                assert la.norm((flux[0, i] - expected_flux[i]).get()) == 0.0
                if i != livedim:
                    assert la.norm(flux[0, i].get()) == 0.0
                else:
                    assert la.norm(flux[0, i].get()) > 0.0

            logger.info("Testing energy")
            expected_flux = mom * make_obj_array([(energy + p) / mass])
            for i in range(dim):
                assert la.norm((flux[1, i] - expected_flux[i]).get()) == 0.0
                if i != livedim:
                    assert la.norm(flux[1, i].get()) == 0.0
                else:
                    assert la.norm(flux[1, i].get()) > 0.0

            logger.info("Testing momentum")
            xpmomflux = make_obj_array([
                (mom[i] * mom[j] / mass + (p if i == j else 0))
                for i in range(dim) for j in range(dim)
            ])

            for i in range(dim):
                expected_flux = xpmomflux[i * dim:(i + 1) * dim]
                for j in range(dim):
                    assert la.norm(
                        (flux[2 + i, j] - expected_flux[j]).get()) == 0
                    if i == j:
                        if i == livedim:
                            assert (la.norm(flux[2 + i, j].get()) > 0.0)
                        else:
                            # just for sanity - make sure the flux recovered the
                            # prescribed value of p0 (within fp tol)
                            for k in range(ntestnodes):
                                assert np.abs(flux[2 + i, j][k] -
                                              p0) < tolerance
                    else:
                        assert la.norm(flux[2 + i, j].get()) == 0.0
예제 #14
0
def test_inviscid_flux(actx_factory, nspecies, dim):
    """Check inviscid flux against exact expected result: Identity test.

    Directly check inviscid flux routine, :func:`mirgecom.inviscid.inviscid_flux`,
    against the exact expected result. This test is designed to fail if the flux
    routine is broken.

    The expected inviscid flux is:
      F(q) = <rhoV, (E+p)V, rho(V.x.V) + pI, rhoY V>
    """
    actx = actx_factory()

    nel_1d = 16

    from meshmode.mesh.generation import generate_regular_rect_mesh

    #    for dim in [1, 2, 3]:
    mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim,
                                      b=(0.5, ) * dim,
                                      nelements_per_axis=(nel_1d, ) * dim)

    order = 3
    discr = EagerDGDiscretization(actx, mesh, order=order)
    eos = IdealSingleGas()

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

    def rand():
        from meshmode.dof_array import DOFArray
        return DOFArray(
            actx,
            tuple(
                actx.from_numpy(np.random.rand(grp.nelements, grp.nunit_dofs))
                for grp in discr.discr_from_dd("vol").groups))

    mass = rand()
    energy = rand()
    mom = make_obj_array([rand() for _ in range(dim)])

    mass_fractions = make_obj_array([rand() for _ in range(nspecies)])
    species_mass = mass * mass_fractions

    cv = make_conserved(dim,
                        mass=mass,
                        energy=energy,
                        momentum=mom,
                        species_mass=species_mass)

    # {{{ create the expected result

    p = eos.pressure(cv)
    escale = (energy + p) / mass

    numeq = dim + 2 + nspecies

    expected_flux = np.zeros((numeq, dim), dtype=object)
    expected_flux[0] = mom
    expected_flux[1] = mom * escale

    for i in range(dim):
        for j in range(dim):
            expected_flux[2 + i,
                          j] = (mom[i] * mom[j] / mass + (p if i == j else 0))

    for i in range(nspecies):
        expected_flux[dim + 2 + i] = mom * mass_fractions[i]

    expected_flux = make_conserved(dim, q=expected_flux)

    # }}}

    from mirgecom.gas_model import GasModel, make_fluid_state
    gas_model = GasModel(eos=eos)
    state = make_fluid_state(cv, gas_model)

    flux = inviscid_flux(state)
    flux_resid = flux - expected_flux

    for i in range(numeq, dim):
        for j in range(dim):
            assert (la.norm(flux_resid[i, j].get())) == 0.0
예제 #15
0
def test_poiseuille_fluxes(actx_factory, order, kappa):
    """Test the viscous fluxes using a Poiseuille input state."""
    actx = actx_factory()
    dim = 2

    from pytools.convergence import EOCRecorder
    e_eoc_rec = EOCRecorder()
    p_eoc_rec = EOCRecorder()

    base_pressure = 100000.0
    pressure_ratio = 1.001
    mu = 42  # arbitrary
    left_boundary_location = 0
    right_boundary_location = 0.1
    ybottom = 0.
    ytop = .02
    nspecies = 0
    spec_diffusivity = 0 * np.ones(nspecies)
    transport_model = SimpleTransport(viscosity=mu,
                                      thermal_conductivity=kappa,
                                      species_diffusivity=spec_diffusivity)

    xlen = right_boundary_location - left_boundary_location
    p_low = base_pressure
    p_hi = pressure_ratio * base_pressure
    dpdx = (p_low - p_hi) / xlen
    rho = 1.0

    eos = IdealSingleGas()
    gas_model = GasModel(eos=eos, transport=transport_model)

    from mirgecom.initializers import PlanarPoiseuille
    initializer = PlanarPoiseuille(density=rho, mu=mu)

    def _elbnd_flux(discr, compute_interior_flux, compute_boundary_flux,
                    int_tpair, boundaries):
        return (compute_interior_flux(int_tpair) +
                sum(compute_boundary_flux(btag) for btag in boundaries))

    from mirgecom.flux import gradient_flux_central

    def cv_flux_interior(int_tpair):
        normal = thaw(actx, discr.normal(int_tpair.dd))
        flux_weak = gradient_flux_central(int_tpair, normal)
        dd_all_faces = int_tpair.dd.with_dtag("all_faces")
        return discr.project(int_tpair.dd, dd_all_faces, flux_weak)

    def cv_flux_boundary(btag):
        boundary_discr = discr.discr_from_dd(btag)
        bnd_nodes = thaw(actx, boundary_discr.nodes())
        cv_bnd = initializer(x_vec=bnd_nodes, eos=eos)
        bnd_nhat = thaw(actx, discr.normal(btag))
        from grudge.trace_pair import TracePair
        bnd_tpair = TracePair(btag, interior=cv_bnd, exterior=cv_bnd)
        flux_weak = gradient_flux_central(bnd_tpair, bnd_nhat)
        dd_all_faces = bnd_tpair.dd.with_dtag("all_faces")
        return discr.project(bnd_tpair.dd, dd_all_faces, flux_weak)

    for nfac in [1, 2, 4]:

        npts_axis = nfac * (11, 21)
        box_ll = (left_boundary_location, ybottom)
        box_ur = (right_boundary_location, ytop)
        mesh = _get_box_mesh(2, a=box_ll, b=box_ur, n=npts_axis)

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

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

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

        # compute max element size
        from grudge.dt_utils import h_max_from_volume
        h_max = h_max_from_volume(discr)

        # form exact cv
        cv = initializer(x_vec=nodes, eos=eos)
        cv_int_tpair = interior_trace_pair(discr, cv)
        boundaries = [BTAG_ALL]
        cv_flux_bnd = _elbnd_flux(discr, cv_flux_interior, cv_flux_boundary,
                                  cv_int_tpair, boundaries)
        from mirgecom.operators import grad_operator
        from grudge.dof_desc import as_dofdesc
        dd_vol = as_dofdesc("vol")
        dd_faces = as_dofdesc("all_faces")
        grad_cv = grad_operator(discr, dd_vol, dd_faces, cv, cv_flux_bnd)

        xp_grad_cv = initializer.exact_grad(x_vec=nodes, eos=eos, cv_exact=cv)
        xp_grad_v = 1 / cv.mass * xp_grad_cv.momentum
        xp_tau = mu * (xp_grad_v + xp_grad_v.transpose())

        # sanity check the gradient:
        relerr_scale_e = 1.0 / inf_norm(xp_grad_cv.energy)
        relerr_scale_p = 1.0 / inf_norm(xp_grad_cv.momentum)
        graderr_e = inf_norm(grad_cv.energy - xp_grad_cv.energy)
        graderr_p = inf_norm(grad_cv.momentum - xp_grad_cv.momentum)
        graderr_e *= relerr_scale_e
        graderr_p *= relerr_scale_p
        assert graderr_e < 5e-7
        assert graderr_p < 5e-11

        zeros = discr.zeros(actx)
        ones = zeros + 1
        pressure = eos.pressure(cv)
        # grad of p should be dp/dx
        xp_grad_p = make_obj_array([dpdx * ones, zeros])
        grad_p = op.local_grad(discr, pressure)
        dpscal = 1.0 / np.abs(dpdx)

        temperature = eos.temperature(cv)
        tscal = rho * eos.gas_const() * dpscal
        xp_grad_t = xp_grad_p / (cv.mass * eos.gas_const())
        grad_t = op.local_grad(discr, temperature)

        # sanity check
        assert inf_norm(grad_p - xp_grad_p) * dpscal < 5e-9
        assert inf_norm(grad_t - xp_grad_t) * tscal < 5e-9

        fluid_state = make_fluid_state(cv, gas_model)
        # verify heat flux
        from mirgecom.viscous import conductive_heat_flux
        heat_flux = conductive_heat_flux(fluid_state, grad_t)
        xp_heat_flux = -kappa * xp_grad_t
        assert inf_norm(heat_flux - xp_heat_flux) < 2e-8

        xp_e_flux = np.dot(xp_tau, cv.velocity) - xp_heat_flux
        xp_mom_flux = xp_tau
        from mirgecom.viscous import viscous_flux
        vflux = viscous_flux(fluid_state, grad_cv, grad_t)

        efluxerr = (inf_norm(vflux.energy - xp_e_flux) / inf_norm(xp_e_flux))
        momfluxerr = (inf_norm(vflux.momentum - xp_mom_flux) /
                      inf_norm(xp_mom_flux))

        assert inf_norm(vflux.mass) == 0
        e_eoc_rec.add_data_point(actx.to_numpy(h_max), efluxerr)
        p_eoc_rec.add_data_point(actx.to_numpy(h_max), momfluxerr)

    assert (e_eoc_rec.order_estimate() >= order - 0.5
            or e_eoc_rec.max_error() < 3e-9)
    assert (p_eoc_rec.order_estimate() >= order - 0.5
            or p_eoc_rec.max_error() < 2e-12)