Beispiel #1
0
def wave_operator(discr, c, w):
    u = w[0]
    v = w[1:]

    dir_u = discr.project("vol", BTAG_ALL, u)
    dir_v = discr.project("vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    return (
            discr.inverse_mass(
                flat_obj_array(
                    -c*discr.weak_div(v),
                    -c*discr.weak_grad(u)
                    )
                +  # noqa: W504
                discr.face_mass(
                    wave_flux(discr, c=c, w_tpair=interior_trace_pair(discr, w))
                    + wave_flux(discr, c=c, w_tpair=TracePair(
                        BTAG_ALL, interior=dir_bval, exterior=dir_bc))
                    + sum(
                        wave_flux(discr, c=c, w_tpair=tpair)
                        for tpair in cross_rank_trace_pairs(discr, w))
                    )
                )
                )
Beispiel #2
0
def cross_rank_trace_pairs(discrwb, vec, tag=None):
    if (isinstance(vec, np.ndarray)
            and vec.dtype.char == "O"
            and not isinstance(vec, DOFArray)):

        n, = vec.shape
        result = {}
        for ivec in range(n):
            for rank_tpair in _cross_rank_trace_pairs_scalar_field(
                    discrwb, vec[ivec]):
                assert isinstance(rank_tpair.dd.domain_tag, sym.DTAG_BOUNDARY)
                assert isinstance(rank_tpair.dd.domain_tag.tag, BTAG_PARTITION)
                result[rank_tpair.dd.domain_tag.tag.part_nr, ivec] = rank_tpair

        return [
            TracePair(
                dd=sym.as_dofdesc(sym.DTAG_BOUNDARY(BTAG_PARTITION(remote_rank))),
                interior=make_obj_array([
                    result[remote_rank, i].int for i in range(n)]),
                exterior=make_obj_array([
                    result[remote_rank, i].ext for i in range(n)])
                )
            for remote_rank in discrwb.connected_ranks()]
    else:
        return _cross_rank_trace_pairs_scalar_field(discrwb, vec, tag=tag)
def wave_operator(discr, c, w):
    u = w[0]
    v = w[1:]

    dir_u = discr.project("vol", BTAG_ALL, u)
    dir_v = discr.project("vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    dd_quad = DOFDesc("vol", "vel_prod")
    c_quad = discr.project("vol", dd_quad, c)
    w_quad = discr.project("vol", dd_quad, w)
    u_quad = w_quad[0]
    v_quad = w_quad[1:]

    dd_allfaces_quad = DOFDesc("all_faces", "vel_prod")

    # FIXME Fix sign issue
    return (discr.inverse_mass(
        flat_obj_array(discr.weak_div(dd_quad,
                                      scalar(c_quad) * v_quad),
                       discr.weak_grad(dd_quad, c_quad *
                                       u_quad)) -  # noqa: W504
        discr.face_mass(
            dd_allfaces_quad,
            wave_flux(discr, c=c, w_tpair=interior_trace_pair(discr, w)) +
            wave_flux(
                discr, c=c, w_tpair=TracePair(BTAG_ALL, dir_bval, dir_bc)))))
Beispiel #4
0
def wave_operator(dcoll, c, w):
    u = w[0]
    v = w[1:]

    dir_u = op.project(dcoll, "vol", BTAG_ALL, u)
    dir_v = op.project(dcoll, "vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    dd_quad = DOFDesc("vol", DISCR_TAG_QUAD)
    c_quad = op.project(dcoll, "vol", dd_quad, c)
    w_quad = op.project(dcoll, "vol", dd_quad, w)
    u_quad = w_quad[0]
    v_quad = w_quad[1:]

    dd_allfaces_quad = DOFDesc("all_faces", DISCR_TAG_QUAD)

    return (op.inverse_mass(
        dcoll,
        flat_obj_array(-op.weak_local_div(dcoll, dd_quad, c_quad * v_quad),
                       -op.weak_local_grad(dcoll, dd_quad, c_quad * u_quad))
        +  # noqa: W504
        op.face_mass(
            dcoll, dd_allfaces_quad,
            wave_flux(dcoll, c=c, w_tpair=op.interior_trace_pair(dcoll, w)) +
            wave_flux(dcoll,
                      c=c,
                      w_tpair=TracePair(
                          BTAG_ALL, interior=dir_bval, exterior=dir_bc)))))
Beispiel #5
0
def interior_trace_pair(discrwb, vec):
    """Return a :class:`grudge.sym.TracePair` for the interior faces of
    *discrwb*.
    """
    i = discrwb.project("vol", "int_faces", vec)
    e = obj_array_vectorize(lambda el: discrwb.opposite_face_connection()(el),
                            i)
    return TracePair("int_faces", interior=i, exterior=e)
Beispiel #6
0
def euler_operator(discr, eos, boundaries, cv, t=0.0):
    r"""Compute RHS of the Euler flow equations.

    Returns
    -------
    numpy.ndarray
        The right-hand-side of the Euler flow equations:

        .. math::

            \dot{\mathbf{q}} = - \nabla\cdot\mathbf{F} +
                (\mathbf{F}\cdot\hat{n})_{\partial\Omega}

    Parameters
    ----------
    cv: :class:`mirgecom.fluid.ConservedVars`
        Fluid conserved state object with the conserved variables.

    boundaries
        Dictionary of boundary functions, one for each valid btag

    t
        Time

    eos: mirgecom.eos.GasEOS
        Implementing the pressure and temperature functions for
        returning pressure and temperature as a function of the state q.

    Returns
    -------
    numpy.ndarray
        Agglomerated object array of DOF arrays representing the RHS of the Euler
        flow equations.
    """
    vol_weak = discr.weak_div(inviscid_flux(discr=discr, eos=eos, cv=cv).join())

    boundary_flux = (
        _facial_flux(discr=discr, eos=eos, cv_tpair=interior_trace_pair(discr, cv))
        + sum(
            _facial_flux(
                discr, eos=eos,
                cv_tpair=TracePair(
                    part_pair.dd,
                    interior=split_conserved(discr.dim, part_pair.int),
                    exterior=split_conserved(discr.dim, part_pair.ext)))
            for part_pair in cross_rank_trace_pairs(discr, cv.join()))
        + sum(
            _facial_flux(
                discr=discr, eos=eos,
                cv_tpair=boundaries[btag].boundary_pair(
                    discr, eos=eos, btag=btag, t=t, cv=cv)
            )
            for btag in boundaries)
    ).join()

    return split_conserved(
        discr.dim, discr.inverse_mass(vol_weak - discr.face_mass(boundary_flux))
    )
Beispiel #7
0
    def boundary_pair(self, discr, q, btag, eos, t=0.0):
        """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 #8
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 #9
0
def interior_trace_pair(discrwb, vec):
    i = discrwb.project("vol", "int_faces", vec)

    if (isinstance(vec, np.ndarray)
            and vec.dtype.char == "O"
            and not isinstance(vec, DOFArray)):
        e = obj_array_vectorize(
                lambda el: discrwb.opposite_face_connection()(el),
                i)

    return TracePair("int_faces", i, e)
Beispiel #10
0
def _cross_rank_trace_pairs_scalar_field(dcoll, vec, tag=None):
    if isinstance(vec, Number):
        return [
            TracePair(BTAG_PARTITION(remote_rank), interior=vec, exterior=vec)
            for remote_rank in connected_ranks(dcoll)
        ]
    else:
        rbcomms = [
            _RankBoundaryCommunication(dcoll, remote_rank, vec, tag=tag)
            for remote_rank in connected_ranks(dcoll)
        ]
        return [rbcomm.finish() for rbcomm in rbcomms]
Beispiel #11
0
def interior_trace_pair(dcoll, vec):
    """Return a :class:`grudge.sym.TracePair` for the interior faces of
    *dcoll*.
    """
    i = project(dcoll, "vol", "int_faces", vec)

    def get_opposite_face(el):
        if isinstance(el, Number):
            return el
        else:
            return dcoll.opposite_face_connection()(el)

    e = obj_array_vectorize(get_opposite_face, i)

    return TracePair("int_faces", interior=i, exterior=e)
Beispiel #12
0
    def finish(self):
        self.recv_req.Wait()

        actx = self.array_context
        remote_dof_array = unflatten(self.array_context, self.bdry_discr,
                actx.from_numpy(self.remote_data_host))

        bdry_conn = self.discrwb.get_distributed_boundary_swap_connection(
                sym.as_dofdesc(sym.DTAG_BOUNDARY(self.remote_btag)))
        swapped_remote_dof_array = bdry_conn(remote_dof_array)

        self.send_req.Wait()

        return TracePair(self.remote_btag, self.local_dof_array,
                swapped_remote_dof_array)
Beispiel #13
0
def cross_rank_trace_pairs(dcoll, ary, tag=None):
    r"""Get a list of *ary* trace pairs for each partition boundary.

    For each partition boundary, the field data values in *ary* are
    communicated to/from the neighboring partition. Presumably, this
    communication is MPI (but strictly speaking, may not be, and this
    routine is agnostic to the underlying communication, see e.g.
    _cross_rank_trace_pairs_scalar_field).

    For each face on each partition boundary, a :class:`TracePair` is
    created with the locally, and remotely owned partition boundary face
    data as the `internal`, and `external` components, respectively.
    Each of the TracePair components are structured like *ary*.

    The input field data *ary* may be a single
    :class:`~meshmode.dof_array.DOFArray`, or an object
    array of ``DOFArray``\ s of arbitrary shape.
    """
    if isinstance(ary, np.ndarray):
        oshape = ary.shape
        comm_vec = ary.flatten()

        n, = comm_vec.shape
        result = {}
        # FIXME: Batch this communication rather than
        # doing it in sequence.
        for ivec in range(n):
            for rank_tpair in _cross_rank_trace_pairs_scalar_field(
                    dcoll, comm_vec[ivec]):
                assert isinstance(rank_tpair.dd.domain_tag,
                                  dof_desc.DTAG_BOUNDARY)
                assert isinstance(rank_tpair.dd.domain_tag.tag, BTAG_PARTITION)
                result[rank_tpair.dd.domain_tag.tag.part_nr, ivec] = rank_tpair

        return [
            TracePair(dd=dof_desc.as_dofdesc(
                dof_desc.DTAG_BOUNDARY(BTAG_PARTITION(remote_rank))),
                      interior=make_obj_array(
                          [result[remote_rank, i].int
                           for i in range(n)]).reshape(oshape),
                      exterior=make_obj_array(
                          [result[remote_rank, i].ext
                           for i in range(n)]).reshape(oshape))
            for remote_rank in connected_ranks(dcoll)
        ]
    else:
        return _cross_rank_trace_pairs_scalar_field(dcoll, ary, tag=tag)
Beispiel #14
0
def wave_operator(dcoll, c, w):
    u = w[0]
    v = w[1:]

    dir_u = op.project(dcoll, "vol", BTAG_ALL, u)
    dir_v = op.project(dcoll, "vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    return (op.inverse_mass(
        dcoll,
        flat_obj_array(-c * op.weak_local_div(dcoll, v),
                       -c * op.weak_local_grad(dcoll, u)) +  # noqa: W504
        op.face_mass(
            dcoll,
            wave_flux(dcoll, c=c, w_tpair=op.interior_trace_pair(dcoll, w)) +
            wave_flux(dcoll,
                      c=c,
                      w_tpair=TracePair(
                          BTAG_ALL, interior=dir_bval, exterior=dir_bc)))))
Beispiel #15
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 #16
0
def wave_operator(discr, c, w):
    """Compute the RHS of the wave equation.

    Parameters
    ----------
    discr: grudge.eager.EagerDGDiscretization
        the discretization to use
    c: float
        the (constant) wave speed
    w: numpy.ndarray
        an object array of DOF arrays, representing the state vector

    Returns
    -------
    numpy.ndarray
        an object array of DOF arrays, representing the ODE RHS
    """
    u = w[0]
    v = w[1:]

    dir_u = discr.project("vol", BTAG_ALL, u)
    dir_v = discr.project("vol", BTAG_ALL, v)
    dir_bval = flat_obj_array(dir_u, dir_v)
    dir_bc = flat_obj_array(-dir_u, dir_v)

    return (discr.inverse_mass(
        flat_obj_array(-c * discr.weak_div(v), -c *
                       discr.weak_grad(u)) +  # noqa: W504
        discr.face_mass(
            _flux(discr, c=c, w_tpair=interior_trace_pair(discr, w)) +
            _flux(discr,
                  c=c,
                  w_tpair=TracePair(
                      BTAG_ALL, interior=dir_bval, exterior=dir_bc)) + sum(
                          _flux(discr, c=c, w_tpair=tpair)
                          for tpair in cross_rank_trace_pairs(discr, w)))))
Beispiel #17
0
 def get_u_flux(self, discr, alpha, dd, q):  # noqa: D102
     q_int = discr.project("vol", dd, q)
     q_tpair = TracePair(dd, interior=q_int, exterior=q_int)
     return _u_flux(discr, alpha, q_tpair)
Beispiel #18
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 #19
0
 def boundary_pair(self, discr, q, btag, eos, t=0.0):
     """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 #20
0
def test_facial_flux(actx_factory, nspecies, order, dim):
    """Check the flux across element faces.

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

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

    tolerance = 1e-14
    p0 = 1.0

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        eoc_rec1.add_data_point(1.0 / nel_1d, momerr)

    logger.info(f"standalone Errors:\n{eoc_rec0}"
                f"boundary Errors:\n{eoc_rec1}")
    assert (eoc_rec0.order_estimate() >= order - 0.5
            or eoc_rec0.max_error() < 1e-9)
    assert (eoc_rec1.order_estimate() >= order - 0.5
            or eoc_rec1.max_error() < 1e-9)
Beispiel #21
0
 def get_q_flux(self, discr, alpha, dd, u):  # noqa: D102
     u_int = discr.project("vol", dd, u)
     u_tpair = TracePair(dd, interior=u_int, exterior=u_int)
     return _q_flux(discr, alpha, u_tpair)