예제 #1
0
파일: op.py 프로젝트: nchristensen/grudge
def _apply_mass_operator(dcoll: DiscretizationCollection, dd_out, dd_in, vec):
    if not isinstance(vec, DOFArray):
        return map_array_container(
            partial(_apply_mass_operator, dcoll, dd_out, dd_in), vec)

    from grudge.geometry import area_element

    in_discr = dcoll.discr_from_dd(dd_in)
    out_discr = dcoll.discr_from_dd(dd_out)

    actx = vec.array_context
    area_elements = area_element(
        actx,
        dcoll,
        dd=dd_in,
        _use_geoderiv_connection=actx.supports_nonscalar_broadcasting)
    return DOFArray(
        actx,
        data=tuple(
            actx.einsum("ij,ej,ej->ei",
                        reference_mass_matrix(actx,
                                              out_element_group=out_grp,
                                              in_element_group=in_grp),
                        ae_i,
                        vec_i,
                        arg_names=("mass_mat", "jac", "vec"),
                        tagged=(FirstAxisIsElementsTag(), ))
            for in_grp, out_grp, ae_i, vec_i in zip(
                in_discr.groups, out_discr.groups, area_elements, vec)))
예제 #2
0
파일: op.py 프로젝트: nchristensen/grudge
def _apply_face_mass_operator(dcoll: DiscretizationCollection, dd, vec):
    if not isinstance(vec, DOFArray):
        return map_array_container(
            partial(_apply_face_mass_operator, dcoll, dd), vec)

    from grudge.geometry import area_element

    volm_discr = dcoll.discr_from_dd(dof_desc.DD_VOLUME)
    face_discr = dcoll.discr_from_dd(dd)
    dtype = vec.entry_dtype
    actx = vec.array_context

    assert len(face_discr.groups) == len(volm_discr.groups)
    surf_area_elements = area_element(
        actx,
        dcoll,
        dd=dd,
        _use_geoderiv_connection=actx.supports_nonscalar_broadcasting)

    return DOFArray(
        actx,
        data=tuple(
            actx.einsum("ifj,fej,fej->ei",
                        reference_face_mass_matrix(actx,
                                                   face_element_group=afgrp,
                                                   vol_element_group=vgrp,
                                                   dtype=dtype),
                        surf_ae_i.reshape(vgrp.mesh_el_group.nfaces,
                                          vgrp.nelements, -1),
                        vec_i.reshape(vgrp.mesh_el_group.nfaces,
                                      vgrp.nelements, afgrp.nunit_dofs),
                        arg_names=("ref_face_mass_mat", "jac_surf", "vec"),
                        tagged=(FirstAxisIsElementsTag(), )) for vgrp, afgrp,
            vec_i, surf_ae_i in zip(volm_discr.groups, face_discr.groups, vec,
                                    surf_area_elements)))
예제 #3
0
파일: op.py 프로젝트: sll2/grudge
def _apply_inverse_mass_operator(dcoll: DiscretizationCollection, dd_out,
                                 dd_in, vec):
    if isinstance(vec, np.ndarray):
        return obj_array_vectorize(
            lambda vi: _apply_inverse_mass_operator(dcoll, dd_out, dd_in, vi),
            vec)

    from grudge.geometry import area_element

    if dd_out != dd_in:
        raise ValueError("Cannot compute inverse of a mass matrix mapping "
                         "between different element groups; inverse is not "
                         "guaranteed to be well-defined")

    actx = vec.array_context
    discr = dcoll.discr_from_dd(dd_in)
    inv_area_elements = 1. / area_element(actx, dcoll, dd=dd_in)
    group_data = []
    for grp, jac_inv, vec_i in zip(discr.groups, inv_area_elements, vec):

        ref_mass_inverse = reference_inverse_mass_matrix(actx,
                                                         element_group=grp)

        group_data.append(
            # Based on https://arxiv.org/pdf/1608.03836.pdf
            # true_Minv ~ ref_Minv * ref_M * (1/jac_det) * ref_Minv
            actx.einsum("ei,ij,ej->ei",
                        jac_inv,
                        ref_mass_inverse,
                        vec_i,
                        tagged=(FirstAxisIsElementsTag(), )))

    return DOFArray(actx, data=tuple(group_data))
예제 #4
0
파일: op.py 프로젝트: sll2/grudge
def _apply_mass_operator(dcoll: DiscretizationCollection, dd_out, dd_in, vec):
    if isinstance(vec, np.ndarray):
        return obj_array_vectorize(
            lambda vi: _apply_mass_operator(dcoll, dd_out, dd_in, vi), vec)

    from grudge.geometry import area_element

    in_discr = dcoll.discr_from_dd(dd_in)
    out_discr = dcoll.discr_from_dd(dd_out)

    actx = vec.array_context
    area_elements = area_element(actx, dcoll, dd=dd_in)
    return DOFArray(
        actx,
        data=tuple(
            actx.einsum("ij,ej,ej->ei",
                        reference_mass_matrix(actx,
                                              out_element_group=out_grp,
                                              in_element_group=in_grp),
                        ae_i,
                        vec_i,
                        arg_names=("mass_mat", "jac", "vec"),
                        tagged=(FirstAxisIsElementsTag(), ))
            for in_grp, out_grp, ae_i, vec_i in zip(
                in_discr.groups, out_discr.groups, area_elements, vec)))
예제 #5
0
파일: op.py 프로젝트: sll2/grudge
def _apply_stiffness_transpose_operator(dcoll: DiscretizationCollection,
                                        dd_out, dd_in, vec, xyz_axis):
    from grudge.geometry import \
        inverse_surface_metric_derivative, area_element

    in_discr = dcoll.discr_from_dd(dd_in)
    out_discr = dcoll.discr_from_dd(dd_out)

    actx = vec.array_context
    area_elements = area_element(actx, dcoll, dd=dd_in)
    inverse_jac_t = actx.np.stack([
        inverse_surface_metric_derivative(actx,
                                          dcoll,
                                          rst_axis,
                                          xyz_axis,
                                          dd=dd_in)
        for rst_axis in range(dcoll.dim)
    ])
    return DOFArray(
        actx,
        data=tuple(
            actx.einsum(
                "dij,ej,ej,dej->ei",
                reference_stiffness_transpose_matrix(
                    actx, out_element_group=out_grp, in_element_group=in_grp),
                ae_i,
                vec_i,
                inv_jac_t_i,
                arg_names=("ref_stiffT_mat", "jac", "vec", "inv_jac_t"),
                tagged=(FirstAxisIsElementsTag(), ))
            for out_grp, in_grp, vec_i, ae_i, inv_jac_t_i in zip(
                out_discr.groups, in_discr.groups, vec, area_elements,
                inverse_jac_t)))
예제 #6
0
파일: op.py 프로젝트: sll2/grudge
def _apply_face_mass_operator(dcoll: DiscretizationCollection, dd, vec):
    if isinstance(vec, np.ndarray):
        return obj_array_vectorize(
            lambda vi: _apply_face_mass_operator(dcoll, dd, vi), vec)

    from grudge.geometry import area_element

    volm_discr = dcoll.discr_from_dd(dof_desc.DD_VOLUME)
    face_discr = dcoll.discr_from_dd(dd)
    dtype = vec.entry_dtype
    actx = vec.array_context

    @memoize_in(actx, (_apply_face_mass_operator, "face_mass_knl"))
    def prg():
        t_unit = make_loopy_program([
            "{[iel]: 0 <= iel < nelements}", "{[f]: 0 <= f < nfaces}",
            "{[idof]: 0 <= idof < nvol_nodes}",
            "{[jdof]: 0 <= jdof < nface_nodes}"
        ],
                                    """
            result[iel, idof] = sum(f, sum(jdof, mat[idof, f, jdof]
                                                 * jac_surf[f, iel, jdof]
                                                 * vec[f, iel, jdof]))
            """,
                                    name="face_mass")
        import loopy as lp
        from meshmode.transform_metadata import (ConcurrentElementInameTag,
                                                 ConcurrentDOFInameTag)
        return lp.tag_inames(t_unit, {
            "iel": ConcurrentElementInameTag(),
            "idof": ConcurrentDOFInameTag()
        })

    assert len(face_discr.groups) == len(volm_discr.groups)
    surf_area_elements = area_element(actx, dcoll, dd=dd)

    return DOFArray(
        actx,
        data=tuple(
            actx.call_loopy(
                prg(),
                mat=reference_face_mass_matrix(actx,
                                               face_element_group=afgrp,
                                               vol_element_group=vgrp,
                                               dtype=dtype),
                jac_surf=surf_ae_i.reshape(vgrp.mesh_el_group.nfaces,
                                           vgrp.nelements, afgrp.nunit_dofs),
                vec=vec_i.reshape(vgrp.mesh_el_group.nfaces, vgrp.nelements,
                                  afgrp.nunit_dofs))["result"] for vgrp, afgrp,
            vec_i, surf_ae_i in zip(volm_discr.groups, face_discr.groups, vec,
                                    surf_area_elements)))
예제 #7
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)
    dcoll = DiscretizationCollection(actx, mesh, order=builder.order)

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

    # }}}

    # {{{ Compute surface and face normals
    from meshmode.discretization.connection import FACE_RESTR_INTERIOR
    from grudge.geometry import normal

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

    ambient_dim = mesh.ambient_dim

    surf_normal = op.project(dcoll, dv, df, normal(actx, dcoll, dd=dv))
    surf_normal = surf_normal / actx.np.sqrt(sum(surf_normal**2))

    face_normal_i = thaw(dcoll.normal(df), actx)
    face_normal_e = dcoll.opposite_face_connection()(face_normal_i)

    if mesh.ambient_dim == 3:
        from grudge.geometry import pseudoscalar, area_element
        # NOTE: there's only one face tangent in 3d
        face_tangent = (pseudoscalar(actx, dcoll, dd=df) /
                        area_element(actx, dcoll, dd=df)).as_vector(
                            dtype=object)

    # }}}

    # {{{ checks

    def _eval_error(x):
        return op.norm(dcoll, x, np.inf, dd=df)

    rtol = 1.0e-14

    # 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:
        error = _eval_error(face_tangent.dot(face_normal_i))
        logger.info("error[t_dot_i]:  %.5e", error)
        assert error < 5 * rtol