Ejemplo n.º 1
0
def grad_operator(discr, dd_vol, dd_faces, u, flux):
    r"""Compute a DG gradient for the input *u* with flux given by *flux*.

    Parameters
    ----------
    discr: grudge.eager.EagerDGDiscretization
        the discretization to use
    dd_vol: grudge.dof_desc.DOFDesc
        the degree-of-freedom tag associated with the volume discrezation.
        This determines the type of quadrature to be used.
    dd_faces: grudge.dof_desc.DOFDesc
        the degree-of-freedom tag associated with the surface discrezation.
        This determines the type of quadrature to be used.
    u: meshmode.dof_array.DOFArray or numpy.ndarray
        the function (or container of functions) for which gradient is to be
        calculated
    flux: numpy.ndarray
        the boundary flux across the faces of the element for each component
        of *u*

    Returns
    -------
    meshmode.dof_array.DOFArray or numpy.ndarray
        the dg gradient operator applied to *u*
    """
    return -discr.inverse_mass(
        op.weak_local_grad(discr, dd_vol, u) -
        op.face_mass(discr, dd_faces, flux))
Ejemplo n.º 2
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)))))
Ejemplo n.º 3
0
    def operator(self, t, w):
        dcoll = self.dcoll
        u = w[0]
        v = w[1:]
        actx = u.array_context

        # boundary conditions -------------------------------------------------

        # dirichlet BCs -------------------------------------------------------
        dir_u = op.project(dcoll, "vol", self.dirichlet_tag, u)
        dir_v = op.project(dcoll, "vol", self.dirichlet_tag, v)
        if self.dirichlet_bc_f:
            # FIXME
            from warnings import warn
            warn("Inhomogeneous Dirichlet conditions on the wave equation "
                 "are still having issues.")

            dir_g = self.dirichlet_bc_f
            dir_bc = flat_obj_array(2 * dir_g - dir_u, dir_v)
        else:
            dir_bc = flat_obj_array(-dir_u, dir_v)

        # neumann BCs ---------------------------------------------------------
        neu_u = op.project(dcoll, "vol", self.neumann_tag, u)
        neu_v = op.project(dcoll, "vol", self.neumann_tag, v)
        neu_bc = flat_obj_array(neu_u, -neu_v)

        # radiation BCs -------------------------------------------------------
        rad_normal = thaw(dcoll.normal(dd=self.radiation_tag), actx)

        rad_u = op.project(dcoll, "vol", self.radiation_tag, u)
        rad_v = op.project(dcoll, "vol", self.radiation_tag, v)

        rad_bc = flat_obj_array(
            0.5 * (rad_u - self.sign * np.dot(rad_normal, rad_v)),
            0.5 * rad_normal * (np.dot(rad_normal, rad_v) - self.sign * rad_u))

        # entire operator -----------------------------------------------------
        def flux(tpair):
            return op.project(dcoll, tpair.dd, "all_faces", self.flux(tpair))

        result = (op.inverse_mass(
            dcoll,
            flat_obj_array(-self.c * op.weak_local_div(dcoll, v),
                           -self.c * op.weak_local_grad(dcoll, u)) -
            op.face_mass(
                dcoll,
                sum(
                    flux(tpair)
                    for tpair in op.interior_trace_pairs(dcoll, w)) +
                flux(op.bv_trace_pair(dcoll, self.dirichlet_tag, w, dir_bc)) +
                flux(op.bv_trace_pair(dcoll, self.neumann_tag, w, neu_bc)) +
                flux(op.bv_trace_pair(dcoll, self.radiation_tag, w, rad_bc)))))

        result[0] = result[0] + self.source_f(actx, dcoll, t)

        return result
Ejemplo n.º 4
0
def grad_operator(discr, u, flux):
    r"""Compute a DG gradient for the input *u* with flux given by *flux*.

    Parameters
    ----------
    discr: grudge.eager.EagerDGDiscretization
        the discretization to use
    u: meshmode.dof_array.DOFArray or numpy.ndarray
        the DOF array (or object array of DOF arrays) to which the operator should be
        applied
    flux: numpy.ndarray
        the boundary fluxes across the faces of the element
    Returns
    -------
    meshmode.dof_array.DOFArray or numpy.ndarray
        the dg gradient operator applied to *u*
    """
    from grudge.op import weak_local_grad
    return -discr.inverse_mass(
        weak_local_grad(discr, u, nested=False) - discr.face_mass(flux))
Ejemplo n.º 5
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)))))
Ejemplo n.º 6
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) \
                # pylint: disable=invalid-unary-operand-type
            ) + op.face_mass(
                dcoll,
                dd_allfaces_quad,
                wave_flux(
                    dcoll, c=c,
                    w_tpair=op.bdry_trace_pair(dcoll,
                                               BTAG_ALL,
                                               interior=dir_bval,
                                               exterior=dir_bc)
                ) + sum(
                    wave_flux(dcoll, c=c, w_tpair=tpair)
                    for tpair in op.interior_trace_pairs(dcoll, w)
                )
            )
        )
    )
Ejemplo n.º 7
0
def wave_operator(dcoll, c, w):
    u = w.u
    v = w.v

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

    return (op.inverse_mass(
        dcoll,
        WaveState(u=-c * op.weak_local_div(dcoll, v),
                  v=-c * op.weak_local_grad(dcoll, u)) +
        op.face_mass(
            dcoll,
            wave_flux(dcoll,
                      c=c,
                      w_tpair=op.bdry_trace_pair(
                          dcoll, BTAG_ALL, interior=dir_bval, exterior=dir_bc))
            + sum(
                wave_flux(dcoll, c=c, w_tpair=tpair)
                for tpair in op.interior_trace_pairs(dcoll, w)))))
Ejemplo n.º 8
0
    def operator(self, t, u):
        from meshmode.mesh import BTAG_ALL

        dcoll = self.dcoll

        def flux(tpair):
            return op.project(dcoll, tpair.dd, "all_faces", self.flux(tpair))

        if self.inflow_u is not None:
            inflow_flux = flux(
                op.bv_trace_pair(dcoll,
                                 BTAG_ALL,
                                 interior=u,
                                 exterior=self.inflow_u(t)))
        else:
            inflow_flux = 0

        return (op.inverse_mass(
            dcoll,
            np.dot(self.v, op.weak_local_grad(dcoll, u)) - op.face_mass(
                dcoll,
                sum(
                    flux(tpair)
                    for tpair in op.interior_trace_pairs(dcoll, u)) +
                inflow_flux

                # FIXME: Add support for inflow/outflow tags
                # + flux(op.bv_trace_pair(dcoll,
                #                         self.inflow_tag,
                #                         interior=u,
                #                         exterior=bc_in))
                # + flux(op.bv_trace_pair(dcoll,
                #                         self.outflow_tag,
                #                         interior=u,
                #                         exterior=bc_out))
            )))
Ejemplo n.º 9
0
while t < t_final:
    # extract the left boundary trace pair
    lbnd_tpair = op.bv_trace_pair(dcoll,
                                  dd=left_bndry,
                                  interior=uh,
                                  exterior=left_boundary_condition(x_bndry, t))
    # extract the right boundary trace pair
    rbnd_tpair = op.bv_trace_pair(dcoll,
                                  dd=right_bndry,
                                  interior=uh,
                                  exterior=op.project(dcoll, "vol",
                                                      right_bndry, uh))
    # extract the trace pairs on the interior faces
    interior_tpair = op.interior_trace_pair(dcoll,
                                            uh)
    Su = op.weak_local_grad(dcoll, uh)

    lift = op.face_mass(dcoll,
                        # left boundary weak-flux terms
                        op.project(dcoll,
                                   left_bndry, "all_faces",
                                   flux(dcoll, lbnd_tpair))
                        # right boundary weak-flux terms
                        + op.project(dcoll,
                                     right_bndry, "all_faces",
                                     flux(dcoll, rbnd_tpair))
                        # interior weak-flux terms
                        + op.project(dcoll,
                                     FACE_RESTR_INTERIOR, "all_faces",
                                     flux(dcoll, interior_tpair)))
Ejemplo n.º 10
0
 def weak_grad(self, *args):
     return op.weak_local_grad(self, *args)
Ejemplo n.º 11
0
def test_gradient(actx_factory,
                  form,
                  dim,
                  order,
                  vectorize,
                  nested,
                  visualize=False):
    actx = actx_factory()

    from pytools.convergence import EOCRecorder
    eoc_rec = EOCRecorder()

    for n in [4, 6, 8]:
        mesh = mgen.generate_regular_rect_mesh(a=(-1, ) * dim,
                                               b=(1, ) * dim,
                                               nelements_per_axis=(n, ) * dim)

        dcoll = DiscretizationCollection(actx, mesh, order=order)

        def f(x):
            result = dcoll.zeros(actx) + 1
            for i in range(dim - 1):
                result = result * actx.np.sin(np.pi * x[i])
            result = result * actx.np.cos(np.pi / 2 * x[dim - 1])
            return result

        def grad_f(x):
            result = make_obj_array(
                [dcoll.zeros(actx) + 1 for _ in range(dim)])
            for i in range(dim - 1):
                for j in range(i):
                    result[i] = result[i] * actx.np.sin(np.pi * x[j])
                result[i] = result[i] * np.pi * actx.np.cos(np.pi * x[i])
                for j in range(i + 1, dim - 1):
                    result[i] = result[i] * actx.np.sin(np.pi * x[j])
                result[i] = result[i] * actx.np.cos(np.pi / 2 * x[dim - 1])
            for j in range(dim - 1):
                result[dim - 1] = result[dim - 1] * actx.np.sin(np.pi * x[j])
            result[dim -
                   1] = result[dim - 1] * (-np.pi / 2 *
                                           actx.np.sin(np.pi / 2 * x[dim - 1]))
            return result

        x = thaw(dcoll.nodes(), actx)

        if vectorize:
            u = make_obj_array([(i + 1) * f(x) for i in range(dim)])
        else:
            u = f(x)

        def get_flux(u_tpair):
            dd = u_tpair.dd
            dd_allfaces = dd.with_dtag("all_faces")
            normal = thaw(dcoll.normal(dd), actx)
            u_avg = u_tpair.avg
            if vectorize:
                if nested:
                    flux = make_obj_array(
                        [u_avg_i * normal for u_avg_i in u_avg])
                else:
                    flux = np.outer(u_avg, normal)
            else:
                flux = u_avg * normal
            return op.project(dcoll, dd, dd_allfaces, flux)

        dd_allfaces = DOFDesc("all_faces")

        if form == "strong":
            grad_u = (
                op.local_grad(dcoll, u, nested=nested)
                # No flux terms because u doesn't have inter-el jumps
            )
        elif form == "weak":
            grad_u = op.inverse_mass(
                dcoll,
                -op.weak_local_grad(dcoll, u, nested=nested)  # pylint: disable=E1130
                +  # noqa: W504
                op.face_mass(
                    dcoll,
                    dd_allfaces,
                    # Note: no boundary flux terms here because u_ext == u_int == 0
                    sum(
                        get_flux(utpair)
                        for utpair in op.interior_trace_pairs(dcoll, u))))
        else:
            raise ValueError("Invalid form argument.")

        if vectorize:
            expected_grad_u = make_obj_array([(i + 1) * grad_f(x)
                                              for i in range(dim)])
            if not nested:
                expected_grad_u = np.stack(expected_grad_u, axis=0)
        else:
            expected_grad_u = grad_f(x)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(dcoll,
                                  vis_order=order if dim == 3 else dim + 3)

            filename = (
                f"test_gradient_{form}_{dim}_{order}"
                f"{'_vec' if vectorize else ''}{'_nested' if nested else ''}.vtu"
            )
            vis.write_vtk_file(filename, [
                ("u", u),
                ("grad_u", grad_u),
                ("expected_grad_u", expected_grad_u),
            ],
                               overwrite=True)

        rel_linf_err = actx.to_numpy(
            op.norm(dcoll, grad_u - expected_grad_u, np.inf) /
            op.norm(dcoll, expected_grad_u, np.inf))
        eoc_rec.add_data_point(1. / n, rel_linf_err)

    print("L^inf error:")
    print(eoc_rec)
    assert (eoc_rec.order_estimate() >= order - 0.5
            or eoc_rec.max_error() < 1e-11)