Beispiel #1
0
        def __call__(self, x_vec, *, t=0, eos):
    
    
            if self._p_fun is not None:
                P0 = self._p_fun(t)
            else:
                P0 = self._P0
            T0 = self._T0

            gamma = eos.gamma()
            gas_const = eos.gas_const()
            pressure = getIsentropicPressure(mach=self._mach, P0=P0, gamma=gamma)
            temperature = getIsentropicTemperature(mach=self._mach, T0=T0, gamma=gamma)
            rho = pressure/temperature/gas_const

            #print(f'ramp Mach number {self._mach}')
            #print(f'ramp stagnation pressure {P0}')
            #print(f'ramp stagnation temperature {T0}')
            #print(f'ramp pressure {pressure}')
            #print(f'ramp temperature {temperature}')

            velocity = np.zeros(shape=(self._dim,)) 
            velocity[self._direc] = self._mach*math.sqrt(gamma*pressure/rho)
    
            mass = 0.0*x_vec[0] + rho
            mom = velocity*mass
            energy = (pressure/(gamma - 1.0)) + np.dot(mom, mom)/(2.0*mass)
            from mirgecom.euler import join_conserved
            return join_conserved(dim=self._dim, mass=mass, momentum=mom, energy=energy)
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 _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 #4
0
    def boundary_pair(self, discr, q, btag, eos, t=0.0):
        """Get the interior and exterior solution on the boundary.

        The exterior solution is set such that there will be vanishing
        flux through the boundary, preserving mass, momentum (magnitude) and
        energy.
        rho_plus = rho_minus
        v_plus = v_minus - 2 * (v_minus . n_hat) * n_hat
        mom_plus = rho_plus * v_plus
        E_plus = E_minus
        """
        # Grab some boundary-relevant data
        dim = discr.dim
        cv = split_conserved(dim, q)
        actx = cv.mass.array_context

        # Grab a unit normal to the boundary
        nhat = thaw(actx, discr.normal(btag))

        # Get the interior/exterior solns
        int_soln = discr.project("vol", btag, q)
        int_cv = split_conserved(dim, int_soln)

        # Subtract out the 2*wall-normal component
        # of velocity from the velocity at the wall to
        # induce an equal but opposite wall-normal (reflected) wave
        # preserving the tangential component
        mom_normcomp = np.dot(int_cv.momentum, nhat)  # wall-normal component
        wnorm_mom = nhat * mom_normcomp  # wall-normal mom vec
        ext_mom = int_cv.momentum - 2.0 * wnorm_mom  # prescribed ext momentum

        # Form the external boundary solution with the new momentum
        bndry_soln = join_conserved(dim=dim,
                                    mass=int_cv.mass,
                                    energy=int_cv.energy,
                                    momentum=ext_mom)

        return TracePair(btag, interior=int_soln, exterior=bndry_soln)
Beispiel #5
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 #6
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 #7
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
Beispiel #8
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()
Beispiel #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.
    """

    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