def test_line_taylor_coeff_growth(): # Regression test for LineTaylorLocalExpansion. # See https://gitlab.tiker.net/inducer/pytential/merge_requests/12 from sumpy.kernel import LaplaceKernel from sumpy.expansion.local import LineTaylorLocalExpansion from sumpy.symbolic import make_sym_vector, SympyToPymbolicMapper import numpy as np order = 10 expn = LineTaylorLocalExpansion(LaplaceKernel(2), order) avec = make_sym_vector("a", 2) bvec = make_sym_vector("b", 2) coeffs = expn.coefficients_from_source(avec, bvec, rscale=1) sym2pymbolic = SympyToPymbolicMapper() coeffs_pymbolic = [sym2pymbolic(c) for c in coeffs] from pymbolic.mapper.flop_counter import FlopCounter flop_counter = FlopCounter() counts = [flop_counter(c) for c in coeffs_pymbolic] indices = np.arange(1, order + 2) max_order = 2 assert np.polyfit(np.log(indices), np.log(counts), deg=1)[0] < max_order
def map_int_g(self, expr): lpot_source = self.places.get_geometry(expr.source.geometry) source_discr = self.places.get_discretization(expr.source.geometry, expr.source.discr_stage) target_discr = self.places.get_discretization(expr.target.geometry, expr.target.discr_stage) if source_discr is not target_discr: raise NotImplementedError rec_density = self._blk_mapper.rec(expr.density) if is_zero(rec_density): return 0 if not np.isscalar(rec_density): raise NotImplementedError actx = self.array_context kernel = expr.kernel kernel_args = _get_layer_potential_args(self._mat_mapper, expr) from sumpy.expansion.local import LineTaylorLocalExpansion local_expn = LineTaylorLocalExpansion(kernel, lpot_source.qbx_order) from sumpy.qbx import LayerPotentialMatrixBlockGenerator mat_gen = LayerPotentialMatrixBlockGenerator(actx.context, (local_expn, )) assert abs(expr.qbx_forced_limit) > 0 from pytential import bind, sym radii = bind( self.places, sym.expansion_radii(source_discr.ambient_dim, dofdesc=expr.target))(actx) centers = bind( self.places, sym.expansion_centers(source_discr.ambient_dim, expr.qbx_forced_limit, dofdesc=expr.target))(actx) from meshmode.dof_array import flatten, thaw _, (mat, ) = mat_gen(actx.queue, targets=flatten(thaw(actx, target_discr.nodes())), sources=flatten(thaw(actx, source_discr.nodes())), centers=flatten(centers), expansion_radii=flatten(radii), index_set=self.index_set, **kernel_args) waa = bind( self.places, sym.weights_and_area_elements(source_discr.ambient_dim, dofdesc=expr.source))(actx) waa = flatten(waa) mat *= waa[self.index_set.linear_col_indices] return rec_density * actx.to_numpy(mat)
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
def get_expansion_for_qbx_direct_eval(self, base_kernel, target_kernels): from sumpy.expansion.local import LineTaylorLocalExpansion from sumpy.kernel import TargetDerivativeRemover # line Taylor cannot support target derivatives txr = TargetDerivativeRemover() if any(knl != txr(knl) for knl in target_kernels): return self.expansion_factory.get_local_expansion_class( base_kernel)(base_kernel, self.qbx_order) else: return LineTaylorLocalExpansion(base_kernel, self.qbx_order)
def map_int_g(self, expr): lpot_source = self.places.get_geometry(expr.source.geometry) source_discr = self.places.get_discretization(expr.source.geometry, expr.source.discr_stage) target_discr = self.places.get_discretization(expr.target.geometry, expr.target.discr_stage) rec_density = self.rec(expr.density) if is_zero(rec_density): return 0 assert isinstance(rec_density, np.ndarray) if not self.is_kind_matrix(rec_density): raise NotImplementedError("layer potentials on non-variables") actx = self.array_context kernel = expr.kernel kernel_args = _get_layer_potential_args(self, expr) from sumpy.expansion.local import LineTaylorLocalExpansion local_expn = LineTaylorLocalExpansion(kernel, lpot_source.qbx_order) from sumpy.qbx import LayerPotentialMatrixGenerator mat_gen = LayerPotentialMatrixGenerator(actx.context, (local_expn, )) assert abs(expr.qbx_forced_limit) > 0 from pytential import bind, sym radii = bind( self.places, sym.expansion_radii(source_discr.ambient_dim, dofdesc=expr.target))(actx) centers = bind( self.places, sym.expansion_centers(source_discr.ambient_dim, expr.qbx_forced_limit, dofdesc=expr.target))(actx) from meshmode.dof_array import flatten, thaw _, (mat, ) = mat_gen(actx.queue, targets=flatten(thaw(actx, target_discr.nodes())), sources=flatten(thaw(actx, source_discr.nodes())), centers=flatten(centers), expansion_radii=flatten(radii), **kernel_args) mat = actx.to_numpy(mat) waa = bind( self.places, sym.weights_and_area_elements(source_discr.ambient_dim, dofdesc=expr.source))(actx) mat[:, :] *= actx.to_numpy(flatten(waa)) mat = mat.dot(rec_density) return mat
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)
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)
def map_int_g(self, expr): source = self.places.get_geometry(expr.source) source_discr = self.places.get_discretization(expr.source) target_discr = self.places.get_discretization(expr.target) if source_discr is not target_discr: raise NotImplementedError() rec_density = self.blk_mapper.rec(expr.density) if is_zero(rec_density): return 0 if not np.isscalar(rec_density): raise NotImplementedError() kernel = expr.kernel kernel_args = _get_layer_potential_args(self.mat_mapper, expr, None) from sumpy.expansion.local import LineTaylorLocalExpansion local_expn = LineTaylorLocalExpansion(kernel, source.qbx_order) from sumpy.qbx import LayerPotentialMatrixBlockGenerator mat_gen = LayerPotentialMatrixBlockGenerator(self.queue.context, (local_expn, )) assert abs(expr.qbx_forced_limit) > 0 centers, radii = _get_centers_and_expansion_radii( self.queue, source, target_discr, expr.qbx_forced_limit) _, (mat, ) = mat_gen(self.queue, targets=target_discr.nodes(), sources=source_discr.nodes(), centers=centers, expansion_radii=radii, index_set=self.index_set, **kernel_args) waa = _get_weights_and_area_elements(self.queue, source, source_discr) mat *= waa[self.index_set.linear_col_indices] mat = rec_density * mat.get(self.queue) return mat
def map_int_g(self, expr): lpot_source = self.places.get_geometry(expr.source) source_discr = self.places.get_discretization(expr.source) target_discr = self.places.get_discretization(expr.target) rec_density = self.rec(expr.density) if is_zero(rec_density): return 0 assert isinstance(rec_density, np.ndarray) if not self.is_kind_matrix(rec_density): raise NotImplementedError("layer potentials on non-variables") kernel = expr.kernel kernel_args = _get_layer_potential_args(self, expr, lpot_source) from sumpy.expansion.local import LineTaylorLocalExpansion local_expn = LineTaylorLocalExpansion(kernel, lpot_source.qbx_order) from sumpy.qbx import LayerPotentialMatrixGenerator mat_gen = LayerPotentialMatrixGenerator(self.queue.context, (local_expn, )) assert abs(expr.qbx_forced_limit) > 0 centers, radii = _get_centers_and_expansion_radii( self.queue, lpot_source, target_discr, expr.qbx_forced_limit) _, (mat, ) = mat_gen(self.queue, targets=target_discr.nodes(), sources=source_discr.nodes(), centers=centers, expansion_radii=radii, **kernel_args) mat = mat.get() waa = _get_weights_and_area_elements(self.queue, lpot_source, source_discr) mat[:, :] *= waa.get(self.queue) mat = mat.dot(rec_density) return mat
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
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)