示例#1
0
        def rewrite_derivative(ref_class, field,  dd_in, with_jacobian=True):
            jac_tag = sym.area_element(self.ambient_dim, self.dim, dd=dd_in)

            rec_field = self.rec(field)
            if with_jacobian:
                rec_field = jac_tag * rec_field
            return sum(
                    sym.inverse_metric_derivative(
                        rst_axis, expr.op.xyz_axis,
                        ambient_dim=self.ambient_dim, dim=self.dim)
                    * ref_class(rst_axis, dd_in=dd_in)(rec_field)
                    for rst_axis in range(self.dim))
示例#2
0
    def map_operator_binding(self, expr):
        # Global-to-reference is run after operator specialization, so
        # if we encounter non-quadrature operators here, we know they
        # must be nodal.

        dd_in = expr.op.dd_in
        dd_out = expr.op.dd_out

        if dd_in.is_volume():
            dim = self.dim
        else:
            dim = self.dim - 1

        jac_in = sym.area_element(self.ambient_dim, dim, dd=dd_in)
        jac_noquad = sym.area_element(self.ambient_dim,
                                      dim,
                                      dd=dd_in.with_discr_tag(
                                          dof_desc.DISCR_TAG_BASE))

        def rewrite_derivative(ref_class, field, dd_in, with_jacobian=True):
            def imd(rst):
                return sym.inverse_surface_metric_derivative(
                    rst,
                    expr.op.xyz_axis,
                    ambient_dim=self.ambient_dim,
                    dim=self.dim,
                    dd=dd_in)

            rec_field = self.rec(field)
            if with_jacobian:
                jac_tag = sym.area_element(self.ambient_dim,
                                           self.dim,
                                           dd=dd_in)
                rec_field = jac_tag * rec_field

                return sum(
                    ref_class(rst_axis, dd_in=dd_in)(rec_field * imd(rst_axis))
                    for rst_axis in range(self.dim))
            else:
                return sum(
                    ref_class(rst_axis, dd_in=dd_in)(rec_field) * imd(rst_axis)
                    for rst_axis in range(self.dim))

        if isinstance(expr.op, op.MassOperator):
            return op.RefMassOperator(dd_in,
                                      dd_out)(jac_in * self.rec(expr.field))

        elif isinstance(expr.op, op.InverseMassOperator):
            # based on https://arxiv.org/pdf/1608.03836.pdf
            return (
                1.0 / jac_in *
                op.RefInverseMassOperator(dd_in, dd_out)(self.rec(expr.field)))

        elif isinstance(expr.op, op.FaceMassOperator):
            jac_in_surf = sym.area_element(self.ambient_dim,
                                           self.dim - 1,
                                           dd=dd_in)
            return op.RefFaceMassOperator(dd_in, dd_out)(jac_in_surf *
                                                         self.rec(expr.field))

        elif isinstance(expr.op, op.StiffnessOperator):
            return op.RefMassOperator(dd_in=dd_in, dd_out=dd_out)(
                jac_noquad *
                self.rec(op.DiffOperator(expr.op.xyz_axis)(expr.field)))

        elif isinstance(expr.op, op.DiffOperator):
            return rewrite_derivative(op.RefDiffOperator,
                                      expr.field,
                                      dd_in=dd_in,
                                      with_jacobian=False)

        elif isinstance(expr.op, op.StiffnessTOperator):
            return rewrite_derivative(op.RefStiffnessTOperator,
                                      expr.field,
                                      dd_in=dd_in)

        elif isinstance(expr.op, op.MInvSTOperator):
            return self.rec(op.InverseMassOperator()(op.StiffnessTOperator(
                expr.op.xyz_axis)(self.rec(expr.field))))

        else:
            return IdentityMapper.map_operator_binding(self, expr)
示例#3
0
def test_face_normal_surface(actx_factory, mesh_name):
    """Check that face normals are orthogonal to the surface normal"""
    actx = actx_factory()

    # {{{ geometry

    if mesh_name == "2-1-ellipse":
        from mesh_data import EllipseMeshBuilder
        builder = EllipseMeshBuilder(radius=3.1, aspect_ratio=2.0)
    elif mesh_name == "spheroid":
        from mesh_data import SpheroidMeshBuilder
        builder = SpheroidMeshBuilder()
    else:
        raise ValueError("unknown mesh name: %s" % mesh_name)

    mesh = builder.get_mesh(builder.resolutions[0], builder.mesh_order)
    discr = DiscretizationCollection(actx, mesh, order=builder.order)

    volume_discr = discr.discr_from_dd(dof_desc.DD_VOLUME)
    logger.info("ndofs:    %d", volume_discr.ndofs)
    logger.info("nelements: %d", volume_discr.mesh.nelements)

    # }}}

    # {{{ symbolic
    from meshmode.discretization.connection import FACE_RESTR_INTERIOR

    dv = dof_desc.DD_VOLUME
    df = dof_desc.as_dofdesc(FACE_RESTR_INTERIOR)

    ambient_dim = mesh.ambient_dim
    dim = mesh.dim

    sym_surf_normal = sym.project(dv,
                                  df)(sym.surface_normal(ambient_dim,
                                                         dim=dim,
                                                         dd=dv).as_vector())
    sym_surf_normal = sym_surf_normal / sym.sqrt(sum(sym_surf_normal**2))

    sym_face_normal_i = sym.normal(df, ambient_dim, dim=dim - 1)
    sym_face_normal_e = sym.OppositeInteriorFaceSwap(df)(sym_face_normal_i)

    if mesh.ambient_dim == 3:
        # NOTE: there's only one face tangent in 3d
        sym_face_tangent = (
            sym.pseudoscalar(ambient_dim, dim - 1, dd=df) /
            sym.area_element(ambient_dim, dim - 1, dd=df)).as_vector()

    # }}}

    # {{{ checks

    def _eval_error(x):
        return bind(discr, sym.norm(np.inf, sym.var("x", dd=df), dd=df))(actx,
                                                                         x=x)

    rtol = 1.0e-14

    surf_normal = bind(discr, sym_surf_normal)(actx)

    face_normal_i = bind(discr, sym_face_normal_i)(actx)
    face_normal_e = bind(discr, sym_face_normal_e)(actx)

    # check interpolated surface normal is orthogonal to face normal
    error = _eval_error(surf_normal.dot(face_normal_i))
    logger.info("error[n_dot_i]:    %.5e", error)
    assert error < rtol

    # check angle between two neighboring elements
    error = _eval_error(face_normal_i.dot(face_normal_e) + 1.0)
    logger.info("error[i_dot_e]:    %.5e", error)
    assert error > rtol

    # check orthogonality with face tangent
    if ambient_dim == 3:
        face_tangent = bind(discr, sym_face_tangent)(actx)

        error = _eval_error(face_tangent.dot(face_normal_i))
        logger.info("error[t_dot_i]:  %.5e", error)
        assert error < 5 * rtol
示例#4
0
    def map_operator_binding(self, expr):
        # Global-to-reference is run after operator specialization, so
        # if we encounter non-quadrature operators here, we know they
        # must be nodal.

        if expr.op.dd_in.is_volume():
            dim = self.dim
        else:
            dim = self.dim - 1

        jac_in = sym.area_element(self.ambient_dim, dim, dd=expr.op.dd_in)
        jac_noquad = sym.area_element(self.ambient_dim, dim,
                dd=expr.op.dd_in.with_qtag(sym.QTAG_NONE))

        def rewrite_derivative(ref_class, field,  dd_in, with_jacobian=True):
            jac_tag = sym.area_element(self.ambient_dim, self.dim, dd=dd_in)

            rec_field = self.rec(field)
            if with_jacobian:
                rec_field = jac_tag * rec_field
            return sum(
                    sym.inverse_metric_derivative(
                        rst_axis, expr.op.xyz_axis,
                        ambient_dim=self.ambient_dim, dim=self.dim)
                    * ref_class(rst_axis, dd_in=dd_in)(rec_field)
                    for rst_axis in range(self.dim))

        if isinstance(expr.op, op.MassOperator):
            return op.RefMassOperator(expr.op.dd_in, expr.op.dd_out)(
                    jac_in * self.rec(expr.field))

        elif isinstance(expr.op, op.InverseMassOperator):
            return op.RefInverseMassOperator(expr.op.dd_in, expr.op.dd_out)(
                1/jac_in * self.rec(expr.field))

        elif isinstance(expr.op, op.FaceMassOperator):
            jac_in_surf = sym.area_element(self.ambient_dim, self.dim - 1,
                    dd=expr.op.dd_in)
            return op.RefFaceMassOperator(expr.op.dd_in, expr.op.dd_out)(
                    jac_in_surf * self.rec(expr.field))

        elif isinstance(expr.op, op.StiffnessOperator):
            return op.RefMassOperator()(
                    jac_noquad
                    * self.rec(
                        op.DiffOperator(expr.op.xyz_axis)(expr.field)))

        elif isinstance(expr.op, op.DiffOperator):
            return rewrite_derivative(
                    op.RefDiffOperator,
                    expr.field, dd_in=expr.op.dd_in, with_jacobian=False)

        elif isinstance(expr.op, op.StiffnessTOperator):
            return rewrite_derivative(
                    op.RefStiffnessTOperator,
                    expr.field, dd_in=expr.op.dd_in)

        elif isinstance(expr.op, op.MInvSTOperator):
            return self.rec(
                    op.InverseMassOperator()(
                        op.StiffnessTOperator(expr.op.xyz_axis)(
                            self.rec(expr.field))))

        else:
            return IdentityMapper.map_operator_binding(self, expr)