Пример #1
0
def test_direct(ctx_factory):
    # This evaluates a single layer potential on a circle.
    logging.basicConfig(level=logging.INFO)

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

    from sumpy.kernel import LaplaceKernel
    lknl = LaplaceKernel(2)

    order = 12

    from sumpy.qbx import LayerPotential
    from sumpy.expansion.local import LineTaylorLocalExpansion

    lpot = LayerPotential(ctx, [LineTaylorLocalExpansion(lknl, order)])

    mode_nr = 25

    from pytools.convergence import EOCRecorder

    eocrec = EOCRecorder()

    for n in [200, 300, 400]:
        t = np.linspace(0, 2 * np.pi, n, endpoint=False)
        unit_circle = np.exp(1j * t)
        unit_circle = np.array([unit_circle.real, unit_circle.imag])

        sigma = np.cos(mode_nr * t)
        eigval = 1 / (2 * mode_nr)

        result_ref = eigval * sigma

        h = 2 * np.pi / n

        targets = unit_circle
        sources = unit_circle

        radius = 7 * h
        centers = unit_circle * (1 - radius)

        expansion_radii = np.ones(n) * radius

        strengths = (sigma * h, )
        evt, (result_qbx, ) = lpot(queue,
                                   targets,
                                   sources,
                                   centers,
                                   strengths,
                                   expansion_radii=expansion_radii)

        eocrec.add_data_point(h, np.max(np.abs(result_ref - result_qbx)))

    print(eocrec)

    slack = 1.5
    assert eocrec.order_estimate() > order - slack
Пример #2
0
    def get_lpot_applier(self, kernels):
        # needs to be separate method for caching

        if any(knl.is_complex_valued for knl in kernels):
            value_dtype = self.density_discr.complex_dtype
        else:
            value_dtype = self.density_discr.real_dtype

        from sumpy.qbx import LayerPotential
        from sumpy.expansion.local import LineTaylorLocalExpansion
        return LayerPotential(
            self.cl_context,
            [LineTaylorLocalExpansion(knl, self.qbx_order) for knl in kernels],
            value_dtypes=value_dtype)
Пример #3
0
    def get_lpot_applier(self, target_kernels, source_kernels):
        # needs to be separate method for caching

        if any(knl.is_complex_valued for knl in target_kernels):
            value_dtype = self.density_discr.complex_dtype
        else:
            value_dtype = self.density_discr.real_dtype

        base_kernel = single_valued(knl.get_base_kernel() for knl in source_kernels)

        from sumpy.qbx import LayerPotential
        return LayerPotential(self.cl_context,
                    expansion=self.get_expansion_for_qbx_direct_eval(
                        base_kernel, target_kernels),
                    target_kernels=target_kernels, source_kernels=source_kernels,
                    value_dtypes=value_dtype)
Пример #4
0
    def get_lpot_applier(self, target_kernels, source_kernels):
        # needs to be separate method for caching

        if any(knl.is_complex_valued for knl in target_kernels):
            value_dtype = self.density_discr.complex_dtype
        else:
            value_dtype = self.density_discr.real_dtype

        base_kernel = single_valued(knl.get_base_kernel()
                                    for knl in source_kernels)

        from sumpy.qbx import LayerPotential
        from sumpy.expansion.local import LineTaylorLocalExpansion
        return LayerPotential(self.cl_context,
                              expansion=LineTaylorLocalExpansion(
                                  base_kernel, self.qbx_order),
                              target_kernels=target_kernels,
                              source_kernels=source_kernels,
                              value_dtypes=value_dtype)
Пример #5
0
def test_qbx_direct(ctx_factory, factor, lpot_id):
    logging.basicConfig(level=logging.INFO)

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

    ndim = 2
    nblks = 10
    order = 12
    mode_nr = 25

    from sumpy.kernel import LaplaceKernel, DirectionalSourceDerivative
    if lpot_id == 1:
        knl = LaplaceKernel(ndim)
    elif lpot_id == 2:
        knl = LaplaceKernel(ndim)
        knl = DirectionalSourceDerivative(knl, dir_vec_name="dsource_vec")
    else:
        raise ValueError("unknow lpot_id")

    from sumpy.expansion.local import LineTaylorLocalExpansion
    lknl = LineTaylorLocalExpansion(knl, order)

    from sumpy.qbx import LayerPotential
    lpot = LayerPotential(ctx, [lknl])

    from sumpy.qbx import LayerPotentialMatrixGenerator
    mat_gen = LayerPotentialMatrixGenerator(ctx, [lknl])

    from sumpy.qbx import LayerPotentialMatrixBlockGenerator
    blk_gen = LayerPotentialMatrixBlockGenerator(ctx, [lknl])

    for n in [200, 300, 400]:
        targets, sources, centers, expansion_radii, sigma = \
                _build_geometry(queue, n, mode_nr, target_radius=1.2)

        h = 2 * np.pi / n
        strengths = (sigma * h, )

        tgtindices = _build_block_index(queue, n, nblks, factor)
        srcindices = _build_block_index(queue, n, nblks, factor)
        index_set = MatrixBlockIndexRanges(ctx, tgtindices, srcindices)

        extra_kwargs = {}
        if lpot_id == 2:
            from pytools.obj_array import make_obj_array
            extra_kwargs["dsource_vec"] = \
                    vector_to_device(queue, make_obj_array(np.ones((ndim, n))))

        _, (result_lpot, ) = lpot(queue,
                                  targets=targets,
                                  sources=sources,
                                  centers=centers,
                                  expansion_radii=expansion_radii,
                                  strengths=strengths,
                                  **extra_kwargs)
        result_lpot = result_lpot.get()

        _, (mat, ) = mat_gen(queue,
                             targets=targets,
                             sources=sources,
                             centers=centers,
                             expansion_radii=expansion_radii,
                             **extra_kwargs)
        mat = mat.get()
        result_mat = mat.dot(strengths[0].get())

        _, (blk, ) = blk_gen(queue,
                             targets=targets,
                             sources=sources,
                             centers=centers,
                             expansion_radii=expansion_radii,
                             index_set=index_set,
                             **extra_kwargs)
        blk = blk.get()

        rowindices = index_set.linear_row_indices.get(queue)
        colindices = index_set.linear_col_indices.get(queue)

        eps = 1.0e-10 * la.norm(result_lpot)
        assert la.norm(result_mat - result_lpot) < eps
        assert la.norm(blk - mat[rowindices, colindices]) < eps
Пример #6
0
def main():
    import logging
    logging.basicConfig(level=logging.INFO)

    ctx = cl.create_some_context()
    queue = cl.CommandQueue(ctx)

    if 1:
        ext = 0.5
        mesh = generate_regular_rect_mesh(a=(-ext / 2, -ext / 2),
                                          b=(ext / 2, ext / 2),
                                          n=(int(ext / h), int(ext / h)))
    else:
        mesh = generate_gmsh(FileSource("circle.step"),
                             2,
                             order=mesh_order,
                             force_ambient_dim=2,
                             other_options=[
                                 "-string",
                                 "Mesh.CharacteristicLengthMax = %g;" % h
                             ])

    logger.info("%d elements" % mesh.nelements)

    # {{{ discretizations and connections

    vol_discr = Discretization(
        ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(vol_quad_order))
    ovsmp_vol_discr = Discretization(
        ctx, mesh,
        InterpolatoryQuadratureSimplexGroupFactory(vol_ovsmp_quad_order))

    from meshmode.mesh import BTAG_ALL
    from meshmode.discretization.connection import (make_face_restriction,
                                                    make_same_mesh_connection)
    bdry_connection = make_face_restriction(
        vol_discr, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order),
        BTAG_ALL)

    bdry_discr = bdry_connection.to_discr

    vol_to_ovsmp_vol = make_same_mesh_connection(ovsmp_vol_discr, vol_discr)

    # }}}

    # {{{ visualizers

    vol_vis = make_visualizer(queue, vol_discr, 20)
    bdry_vis = make_visualizer(queue, bdry_discr, 20)

    # }}}

    vol_x = vol_discr.nodes().with_queue(queue)
    ovsmp_vol_x = ovsmp_vol_discr.nodes().with_queue(queue)

    rhs = rhs_func(vol_x[0], vol_x[1])
    poisson_true_sol = sol_func(vol_x[0], vol_x[1])

    vol_vis.write_vtk_file("volume.vtu", [("f", rhs)])

    bdry_normals = bind(bdry_discr, p.normal(
        mesh.ambient_dim))(queue).as_vector(dtype=object)
    bdry_vis.write_vtk_file("boundary.vtu", [("normals", bdry_normals)])

    bdry_nodes = bdry_discr.nodes().with_queue(queue)
    bdry_f = rhs_func(bdry_nodes[0], bdry_nodes[1])
    bdry_f_2 = bdry_connection(queue, rhs)

    bdry_vis.write_vtk_file("y.vtu", [("f", bdry_f_2)])

    if 0:
        vol_vis.show_scalar_in_mayavi(rhs, do_show=False)
        bdry_vis.show_scalar_in_mayavi(bdry_f - bdry_f_2,
                                       line_width=10,
                                       do_show=False)

        import mayavi.mlab as mlab
        mlab.colorbar()
        mlab.show()

    # {{{ compute volume potential

    from sumpy.qbx import LayerPotential
    from sumpy.expansion.local import LineTaylorLocalExpansion

    def get_kernel():
        from sumpy.symbolic import pymbolic_real_norm_2
        from pymbolic.primitives import make_sym_vector
        from pymbolic import var

        d = make_sym_vector("d", 3)
        r = pymbolic_real_norm_2(d[:-1])
        # r3d = pymbolic_real_norm_2(d)
        #expr = var("log")(r3d)

        log = var("log")
        sqrt = var("sqrt")

        a = d[-1]

        expr = log(r)
        expr = log(sqrt(r**2 + a**2))
        expr = log(sqrt(r + a**2))
        #expr = log(sqrt(r**2 + a**2))-a**2/2/(r**2+a**2)
        #expr = 2*log(sqrt(r**2 + a**2))

        scaling = 1 / (2 * var("pi"))

        from sumpy.kernel import ExpressionKernel
        return ExpressionKernel(dim=3,
                                expression=expr,
                                global_scaling_const=scaling,
                                is_complex_valued=False)

    laplace_2d_in_3d_kernel = get_kernel()

    layer_pot = LayerPotential(
        ctx, [LineTaylorLocalExpansion(laplace_2d_in_3d_kernel, order=0)])

    targets = cl.array.zeros(queue, (3, ) + vol_x.shape[1:], vol_x.dtype)
    targets[:2] = vol_x

    center_dist = 0.125 * np.min(
        cl.clmath.sqrt(
            bind(vol_discr, p.area_element(mesh.ambient_dim,
                                           mesh.dim))(queue)).get())

    centers = make_obj_array(
        [ci.copy().reshape(vol_discr.nnodes) for ci in targets])
    centers[2][:] = center_dist

    print(center_dist)

    sources = cl.array.zeros(queue, (3, ) + ovsmp_vol_x.shape[1:],
                             ovsmp_vol_x.dtype)
    sources[:2] = ovsmp_vol_x

    ovsmp_rhs = vol_to_ovsmp_vol(queue, rhs)
    ovsmp_vol_weights = bind(
        ovsmp_vol_discr,
        p.area_element(mesh.ambient_dim, mesh.dim) * p.QWeight())(queue)

    print("volume: %d source nodes, %d target nodes" %
          (ovsmp_vol_discr.nnodes, vol_discr.nnodes))
    evt, (vol_pot, ) = layer_pot(
        queue,
        targets=targets.reshape(3, vol_discr.nnodes),
        centers=centers,
        sources=sources.reshape(3, ovsmp_vol_discr.nnodes),
        strengths=((ovsmp_vol_weights * ovsmp_rhs).reshape(
            ovsmp_vol_discr.nnodes), ),
        expansion_radii=np.zeros(vol_discr.nnodes),
    )

    vol_pot_bdry = bdry_connection(queue, vol_pot)

    # }}}

    # {{{ solve bvp

    from sumpy.kernel import LaplaceKernel
    from pytential.symbolic.pde.scalar import DirichletOperator
    op = DirichletOperator(LaplaceKernel(2), -1, use_l2_weighting=True)

    sym_sigma = sym.var("sigma")
    op_sigma = op.operator(sym_sigma)

    from pytential.qbx import QBXLayerPotentialSource
    qbx = QBXLayerPotentialSource(
        bdry_discr,
        fine_order=bdry_ovsmp_quad_order,
        qbx_order=qbx_order,
        fmm_order=fmm_order,
    )

    bound_op = bind(qbx, op_sigma)

    poisson_bc = poisson_bc_func(bdry_nodes[0], bdry_nodes[1])
    bvp_bc = poisson_bc - vol_pot_bdry
    bdry_f = rhs_func(bdry_nodes[0], bdry_nodes[1])

    bvp_rhs = bind(bdry_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bvp_bc)

    from pytential.solve import gmres
    gmres_result = gmres(bound_op.scipy_op(queue, "sigma", dtype=np.float64),
                         bvp_rhs,
                         tol=1e-14,
                         progress=True,
                         hard_failure=False)

    sigma = gmres_result.solution
    print("gmres state:", gmres_result.state)

    # }}}

    bvp_sol = bind((qbx, vol_discr), op.representation(sym_sigma))(queue,
                                                                   sigma=sigma)

    poisson_sol = bvp_sol + vol_pot
    poisson_err = poisson_sol - poisson_true_sol

    rel_err = (norm(vol_discr, queue, poisson_err) /
               norm(vol_discr, queue, poisson_true_sol))
    bdry_vis.write_vtk_file("poisson-boundary.vtu", [
        ("vol_pot_bdry", vol_pot_bdry),
        ("sigma", sigma),
    ])

    vol_vis.write_vtk_file("poisson-volume.vtu", [
        ("bvp_sol", bvp_sol),
        ("poisson_sol", poisson_sol),
        ("poisson_true_sol", poisson_true_sol),
        ("poisson_err", poisson_err),
        ("vol_pot", vol_pot),
        ("rhs", rhs),
    ])

    print("h = %s" % h)
    print("mesh_order = %s" % mesh_order)
    print("vol_quad_order = %s" % vol_quad_order)
    print("vol_ovsmp_quad_order = %s" % vol_ovsmp_quad_order)
    print("bdry_quad_order = %s" % bdry_quad_order)
    print("bdry_ovsmp_quad_order = %s" % bdry_ovsmp_quad_order)
    print("qbx_order = %s" % qbx_order)
    #print("vol_qbx_order = %s" % vol_qbx_order)
    print("fmm_order = %s" % fmm_order)
    print()
    print("rel err: %g" % rel_err)
Пример #7
0
def draw_pot_figure(aspect_ratio,
                    nsrc=100,
                    novsmp=None,
                    helmholtz_k=0,
                    what_operator="S",
                    what_operator_lpot=None,
                    order=4,
                    ovsmp_center_exp=0.66,
                    force_center_side=None):

    import logging
    logging.basicConfig(level=logging.INFO)

    if novsmp is None:
        novsmp = 4 * nsrc

    if what_operator_lpot is None:
        what_operator_lpot = what_operator

    ctx = cl.create_some_context()
    queue = cl.CommandQueue(ctx)

    # {{{ make plot targets

    center = np.asarray([0, 0], dtype=np.float64)
    from sumpy.visualization import FieldPlotter
    fp = FieldPlotter(center, npoints=1000, extent=6)

    # }}}

    # {{{ make p2p kernel calculator

    from sumpy.p2p import P2P
    from sumpy.kernel import LaplaceKernel, HelmholtzKernel
    from sumpy.expansion.local import H2DLocalExpansion, LineTaylorLocalExpansion
    if helmholtz_k:
        if isinstance(helmholtz_k, complex):
            knl = HelmholtzKernel(2, allow_evanescent=True)
            expn_class = H2DLocalExpansion
            knl_kwargs = {"k": helmholtz_k}
        else:
            knl = HelmholtzKernel(2)
            expn_class = H2DLocalExpansion
            knl_kwargs = {"k": helmholtz_k}

    else:
        knl = LaplaceKernel(2)
        expn_class = LineTaylorLocalExpansion
        knl_kwargs = {}

    vol_knl = process_kernel(knl, what_operator)
    p2p = P2P(ctx, [vol_knl], exclude_self=False, value_dtypes=np.complex128)

    lpot_knl = process_kernel(knl, what_operator_lpot)

    from sumpy.qbx import LayerPotential
    lpot = LayerPotential(ctx, [expn_class(lpot_knl, order=order)],
                          value_dtypes=np.complex128)

    # }}}

    # {{{ set up geometry

    # r,a,b match the corresponding letters from G. J. Rodin and O. Steinbach,
    # Boundary Element Preconditioners for problems defined on slender domains.
    # http://dx.doi.org/10.1137/S1064827500372067

    a = 1
    b = 1 / aspect_ratio

    def map_to_curve(t):
        t = t * (2 * np.pi)

        x = a * np.cos(t)
        y = b * np.sin(t)

        w = (np.zeros_like(t) + 1) / len(t)

        return x, y, w

    from curve import CurveGrid

    native_t = np.linspace(0, 1, nsrc, endpoint=False)
    native_x, native_y, native_weights = map_to_curve(native_t)
    native_curve = CurveGrid(native_x, native_y)

    ovsmp_t = np.linspace(0, 1, novsmp, endpoint=False)
    ovsmp_x, ovsmp_y, ovsmp_weights = map_to_curve(ovsmp_t)
    ovsmp_curve = CurveGrid(ovsmp_x, ovsmp_y)

    curve_len = np.sum(ovsmp_weights * ovsmp_curve.speed)
    hovsmp = curve_len / novsmp
    center_dist = 5 * hovsmp

    if force_center_side is not None:
        center_side = force_center_side * np.ones(len(native_curve))
    else:
        center_side = -np.sign(native_curve.mean_curvature)

    centers = (native_curve.pos +
               center_side[:, np.newaxis] * center_dist * native_curve.normal)

    #native_curve.plot()
    #pt.show()

    volpot_kwargs = knl_kwargs.copy()
    lpot_kwargs = knl_kwargs.copy()

    if what_operator == "D":
        volpot_kwargs["src_derivative_dir"] = native_curve.normal

    if what_operator_lpot == "D":
        lpot_kwargs["src_derivative_dir"] = ovsmp_curve.normal

    if what_operator_lpot == "S'":
        lpot_kwargs["tgt_derivative_dir"] = native_curve.normal

    # }}}

    if 0:
        # {{{ build matrix

        from fourier import make_fourier_interp_matrix
        fim = make_fourier_interp_matrix(novsmp, nsrc)
        from sumpy.tools import build_matrix
        from scipy.sparse.linalg import LinearOperator

        def apply_lpot(x):
            xovsmp = np.dot(fim, x)
            evt, (y, ) = lpot(queue,
                              native_curve.pos,
                              ovsmp_curve.pos,
                              centers,
                              [xovsmp * ovsmp_curve.speed * ovsmp_weights],
                              expansion_radii=np.ones(centers.shape[1]),
                              **lpot_kwargs)

            return y

        op = LinearOperator((nsrc, nsrc), apply_lpot)
        mat = build_matrix(op, dtype=np.complex128)
        w, v = la.eig(mat)
        pt.plot(w.real, "o-")
        #import sys; sys.exit(0)
        return

        # }}}

    # {{{ compute potentials

    mode_nr = 0
    density = np.cos(mode_nr * 2 * np.pi * native_t).astype(np.complex128)
    ovsmp_density = np.cos(mode_nr * 2 * np.pi * ovsmp_t).astype(np.complex128)
    evt, (vol_pot, ) = p2p(queue, fp.points, native_curve.pos,
                           [native_curve.speed * native_weights * density],
                           **volpot_kwargs)

    evt, (curve_pot, ) = lpot(
        queue,
        native_curve.pos,
        ovsmp_curve.pos,
        centers, [ovsmp_density * ovsmp_curve.speed * ovsmp_weights],
        expansion_radii=np.ones(centers.shape[1]),
        **lpot_kwargs)

    # }}}

    if 0:
        # {{{ plot on-surface potential in 2D

        pt.plot(curve_pot, label="pot")
        pt.plot(density, label="dens")
        pt.legend()
        pt.show()

        # }}}

    fp.write_vtk_file("potential.vts", [("potential", vol_pot.real)])

    if 0:
        # {{{ 2D false-color plot

        pt.clf()
        plotval = np.log10(1e-20 + np.abs(vol_pot))
        im = fp.show_scalar_in_matplotlib(plotval.real)
        from matplotlib.colors import Normalize
        im.set_norm(Normalize(vmin=-2, vmax=1))

        src = native_curve.pos
        pt.plot(src[:, 0], src[:, 1], "o-k")
        # close the curve
        pt.plot(src[-1::-len(src) + 1, 0], src[-1::-len(src) + 1, 1], "o-k")

        #pt.gca().set_aspect("equal", "datalim")
        cb = pt.colorbar(shrink=0.9)
        cb.set_label(r"$\log_{10}(\mathdefault{Error})$")
        #from matplotlib.ticker import NullFormatter
        #pt.gca().xaxis.set_major_formatter(NullFormatter())
        #pt.gca().yaxis.set_major_formatter(NullFormatter())
        fp.set_matplotlib_limits()

        # }}}
    else:
        # {{{ 3D plots

        plotval_vol = vol_pot.real
        plotval_c = curve_pot.real

        scale = 1

        if 0:
            # crop singularities--doesn't work very well
            neighbors = [
                np.roll(plotval_vol, 3, 0),
                np.roll(plotval_vol, -3, 0),
                np.roll(plotval_vol, 6, 0),
                np.roll(plotval_vol, -6, 0),
            ]
            avg = np.average(np.abs(plotval_vol))
            outlier_flag = sum(np.abs(plotval_vol - nb)
                               for nb in neighbors) > avg
            plotval_vol[outlier_flag] = sum(
                nb[outlier_flag] for nb in neighbors) / len(neighbors)

        fp.show_scalar_in_mayavi(scale * plotval_vol, max_val=1)
        from mayavi import mlab
        mlab.colorbar()
        if 1:
            mlab.points3d(native_curve.pos[0],
                          native_curve.pos[1],
                          scale * plotval_c,
                          scale_factor=0.02)
        mlab.show()