Beispiel #1
0
    def __call__(self, x_vec, *, t=0, eos=None):
        """
        Create a uniform flow solution at locations *x_vec*.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired (unused)
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.IdealSingleGas`
            Equation of state class with method to supply gas *gamma*.
        """
        if eos is None:
            eos = IdealSingleGas()

        gamma = eos.gamma()
        mass = 0.0 * x_vec[0] + self._rho
        mom = self._velocity * mass
        energy = (self._p / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass)
        species_mass = self._mass_fracs * mass

        return make_conserved(dim=self._dim,
                              mass=mass,
                              energy=energy,
                              momentum=mom,
                              species_mass=species_mass)
Beispiel #2
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
Beispiel #3
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
Beispiel #4
0
def test_viscous_timestep(actx_factory, dim, mu, vel):
    """Test timestep size."""
    actx = actx_factory()
    nel_1d = 4

    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 = 1

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

    velocity = make_obj_array([zeros + vel for _ in range(dim)])

    massval = 1
    mass = massval * ones

    # I *think* this energy should yield c=1.0
    energy = zeros + 1.0 / (1.4 * .4)
    mom = mass * velocity
    species_mass = None

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

    from grudge.dt_utils import characteristic_lengthscales
    chlen = characteristic_lengthscales(actx, discr)
    from grudge.op import nodal_min
    chlen_min = nodal_min(discr, "vol", chlen)

    mu = mu * chlen_min
    if mu < 0:
        mu = 0
        tv_model = None
    else:
        tv_model = SimpleTransport(viscosity=mu)

    eos = IdealSingleGas(transport_model=tv_model)

    from mirgecom.viscous import get_viscous_timestep
    dt_field = get_viscous_timestep(discr, eos, cv)

    speed_total = actx.np.sqrt(np.dot(velocity,
                                      velocity)) + eos.sound_speed(cv)
    dt_expected = chlen / (speed_total + (mu / chlen))

    error = (dt_expected - dt_field) / dt_expected
    assert discr.norm(error, np.inf) == 0
Beispiel #5
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
Beispiel #6
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
Beispiel #7
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
Beispiel #8
0
    def __call__(self, t, x_vec, eos=IdealSingleGas()):
        """
        Create the lump-of-mass solution at time *t* and locations *x_vec*.

        Note that *t* is used to advect the mass lump under the assumption of
        constant, and uniform velocity.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.GasEOS`
            Equation of state class to be used in construction of soln (if needed)
        """
        lump_loc = self._center + t * self._velocity
        assert len(x_vec) == self._dim
        # coordinates relative to lump center
        rel_center = make_obj_array(
            [x_vec[i] - lump_loc[i] for i in range(self._dim)]
        )
        actx = x_vec[0].array_context
        r = actx.np.sqrt(np.dot(rel_center, rel_center))

        gamma = eos.gamma()
        expterm = self._rhoamp * actx.np.exp(1 - r ** 2)
        mass = expterm + self._rho0
        mom = self._velocity * mass
        energy = (self._p0 / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass)

        return flat_obj_array(mass, energy, mom)
Beispiel #9
0
    def __call__(self, t, x_vec, eos=IdealSingleGas()):
        """
        Create the isentropic vortex solution at time *t* at locations *x_vec*.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired.
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.GasEOS`
            Equation of state class to be used in construction of soln (if needed)
        """
        vortex_loc = self._center + t * self._velocity

        # coordinates relative to vortex center
        x_rel = x_vec[0] - vortex_loc[0]
        y_rel = x_vec[1] - vortex_loc[1]
        actx = x_vec[0].array_context
        gamma = eos.gamma()
        r = actx.np.sqrt(x_rel ** 2 + y_rel ** 2)
        expterm = self._beta * actx.np.exp(1 - r ** 2)
        u = self._velocity[0] - expterm * y_rel / (2 * np.pi)
        v = self._velocity[1] + expterm * x_rel / (2 * np.pi)
        mass = (1 - (gamma - 1) / (16 * gamma * np.pi ** 2)
                * expterm ** 2) ** (1 / (gamma - 1))
        p = mass ** gamma

        e = p / (gamma - 1) + mass / 2 * (u ** 2 + v ** 2)

        return flat_obj_array(mass, e, mass * u, mass * v)
Beispiel #10
0
    def __call__(self, x_vec, *, t=0, eos=None):
        """
        Create a multi-component lump solution at time *t* and locations *x_vec*.

        The solution at time *t* is created by advecting the component mass lump
        at the user-specified constant, uniform velocity
        (``MulticomponentLump._velocity``).

        Parameters
        ----------
        t: float
            Current time at which the solution is desired
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.IdealSingleGas`
            Equation of state class with method to supply gas *gamma*.
        """
        if eos is None:
            eos = IdealSingleGas()
        if x_vec.shape != (self._dim, ):
            print(f"len(x_vec) = {len(x_vec)}")
            print(f"self._dim = {self._dim}")
            raise ValueError(f"Expected {self._dim}-dimensional inputs.")

        actx = x_vec[0].array_context

        loc_update = t * self._velocity

        gamma = eos.gamma()
        mass = 0 * x_vec[0] + self._rho0
        mom = self._velocity * mass
        energy = (self._p0 / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass)

        # process the species components independently
        species_mass = np.empty((self._nspecies, ), dtype=object)
        for i in range(self._nspecies):
            lump_loc = self._spec_centers[i] + loc_update
            rel_pos = x_vec - lump_loc
            r2 = np.dot(rel_pos, rel_pos)
            expterm = self._spec_amplitudes[i] * actx.np.exp(-r2)
            species_mass[i] = self._rho0 * (self._spec_y0s[i] + expterm)

        return make_conserved(dim=self._dim,
                              mass=mass,
                              energy=energy,
                              momentum=mom,
                              species_mass=species_mass)
Beispiel #11
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 #12
0
 def boundary_pair(self,
                   discr,
                   q,
                   t=0.0,
                   btag=BTAG_ALL,
                   eos=IdealSingleGas()):
     """Get the interior and exterior solution on the boundary."""
     dir_soln = discr.project("vol", btag, q)
     return TracePair(btag, interior=dir_soln, exterior=dir_soln)
Beispiel #13
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 #14
0
    def __call__(self, x_vec, *, t=0, eos=None):
        """
        Create the isentropic vortex solution at time *t* at locations *x_vec*.

        The solution at time *t* is created by advecting the vortex under the
        assumption of user-supplied constant, uniform velocity
        (``Vortex2D._velocity``).

        Parameters
        ----------
        t: float
            Current time at which the solution is desired.
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: mirgecom.eos.IdealSingleGas
            Equation of state class to supply method for gas *gamma*.
        """
        if eos is None:
            eos = IdealSingleGas()
        vortex_loc = self._center + t * self._velocity

        # coordinates relative to vortex center
        x_rel = x_vec[0] - vortex_loc[0]
        y_rel = x_vec[1] - vortex_loc[1]
        actx = x_vec[0].array_context
        gamma = eos.gamma()
        r = actx.np.sqrt(x_rel**2 + y_rel**2)
        expterm = self._beta * actx.np.exp(1 - r**2)
        u = self._velocity[0] - expterm * y_rel / (2 * np.pi)
        v = self._velocity[1] + expterm * x_rel / (2 * np.pi)
        velocity = make_obj_array([u, v])
        mass = (1 - (gamma - 1) /
                (16 * gamma * np.pi**2) * expterm**2)**(1 / (gamma - 1))
        momentum = mass * velocity
        p = mass**gamma

        energy = p / (gamma - 1) + mass / 2 * (u**2 + v**2)

        return make_conserved(dim=2,
                              mass=mass,
                              energy=energy,
                              momentum=momentum)
Beispiel #15
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
Beispiel #16
0
def test_viscous_stress_tensor(actx_factory, transport_model):
    """Test tau data structure and values against exact."""
    actx = actx_factory()
    dim = 3
    nel_1d = 4

    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 = 1

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

    # assemble velocities for simple, unique grad components
    velocity_x = nodes[0] + 2 * nodes[1] + 3 * nodes[2]
    velocity_y = 4 * nodes[0] + 5 * nodes[1] + 6 * nodes[2]
    velocity_z = 7 * nodes[0] + 8 * nodes[1] + 9 * nodes[2]
    velocity = make_obj_array([velocity_x, velocity_y, velocity_z])

    mass = 2 * ones
    energy = zeros + 2.5
    mom = mass * velocity

    cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom)
    grad_cv = op.local_grad(discr, cv)

    if transport_model:
        tv_model = SimpleTransport(bulk_viscosity=1.0, viscosity=0.5)
    else:
        tv_model = PowerLawTransport()

    eos = IdealSingleGas()
    gas_model = GasModel(eos=eos, transport=tv_model)
    fluid_state = make_fluid_state(cv, gas_model)

    mu = tv_model.viscosity(eos, cv)
    lam = tv_model.volume_viscosity(eos, cv)

    # Exact answer for tau
    exp_grad_v = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    exp_grad_v_t = np.array([[1, 4, 7], [2, 5, 8], [3, 6, 9]])
    exp_div_v = 15
    exp_tau = (mu * (exp_grad_v + exp_grad_v_t) + lam * exp_div_v * np.eye(3))

    from mirgecom.viscous import viscous_stress_tensor
    tau = viscous_stress_tensor(fluid_state, grad_cv)

    # The errors come from grad_v
    assert actx.to_numpy(discr.norm(tau - exp_tau, np.inf)) < 1e-12
Beispiel #17
0
    def __call__(self, x_vec, *, t=0, eos=None):
        """
        Create the lump-of-mass solution at time *t* and locations *x_vec*.

        The solution at time *t* is created by advecting the mass lump under the
        assumption of constant, uniform velocity (``Lump._velocity``).

        Parameters
        ----------
        t: float
            Current time at which the solution is desired
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.IdealSingleGas`
            Equation of state class with method to supply gas *gamma*.
        """
        if eos is None:
            eos = IdealSingleGas()
        if x_vec.shape != (self._dim, ):
            raise ValueError(f"Position vector has unexpected dimensionality,"
                             f" expected {self._dim}.")

        amplitude = self._rhoamp
        lump_loc = self._center + t * self._velocity

        # coordinates relative to lump center
        rel_center = make_obj_array(
            [x_vec[i] - lump_loc[i] for i in range(self._dim)])
        actx = x_vec[0].array_context
        r = actx.np.sqrt(np.dot(rel_center, rel_center))
        expterm = amplitude * actx.np.exp(1 - r**2)

        mass = expterm + self._rho0
        gamma = eos.gamma()
        mom = self._velocity * mass
        energy = (self._p0 / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass)

        return make_conserved(dim=self._dim,
                              mass=mass,
                              energy=energy,
                              momentum=mom)
Beispiel #18
0
def test_local_max_species_diffusivity(actx_factory, dim, array_valued):
    """Test the local maximum species diffusivity."""
    actx = actx_factory()
    nel_1d = 4

    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 = 1

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

    velocity = make_obj_array([zeros + vel for _ in range(dim)])

    massval = 1
    mass = massval * ones

    energy = zeros + 1.0 / (1.4 * .4)
    mom = mass * velocity
    species_mass = np.array([1., 2., 3.], dtype=object)

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

    d_alpha_input = np.array([.1, .2, .3])
    if array_valued:
        f = 1 + 0.1 * actx.np.sin(nodes[0])
        d_alpha_input *= f

    tv_model = SimpleTransport(species_diffusivity=d_alpha_input)
    eos = IdealSingleGas()

    d_alpha = tv_model.species_diffusivity(eos, cv)

    from mirgecom.viscous import get_local_max_species_diffusivity
    expected = .3 * ones
    if array_valued:
        expected *= f
    calculated = get_local_max_species_diffusivity(actx, d_alpha)

    assert actx.to_numpy(discr.norm(calculated - expected, np.inf)) == 0
Beispiel #19
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
Beispiel #20
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
Beispiel #21
0
    def boundary_pair(self,
                      discr,
                      q,
                      t=0.0,
                      btag=BTAG_ALL,
                      eos=IdealSingleGas()):
        """Get the interior and exterior solution on the boundary."""
        actx = q[0].array_context

        boundary_discr = discr.discr_from_dd(btag)
        nodes = thaw(actx, boundary_discr.nodes())
        ext_soln = self._userfunc(t, nodes)
        int_soln = discr.project("vol", btag, q)
        return TracePair(btag, interior=int_soln, exterior=ext_soln)
Beispiel #22
0
    def __call__(self, x_vec, *, eos=None, **kwargs):
        """
        Create the 1D Sod's shock solution at locations *x_vec*.

        Parameters
        ----------
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.IdealSingleGas`
            Equation of state class with method to supply gas *gamma*.
        """
        if eos is None:
            eos = IdealSingleGas()
        gm1 = eos.gamma() - 1.0
        gmn1 = 1.0 / gm1
        x_rel = x_vec[self._xdir]
        actx = x_rel.array_context

        zeros = 0*x_rel

        rhor = zeros + self._rhor
        rhol = zeros + self._rhol
        x0 = zeros + self._x0
        energyl = zeros + gmn1 * self._energyl
        energyr = zeros + gmn1 * self._energyr
        yesno = actx.np.greater(x_rel, x0)
        mass = actx.np.where(yesno, rhor, rhol)
        energy = actx.np.where(yesno, energyr, energyl)
        mom = make_obj_array(
            [
                0*x_rel
                for i in range(self._dim)
            ]
        )

        return make_conserved(dim=self._dim, mass=mass, energy=energy,
                              momentum=mom)
Beispiel #23
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 #24
0
    def __call__(self, t, x_vec, eos=IdealSingleGas()):
        """
        Create a uniform flow solution at locations *x_vec*.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired (unused)
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.GasEOS`
            Equation of state class to be used in construction of soln (unused)
        """
        return _make_uniform_flow(x_vec=x_vec, mass=self._rho,
                                  pressure=self._p, energy=self._e,
                                  velocity=self._velocity, eos=eos)
Beispiel #25
0
def _make_uniform_flow(x_vec, mass=1.0, energy=2.5, pressure=1.0,
                       velocity=None, eos=IdealSingleGas()):
    r"""Construct uniform, constant flow.

    Construct a uniform, constant flow from mass, energy, pressure, and
    an EOS object.

    Parameters
    ----------
    x_vec: np.ndarray
        Nodal positions
    mass: float
        Value to set $\rho$
    energy: float
        Optional value to set $\rho{E}$
    pressure: float
        Value to use for calculating $\rho{E}$
    velocity: np.ndarray
        Optional constant velocity to set $\rho\vec{V}$

    Returns
    -------
    q: Object array of DOFArrays
        Agglomerated object array with the uniform flow
    """
    dim = len(x_vec)
    if velocity is None:
        velocity = np.zeros(shape=(dim,))

    _rho = mass
    _p = pressure
    _velocity = velocity
    _gamma = eos.gamma()

    mom0 = _velocity * _rho
    e0 = _p / (_gamma - 1.0)
    ke0 = _rho * 0.5 * np.dot(_velocity, _velocity)

    x_rel = x_vec[0]
    zeros = 0.0*x_rel
    ones = zeros + 1.0

    mass = zeros + _rho
    mom = mom0 * ones
    energy = e0 + ke0 + zeros

    return join_conserved(dim=dim, mass=mass, energy=energy, momentum=mom)
Beispiel #26
0
def _get_scalar_lump():
    from mirgecom.eos import IdealSingleGas
    eos = IdealSingleGas()

    from mirgecom.initializers import MulticomponentLump
    init = MulticomponentLump(dim=2,
                              nspecies=3,
                              velocity=np.ones(2),
                              spec_y0s=np.ones(3),
                              spec_amplitudes=np.ones(3))

    from meshmode.mesh import BTAG_ALL
    from mirgecom.boundary import PrescribedInviscidBoundary
    boundaries = {
        BTAG_ALL: PrescribedInviscidBoundary(fluid_solution_func=init)
    }

    return eos, init, boundaries, 1e-12
Beispiel #27
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
Beispiel #28
0
    def __call__(self, t, x_vec, eos=IdealSingleGas()):
        """
        Create a uniform flow solution at locations *x_vec*.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired (unused)
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.GasEOS`
            Equation of state class to be used in construction of soln (unused)
        """
        gamma = eos.gamma()
        mass = x_vec[0].copy()
        mom = self._velocity * make_obj_array([mass])
        energy = (self._p / (gamma - 1.0)) + np.dot(mom, mom) / (2.0 * mass)

        return flat_obj_array(mass, energy, mom)
Beispiel #29
0
def _get_pulse():
    from mirgecom.eos import IdealSingleGas
    from mirgecom.gas_model import GasModel
    gas_model = GasModel(eos=IdealSingleGas())

    from mirgecom.initializers import Uniform, AcousticPulse
    uniform_init = Uniform(dim=2)
    pulse_init = AcousticPulse(dim=2, center=np.zeros(2), amplitude=1.0, width=.1)

    def init(nodes):
        return pulse_init(x_vec=nodes, cv=uniform_init(nodes), eos=gas_model.eos)

    from meshmode.mesh import BTAG_ALL
    from mirgecom.boundary import AdiabaticSlipBoundary
    boundaries = {
        BTAG_ALL: AdiabaticSlipBoundary()
    }

    return gas_model, init, boundaries, 3e-12
Beispiel #30
0
    def __call__(self, x_vec, q, eos=IdealSingleGas()):
        """
        Create the acoustic pulse at locations *x_vec*.

        Parameters
        ----------
        t: float
            Current time at which the solution is desired (unused)
        x_vec: numpy.ndarray
            Nodal coordinates
        eos: :class:`mirgecom.eos.GasEOS`
            Equation of state class to be used in construction of soln (unused)
        """
        assert len(x_vec) == self._dim
        cv = split_conserved(self._dim, q)
        return cv.replace(
            energy=cv.energy + _make_pulse(
                amp=self._amp, w=self._width, r0=self._center, r=x_vec)
            ).join()