Exemplo n.º 1
0
def test_elementwise_reductions(actx_factory):
    actx = actx_factory()

    from mesh_data import BoxMeshBuilder
    builder = BoxMeshBuilder(ambient_dim=1)

    nelements = 4
    mesh = builder.get_mesh(nelements, builder.mesh_order)
    dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
    x = thaw(dcoll.nodes(), actx)

    def f(x):
        return actx.np.sin(x[0])

    field = f(x)
    mins = []
    maxs = []
    sums = []
    for gidx, grp_f in enumerate(field):
        min_res = np.empty(grp_f.shape)
        max_res = np.empty(grp_f.shape)
        sum_res = np.empty(grp_f.shape)
        for eidx in range(dcoll._volume_discr.groups[gidx].nelements):
            element_data = actx.to_numpy(grp_f[eidx])
            min_res[eidx, :] = np.min(element_data)
            max_res[eidx, :] = np.max(element_data)
            sum_res[eidx, :] = np.sum(element_data)
        mins.append(actx.from_numpy(min_res))
        maxs.append(actx.from_numpy(max_res))
        sums.append(actx.from_numpy(sum_res))

    from meshmode.dof_array import DOFArray, flat_norm

    ref_mins = DOFArray(actx, data=tuple(mins))
    ref_maxs = DOFArray(actx, data=tuple(maxs))
    ref_sums = DOFArray(actx, data=tuple(sums))

    elem_mins = op.elementwise_min(dcoll, field)
    elem_maxs = op.elementwise_max(dcoll, field)
    elem_sums = op.elementwise_sum(dcoll, field)

    assert flat_norm(elem_mins - ref_mins, ord=np.inf) < 1.e-15
    assert flat_norm(elem_maxs - ref_maxs, ord=np.inf) < 1.e-15
    assert flat_norm(elem_sums - ref_sums, ord=np.inf) < 1.e-15
Exemplo n.º 2
0
def test_surface_divergence_theorem(actx_factory, mesh_name, visualize=False):
    r"""Check the surface divergence theorem.

        .. math::

            \int_Sigma \phi \nabla_i f_i =
            \int_\Sigma \nabla_i \phi f_i +
            \int_\Sigma \kappa \phi f_i n_i +
            \int_{\partial \Sigma} \phi f_i m_i

        where :math:`n_i` is the surface normal and :class:`m_i` is the
        face normal (which should be orthogonal to both the surface normal
        and the face tangent).
    """
    actx = actx_factory()

    # {{{ cases

    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()
    elif mesh_name == "circle":
        from mesh_data import EllipseMeshBuilder
        builder = EllipseMeshBuilder(radius=1.0, aspect_ratio=1.0)
    elif mesh_name == "starfish":
        from mesh_data import StarfishMeshBuilder
        builder = StarfishMeshBuilder()
    elif mesh_name == "sphere":
        from mesh_data import SphereMeshBuilder
        builder = SphereMeshBuilder(radius=1.0, mesh_order=16)
    else:
        raise ValueError("unknown mesh name: %s" % mesh_name)

    # }}}

    # {{{ convergence

    def f(x):
        return flat_obj_array(
            actx.np.sin(3 * x[1]) + actx.np.cos(3 * x[0]) + 1.0,
            actx.np.sin(2 * x[0]) + actx.np.cos(x[1]),
            3.0 * actx.np.cos(x[0] / 2) + actx.np.cos(x[1]),
        )[:ambient_dim]

    from pytools.convergence import EOCRecorder
    eoc_global = EOCRecorder()
    eoc_local = EOCRecorder()

    theta = np.pi / 3.33
    ambient_dim = builder.ambient_dim
    if ambient_dim == 2:
        mesh_rotation = np.array([
            [np.cos(theta), -np.sin(theta)],
            [np.sin(theta), np.cos(theta)],
        ])
    else:
        mesh_rotation = np.array([
            [1.0, 0.0, 0.0],
            [0.0, np.cos(theta), -np.sin(theta)],
            [0.0, np.sin(theta), np.cos(theta)],
        ])

    mesh_offset = np.array([0.33, -0.21, 0.0])[:ambient_dim]

    for i, resolution in enumerate(builder.resolutions):
        from meshmode.mesh.processing import affine_map
        from meshmode.discretization.connection import FACE_RESTR_ALL

        mesh = builder.get_mesh(resolution, builder.mesh_order)
        mesh = affine_map(mesh, A=mesh_rotation, b=mesh_offset)

        from meshmode.discretization.poly_element import \
                QuadratureSimplexGroupFactory

        qtag = dof_desc.DISCR_TAG_QUAD
        dcoll = DiscretizationCollection(actx,
                                         mesh,
                                         order=builder.order,
                                         discr_tag_to_group_factory={
                                             qtag:
                                             QuadratureSimplexGroupFactory(
                                                 2 * builder.order)
                                         })

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

        dd = dof_desc.DD_VOLUME
        dq = dd.with_discr_tag(qtag)
        df = dof_desc.as_dofdesc(FACE_RESTR_ALL)
        ambient_dim = dcoll.ambient_dim

        # variables
        f_num = f(thaw(dcoll.nodes(dd=dd), actx))
        f_quad_num = f(thaw(dcoll.nodes(dd=dq), actx))

        from grudge.geometry import normal, summed_curvature

        kappa = summed_curvature(actx, dcoll, dd=dq)
        normal = normal(actx, dcoll, dd=dq)
        face_normal = thaw(dcoll.normal(df), actx)
        face_f = op.project(dcoll, dd, df, f_num)

        # operators
        stiff = op.mass(
            dcoll,
            sum(
                op.local_d_dx(dcoll, i, f_num_i)
                for i, f_num_i in enumerate(f_num)))
        stiff_t = sum(
            op.weak_local_d_dx(dcoll, i, f_num_i)
            for i, f_num_i in enumerate(f_num))
        kterm = op.mass(dcoll, dq, kappa * f_quad_num.dot(normal))
        flux = op.face_mass(dcoll, face_f.dot(face_normal))

        # sum everything up
        op_global = op.nodal_sum(dcoll, dd, stiff - (stiff_t + kterm))
        op_local = op.elementwise_sum(dcoll, dd,
                                      stiff - (stiff_t + kterm + flux))

        err_global = abs(op_global)
        err_local = op.norm(dcoll, op_local, np.inf)
        logger.info("errors: global %.5e local %.5e", err_global, err_local)

        # compute max element size
        from grudge.dt_utils import h_max_from_volume

        h_max = h_max_from_volume(dcoll)

        eoc_global.add_data_point(h_max, actx.to_numpy(err_global))
        eoc_local.add_data_point(h_max, err_local)

        if visualize:
            from grudge.shortcuts import make_visualizer
            vis = make_visualizer(dcoll)

            filename = f"surface_divergence_theorem_{mesh_name}_{i:04d}.vtu"
            vis.write_vtk_file(filename, [("r", actx.np.log10(op_local))],
                               overwrite=True)

    # }}}

    order = min(builder.order, builder.mesh_order) - 0.5
    logger.info("\n%s", str(eoc_global))
    logger.info("\n%s", str(eoc_local))

    assert eoc_global.max_error() < 1.0e-12 \
            or eoc_global.order_estimate() > order - 0.5

    assert eoc_local.max_error() < 1.0e-12 \
            or eoc_local.order_estimate() > order - 0.5
Exemplo n.º 3
0
def test_elementwise_reductions_with_container(actx_factory):
    actx = actx_factory()

    from mesh_data import BoxMeshBuilder
    builder = BoxMeshBuilder(ambient_dim=2)

    nelements = 4
    mesh = builder.get_mesh(nelements, builder.mesh_order)
    dcoll = DiscretizationCollection(actx, mesh, order=builder.order)
    x = thaw(dcoll.nodes(), actx)

    def f(x):
        return actx.np.sin(x[0]) * actx.np.sin(x[1])

    def g(x):
        return actx.np.cos(x[0]) * actx.np.cos(x[1])

    def h(x):
        return actx.np.cos(x[0]) * actx.np.sin(x[1])

    mass = 2 * f(x) + 0.5 * g(x)
    momentum = make_obj_array([f(x) / g(x), h(x)])
    enthalpy = 3 * h(x) - g(x)

    ary_container = MyContainer(name="container",
                                mass=mass,
                                momentum=momentum,
                                enthalpy=enthalpy)

    def _get_ref_data(field):
        mins = []
        maxs = []
        sums = []
        for grp_f in field:
            min_res = np.empty(grp_f.shape)
            max_res = np.empty(grp_f.shape)
            sum_res = np.empty(grp_f.shape)
            for eidx in range(dcoll.mesh.nelements):
                element_data = actx.to_numpy(grp_f[eidx])
                min_res[eidx, :] = np.min(element_data)
                max_res[eidx, :] = np.max(element_data)
                sum_res[eidx, :] = np.sum(element_data)
            mins.append(actx.from_numpy(min_res))
            maxs.append(actx.from_numpy(max_res))
            sums.append(actx.from_numpy(sum_res))
        min_field = DOFArray(actx, data=tuple(mins))
        max_field = DOFArray(actx, data=tuple(maxs))
        sums_field = DOFArray(actx, data=tuple(sums))
        return min_field, max_field, sums_field

    min_mass, max_mass, sums_mass = _get_ref_data(mass)
    min_enthalpy, max_enthalpy, sums_enthalpy = _get_ref_data(enthalpy)
    min_mom_x, max_mom_x, sums_mom_x = _get_ref_data(momentum[0])
    min_mom_y, max_mom_y, sums_mom_y = _get_ref_data(momentum[1])
    min_momentum = make_obj_array([min_mom_x, min_mom_y])
    max_momentum = make_obj_array([max_mom_x, max_mom_y])
    sums_momentum = make_obj_array([sums_mom_x, sums_mom_y])

    reference_min = MyContainer(name="Reference min",
                                mass=min_mass,
                                momentum=min_momentum,
                                enthalpy=min_enthalpy)

    reference_max = MyContainer(name="Reference max",
                                mass=max_mass,
                                momentum=max_momentum,
                                enthalpy=max_enthalpy)

    reference_sum = MyContainer(name="Reference sums",
                                mass=sums_mass,
                                momentum=sums_momentum,
                                enthalpy=sums_enthalpy)

    elem_mins = op.elementwise_min(dcoll, ary_container)
    elem_maxs = op.elementwise_max(dcoll, ary_container)
    elem_sums = op.elementwise_sum(dcoll, ary_container)

    assert actx.to_numpy(op.norm(dcoll, elem_mins - reference_min,
                                 np.inf)) < 1.e-14
    assert actx.to_numpy(op.norm(dcoll, elem_maxs - reference_max,
                                 np.inf)) < 1.e-14
    assert actx.to_numpy(op.norm(dcoll, elem_sums - reference_sum,
                                 np.inf)) < 1.e-14