예제 #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)
예제 #2
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
예제 #3
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
예제 #4
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)
예제 #5
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)
예제 #6
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)
예제 #7
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
예제 #8
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)
예제 #9
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
예제 #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.
    """

    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