Example #1
0
def test_block_builder(ctx_factory,
                       ambient_dim,
                       block_builder_type,
                       index_sparsity_factor,
                       op_type,
                       visualize=False):
    """Test that block builders and full matrix builders actually match."""

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)
    actx = PyOpenCLArrayContext(queue)

    # prevent cache explosion
    from sympy.core.cache import clear_cache
    clear_cache()

    if ambient_dim == 2:
        case = extra.CurveTestCase(
            name="ellipse",
            target_order=7,
            index_sparsity_factor=index_sparsity_factor,
            op_type=op_type,
            resolutions=[32],
            curve_fn=partial(ellipse, 3.0),
        )
Example #2
0
        for i in range(indices.nblocks):
            isrc = indices.block_indices(i)
            marker[isrc] = 10.0 * (i + 1.0)

        from meshmode.dof_array import unflatten
        marker = unflatten(actx, discr, actx.from_numpy(marker))

        vis = make_visualizer(actx, discr, 10)

        filename = "test_partition_{0}_{1}_{3}d_{2}.vtu".format(*args)
        vis.write_vtk_file(filename, [("marker", marker)])


PROXY_TEST_CASES = [
    extra.CurveTestCase(name="ellipse",
                        target_order=7,
                        curve_fn=partial(ellipse, 3.0)),
    extra.TorusTestCase(target_order=2, resolutions=[0])
]


@pytest.mark.skip(reason="only useful with visualize=True")
@pytest.mark.parametrize("tree_kind", ['adaptive', None])
@pytest.mark.parametrize("case", PROXY_TEST_CASES)
def test_partition_points(ctx_factory, tree_kind, case, visualize=False):
    """Tests that the points are correctly partitioned (by visualization)."""

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)
    actx = PyOpenCLArrayContext(queue)
                mesh = merge_disjoint_meshes([mesh, discr.mesh])
                discr = Discretization(
                    actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(4))

                vis = make_visualizer(actx, discr)
                filename = f"test_proxy_geometry_{suffix}_block_{i:04d}.vtu"
                vis.write_vtk_file(filename, [], overwrite=False)
    else:
        raise ValueError


# }}}

PROXY_TEST_CASES = [
    extra.CurveTestCase(name="ellipse",
                        target_order=7,
                        curve_fn=partial(ellipse, 3.0)),
    extra.CurveTestCase(name="starfish",
                        target_order=4,
                        curve_fn=NArmedStarfish(5, 0.25),
                        resolutions=[32]),
    extra.TorusTestCase(target_order=2, resolutions=[0])
]

# {{{ test_partition_points


@pytest.mark.parametrize("tree_kind", ["adaptive", None])
@pytest.mark.parametrize("case", PROXY_TEST_CASES)
def test_partition_points(actx_factory, tree_kind, case, visualize=False):
    """Tests that the points are correctly partitioned."""
Example #4
0
def test_build_matrix(ctx_factory, k, curve_fn, op_type, visualize=False):
    """Checks that the matrix built with `symbolic.execution.build_matrix`
    gives the same (to tolerance) answer as a direct evaluation.
    """

    cl_ctx = ctx_factory()
    queue = cl.CommandQueue(cl_ctx)
    actx = PyOpenCLArrayContext(queue)

    # prevent cache 'splosion
    from sympy.core.cache import clear_cache
    clear_cache()

    case = extra.CurveTestCase(name="curve",
                               knl_class_or_helmholtz_k=k,
                               curve_fn=curve_fn,
                               op_type=op_type,
                               target_order=7,
                               qbx_order=4,
                               resolutions=[30])

    logger.info("\n%s", case)

    # {{{ geometry

    qbx = case.get_layer_potential(actx, case.resolutions[-1],
                                   case.target_order)

    from pytential.qbx.refinement import refine_geometry_collection
    places = GeometryCollection(qbx, auto_where=case.name)
    places = refine_geometry_collection(places,
                                        kernel_length_scale=(5 /
                                                             k if k else None))

    dd = places.auto_source.to_stage1()
    density_discr = places.get_discretization(dd.geometry)

    logger.info("nelements:     %d", density_discr.mesh.nelements)
    logger.info("ndofs:         %d", density_discr.ndofs)

    # }}}

    # {{{ symbolic

    sym_u, sym_op = case.get_operator(places.ambient_dim)
    bound_op = bind(places, sym_op)

    # }}}

    # {{{ dense matrix

    from pytential.symbolic.execution import build_matrix
    mat = actx.to_numpy(
        build_matrix(actx,
                     places,
                     sym_op,
                     sym_u,
                     context=case.knl_concrete_kwargs))

    if visualize:
        try:
            import matplotlib.pyplot as pt
        except ImportError:
            visualize = False

    if visualize:
        from sumpy.tools import build_matrix as build_matrix_via_matvec
        mat2 = bound_op.scipy_op(actx,
                                 "u",
                                 dtype=mat.dtype,
                                 **case.knl_concrete_kwargs)
        mat2 = build_matrix_via_matvec(mat2)

        logger.info(
            "real %.5e imag %.5e",
            la.norm((mat - mat2).real, "fro") / la.norm(mat2.real, "fro"),
            la.norm((mat - mat2).imag, "fro") / la.norm(mat2.imag, "fro"))

        pt.subplot(121)
        pt.imshow(np.log10(np.abs(1.0e-20 + (mat - mat2).real)))
        pt.colorbar()
        pt.subplot(122)
        pt.imshow(np.log10(np.abs(1.0e-20 + (mat - mat2).imag)))
        pt.colorbar()
        pt.show()
        pt.clf()

    if visualize:
        pt.subplot(121)
        pt.imshow(mat.real)
        pt.colorbar()
        pt.subplot(122)
        pt.imshow(mat.imag)
        pt.colorbar()
        pt.show()
        pt.clf()

    # }}}

    # {{{ check

    from pytential.utils import unflatten_from_numpy, flatten_to_numpy

    np.random.seed(12)
    for i in range(5):
        if isinstance(sym_u, np.ndarray):
            u = make_obj_array([
                np.random.randn(density_discr.ndofs) for _ in range(len(sym_u))
            ])
        else:
            u = np.random.randn(density_discr.ndofs)
        u_dev = unflatten_from_numpy(actx, density_discr, u)

        res_matvec = np.hstack(
            flatten_to_numpy(
                actx, bound_op(actx, u=u_dev, **case.knl_concrete_kwargs)))
        res_mat = mat.dot(np.hstack(u))

        abs_err = la.norm(res_mat - res_matvec, np.inf)
        rel_err = abs_err / la.norm(res_matvec, np.inf)

        logger.info("AbsErr {:.5e} RelErr {:.5e}".format(abs_err, rel_err))
        assert rel_err < 1.0e-13, 'iteration: {}'.format(i)
Example #5
0
def test_build_matrix_fixed_stage(ctx_factory,
                                  source_discr_stage,
                                  target_discr_stage,
                                  visualize=False):
    """Checks that the block builders match for difference stages."""

    ctx = ctx_factory()
    queue = cl.CommandQueue(ctx)
    actx = PyOpenCLArrayContext(queue)

    # prevent cache explosion
    from sympy.core.cache import clear_cache
    clear_cache()

    case = extra.CurveTestCase(
        name="starfish",
        curve_fn=NArmedStarfish(5, 0.25),
        target_order=4,
        resolutions=[32],
        index_sparsity_factor=0.6,
        op_type="scalar",
        tree_kind=None,
    )

    logger.info("\n%s", case)

    # {{{ geometry

    dd = sym.DOFDescriptor(case.name)
    qbx = case.get_layer_potential(actx, case.resolutions[-1],
                                   case.target_order)

    places = GeometryCollection(
        {case.name: qbx},
        auto_where=(dd.copy(discr_stage=source_discr_stage),
                    dd.copy(discr_stage=target_discr_stage)))

    dd = places.auto_source
    density_discr = places.get_discretization(dd.geometry, dd.discr_stage)

    # }}}

    # {{{ symbolic

    if source_discr_stage is target_discr_stage:
        qbx_forced_limit = -1
    else:
        qbx_forced_limit = None

    sym_u, sym_op = case.get_operator(places.ambient_dim, qbx_forced_limit)

    from pytential.symbolic.execution import _prepare_expr
    sym_prep_op = _prepare_expr(places, sym_op)

    # }}}

    # {{{ check

    source_discr = places.get_discretization(case.name, source_discr_stage)
    target_discr = places.get_discretization(case.name, target_discr_stage)

    logger.info("nelements:     %d", density_discr.mesh.nelements)
    logger.info("ndofs:         %d", source_discr.ndofs)
    logger.info("ndofs:         %d", target_discr.ndofs)

    icols = case.get_block_indices(actx, source_discr, matrix_indices=False)
    irows = case.get_block_indices(actx, target_discr, matrix_indices=False)
    index_set = MatrixBlockIndexRanges(actx.context, icols, irows)

    kwargs = dict(
        dep_expr=sym_u,
        other_dep_exprs=[],
        dep_source=places.get_geometry(case.name),
        dep_discr=density_discr,
        places=places,
        context=case.knl_concrete_kwargs,
    )

    # qbx
    from pytential.symbolic import matrix
    mat = matrix.MatrixBuilder(actx, **kwargs)(sym_prep_op)
    blk = matrix.NearFieldBlockBuilder(actx, index_set=index_set,
                                       **kwargs)(sym_prep_op)

    assert mat.shape == (target_discr.ndofs, source_discr.ndofs)
    assert extra.max_block_error(mat, blk, index_set.get(queue)) < 1.0e-14

    # p2p
    mat = matrix.P2PMatrixBuilder(actx, exclude_self=True,
                                  **kwargs)(sym_prep_op)
    blk = matrix.FarFieldBlockBuilder(actx,
                                      index_set=index_set,
                                      exclude_self=True,
                                      **kwargs)(sym_prep_op)

    assert mat.shape == (target_discr.ndofs, source_discr.ndofs)
    assert extra.max_block_error(mat, blk, index_set.get(queue)) < 1.0e-14
Example #6
0
def test_build_matrix_conditioning(actx_factory,
                                   side,
                                   op_type,
                                   visualize=False):
    """Checks that :math:`I + K`, where :math:`K` is compact gives a
    well-conditioned operator when it should. For example, the exterior Laplace
    problem has a nullspace, so we check that and remove it.
    """

    actx = actx_factory()

    # prevent cache explosion
    from sympy.core.cache import clear_cache
    clear_cache()

    case = extra.CurveTestCase(
        name="ellipse",
        curve_fn=lambda t: ellipse(3.0, t),
        target_order=16,
        source_ovsmp=1,
        qbx_order=4,
        resolutions=[64],
        op_type=op_type,
        side=side,
    )
    logger.info("\n%s", case)

    # {{{ geometry

    qbx = case.get_layer_potential(actx, case.resolutions[-1],
                                   case.target_order)

    from pytential.qbx.refinement import refine_geometry_collection
    places = GeometryCollection(qbx, auto_where=case.name)
    places = refine_geometry_collection(
        places, refine_discr_stage=sym.QBX_SOURCE_QUAD_STAGE2)

    dd = places.auto_source.to_stage1()
    density_discr = places.get_discretization(dd.geometry)

    logger.info("nelements:     %d", density_discr.mesh.nelements)
    logger.info("ndofs:         %d", density_discr.ndofs)

    # }}}

    # {{{ check matrix

    from pytential.symbolic.execution import build_matrix
    sym_u, sym_op = case.get_operator(places.ambient_dim,
                                      qbx_forced_limit="avg")

    mat = actx.to_numpy(
        build_matrix(actx,
                     places,
                     sym_op,
                     sym_u,
                     context=case.knl_concrete_kwargs))

    kappa = la.cond(mat)
    _, sigma, _ = la.svd(mat)

    logger.info("cond: %.5e sigma_max %.5e", kappa, sigma[0])

    # NOTE: exterior Laplace has a nullspace
    if side == +1 and op_type == "double":
        assert kappa > 1.0e+9
        assert sigma[-1] < 1.0e-9
    else:
        assert kappa < 1.0e+1
        assert sigma[-1] > 1.0e-2

    # remove the nullspace and check that it worked
    if side == +1 and op_type == "double":
        # NOTE: this adds the "mean" to remove the nullspace for the operator
        # See `pytential.symbolic.pde.scalar` for the equivalent formulation
        w = actx.to_numpy(
            flatten(
                bind(places,
                     sym.sqrt_jac_q_weight(places.ambient_dim)**2)(actx),
                actx))

        w = np.tile(w.reshape(-1, 1), w.size).T
        kappa = la.cond(mat + w)

        assert kappa < 1.0e+2

    # }}}

    # {{{ plot

    if not visualize:
        return

    side = "int" if side == -1 else "ext"

    import matplotlib.pyplot as plt
    plt.imshow(mat)
    plt.colorbar()
    plt.title(fr"$\kappa(A) = {kappa:.5e}$")
    plt.savefig(f"test_cond_{op_type}_{side}_mat")
    plt.clf()

    plt.plot(sigma)
    plt.ylabel(r"$\sigma$")
    plt.grid()
    plt.savefig(f"test_cond_{op_type}_{side}_svd")
    plt.clf()