def get_operator(self, ambient_dim, qbx_forced_limit="avg"): knl = self.knl_class(ambient_dim) kwargs = self.knl_sym_kwargs.copy() kwargs["qbx_forced_limit"] = qbx_forced_limit if self.op_type == "scalar": sym_u = sym.var("u") sym_op = sym.S(knl, sym_u, **kwargs) elif self.op_type == "scalar_mixed": sym_u = sym.var("u") sym_op = sym.S(knl, 0.3 * sym_u, **kwargs) \ + sym.D(knl, 0.5 * sym_u, **kwargs) elif self.op_type == "vector": sym_u = sym.make_sym_vector("u", ambient_dim) sym_op = make_obj_array([ sym.Sp(knl, sym_u[0], **kwargs) + sym.D(knl, sym_u[1], **kwargs), sym.S(knl, 0.4 * sym_u[0], **kwargs) + 0.3 * sym.D(knl, sym_u[0], **kwargs) ]) else: raise ValueError(f"unknown operator type: '{self.op_type}'") sym_op = 0.5 * sym_u + sym_op return sym_u, sym_op
def main(): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) target_order = 10 from functools import partial nelements = 30 qbx_order = 4 from sumpy.kernel import LaplaceKernel from meshmode.mesh.generation import ( # noqa ellipse, cloverleaf, starfish, drop, n_gon, qbx_peanut, make_curve_mesh) mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements+1), target_order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization(cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, fmm_order=False) from pytools.obj_array import join_fields sig_sym = sym.var("sig") knl = LaplaceKernel(2) op = join_fields( sym.tangential_derivative(mesh.ambient_dim, sym.D(knl, sig_sym, qbx_forced_limit=+1)).as_scalar(), sym.tangential_derivative(mesh.ambient_dim, sym.D(knl, sig_sym, qbx_forced_limit=-1)).as_scalar(), ) nodes = density_discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) n = 10 sig = cl.clmath.sin(n*angle) dt_sig = n*cl.clmath.cos(n*angle) res = bind(qbx, op)(queue, sig=sig) extval = res[0].get() intval = res[1].get() pv = 0.5*(extval + intval) dt_sig_h = dt_sig.get() import matplotlib.pyplot as pt pt.plot(extval, label="+num") pt.plot(pv + dt_sig_h*0.5, label="+ex") pt.legend(loc="best") pt.show()
def representation(self, u, map_potentials=None, qbx_forced_limit=None, **kwargs): """ :param u: symbolic variable for the density. :param map_potentials: a callable that can be used to apply additional transformations on all the layer potentials in the representation, e.g. to take a target derivative. """ sqrt_w = self.get_sqrt_weight() inv_sqrt_w_u = sym.cse(u/sqrt_w) laplace_s_inv_sqrt_w_u = sym.cse(sym.S(self.laplace_kernel, inv_sqrt_w_u)) if map_potentials is None: def map_potentials(x): # pylint:disable=function-redefined return x kwargs["qbx_forced_limit"] = qbx_forced_limit kwargs["kernel_arguments"] = self.kernel_arguments return ( map_potentials( sym.S(self.kernel, inv_sqrt_w_u, **kwargs) ) - self.alpha * map_potentials( sym.D(self.kernel, laplace_s_inv_sqrt_w_u, **kwargs) ) )
def test_cost_model(ctx_factory, dim, use_target_specific_qbx): """Test that cost model gathering can execute successfully.""" cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) lpot_source = get_lpot_source(actx, dim).copy( _use_target_specific_qbx=use_target_specific_qbx, cost_model=CostModel()) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma = get_density(actx, density_discr) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(lpot_source.ambient_dim) sym_op_S = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) op_S = bind(places, sym_op_S) cost_S = op_S.get_modeled_cost(actx, sigma=sigma) assert len(cost_S) == 1 sym_op_S_plus_D = ( sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) + sym.D(k_sym, sigma_sym, qbx_forced_limit="avg")) op_S_plus_D = bind(places, sym_op_S_plus_D) cost_S_plus_D = op_S_plus_D.get_modeled_cost(actx, sigma=sigma) assert len(cost_S_plus_D) == 2
def operator(self, u): sqrt_w = self.get_sqrt_weight() inv_sqrt_w_u = cse(u / sqrt_w) if self.is_unique_only_up_to_constant(): # The exterior Dirichlet operator in this representation # has a nullspace. The mean of the density must be matched # to the desired solution separately. As is, this operator # returns a mean that is not well-specified. # # See Hackbusch, https://books.google.com/books?id=Ssnf7SZB0ZMC # Theorem 8.2.18b amb_dim = self.kernel.dim ones_contribution = (sym.Ones() * sym.mean(amb_dim, amb_dim - 1, inv_sqrt_w_u)) else: ones_contribution = 0 return ( -self.loc_sign * 0.5 * u + sqrt_w * (self.alpha * sym.S(self.kernel, inv_sqrt_w_u, qbx_forced_limit=+1, kernel_arguments=self.kernel_arguments) - sym.D(self.kernel, inv_sqrt_w_u, qbx_forced_limit="avg", kernel_arguments=self.kernel_arguments) + ones_contribution) )
def test_unregularized_off_surface_fmm_vs_direct(ctx_factory): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) nelements = 300 target_order = 8 fmm_order = 4 # {{{ geometry mesh = make_curve_mesh(WobblyCircle.random(8, seed=30), np.linspace(0, 1, nelements+1), target_order) from pytential.unregularized import UnregularizedLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) direct = UnregularizedLayerPotentialSource( density_discr, fmm_order=False, ) fmm = direct.copy( fmm_level_to_order=lambda kernel, kernel_args, tree, level: fmm_order) sigma = density_discr.zeros(actx) + 1 fplot = FieldPlotter(np.zeros(2), extent=5, npoints=100) from pytential.target import PointsTarget ptarget = PointsTarget(fplot.points) from pytential import GeometryCollection places = GeometryCollection({ "unregularized_direct": direct, "unregularized_fmm": fmm, "targets": ptarget}) # }}} # {{{ check from sumpy.kernel import LaplaceKernel op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None) direct_fld_in_vol = bind(places, op, auto_where=("unregularized_direct", "targets"))( actx, sigma=sigma) fmm_fld_in_vol = bind(places, op, auto_where=("unregularized_fmm", "targets"))(actx, sigma=sigma) err = actx.np.fabs(fmm_fld_in_vol - direct_fld_in_vol) linf_err = actx.to_numpy(err).max() print("l_inf error:", linf_err) assert linf_err < 5e-3
def test_off_surface_eval(actx_factory, use_fmm, visualize=False): logging.basicConfig(level=logging.INFO) actx = actx_factory() # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() nelements = 30 target_order = 8 qbx_order = 3 if use_fmm: fmm_order = qbx_order else: fmm_order = False mesh = mgen.make_curve_mesh(partial(mgen.ellipse, 3), np.linspace(0, 1, nelements + 1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=fmm_order, ) from pytential.target import PointsTarget fplot = FieldPlotter(np.zeros(2), extent=0.54, npoints=30) targets = PointsTarget(actx.freeze(actx.from_numpy(fplot.points))) places = GeometryCollection((qbx, targets)) density_discr = places.get_discretization(places.auto_source.geometry) from sumpy.kernel import LaplaceKernel op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=-2) sigma = density_discr.zeros(actx) + 1 fld_in_vol = bind(places, op)(actx, sigma=sigma) fld_in_vol_exact = -1 linf_err = actx.to_numpy( actx.np.linalg.norm(fld_in_vol - fld_in_vol_exact, ord=np.inf)) logger.info("l_inf error: %.12e", linf_err) if visualize: fplot.show_scalar_in_matplotlib(actx.to_numpy(fld_in_vol)) import matplotlib.pyplot as pt pt.colorbar() pt.show() assert linf_err < 1e-3
def test_off_surface_eval(ctx_factory, use_fmm, do_plot=False): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() nelements = 30 target_order = 8 qbx_order = 3 if use_fmm: fmm_order = qbx_order else: fmm_order = False mesh = make_curve_mesh(partial(ellipse, 3), np.linspace(0, 1, nelements + 1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx, _ = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=fmm_order, ).with_refinement() density_discr = qbx.density_discr from sumpy.kernel import LaplaceKernel op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=-2) sigma = density_discr.zeros(queue) + 1 fplot = FieldPlotter(np.zeros(2), extent=0.54, npoints=30) from pytential.target import PointsTarget fld_in_vol = bind((qbx, PointsTarget(fplot.points)), op)(queue, sigma=sigma) err = cl.clmath.fabs(fld_in_vol - (-1)) linf_err = cl.array.max(err).get() print("l_inf error:", linf_err) if do_plot: fplot.show_scalar_in_matplotlib(fld_in_vol.get()) import matplotlib.pyplot as pt pt.colorbar() pt.show() assert linf_err < 1e-3
def test_expr_pickling(): import pickle from sumpy.kernel import LaplaceKernel, AxisTargetDerivative ops_for_testing = [ sym.d_dx( 2, sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=-2)), sym.D(AxisTargetDerivative(0, LaplaceKernel(2)), sym.var("sigma"), qbx_forced_limit=-2) ] for op in ops_for_testing: pickled_op = pickle.dumps(op) after_pickle_op = pickle.loads(pickled_op) assert op == after_pickle_op
def get_zero_op(self, kernel, **knl_kwargs): u_sym = sym.var("u") dn_u_sym = sym.var("dn_u") return (sym.S(kernel, dn_u_sym, qbx_forced_limit=-1, **knl_kwargs) - sym.D(kernel, u_sym, qbx_forced_limit="avg", **knl_kwargs) - 0.5 * u_sym)
def _build_op(lpot_id, k=0, ndim=2, source=sym.DEFAULT_SOURCE, target=sym.DEFAULT_TARGET, qbx_forced_limit="avg"): from sumpy.kernel import LaplaceKernel, HelmholtzKernel if k: knl = HelmholtzKernel(ndim) knl_kwargs = {"k": k} else: knl = LaplaceKernel(ndim) knl_kwargs = {} lpot_kwargs = { "qbx_forced_limit": qbx_forced_limit, "source": source, "target": target} lpot_kwargs.update(knl_kwargs) if lpot_id == 1: # scalar single-layer potential u_sym = sym.var("u") op = sym.S(knl, u_sym, **lpot_kwargs) elif lpot_id == 2: # scalar combination of layer potentials u_sym = sym.var("u") op = sym.S(knl, 0.3 * u_sym, **lpot_kwargs) \ + sym.D(knl, 0.5 * u_sym, **lpot_kwargs) elif lpot_id == 3: # vector potential u_sym = sym.make_sym_vector("u", 2) u0_sym, u1_sym = u_sym op = make_obj_array([ sym.Sp(knl, u0_sym, **lpot_kwargs) + sym.D(knl, u1_sym, **lpot_kwargs), sym.S(knl, 0.4 * u0_sym, **lpot_kwargs) + 0.3 * sym.D(knl, u0_sym, **lpot_kwargs) ]) else: raise ValueError("Unknown lpot_id: {}".format(lpot_id)) op = 0.5 * u_sym + op return op, u_sym, knl_kwargs
def get_zero_op(self, kernel, **knl_kwargs): d = kernel.dim u_sym = sym.var("u") grad_u_sym = sym.make_sym_mv("grad_u", d) dn_u_sym = sym.var("dn_u") return (d1.resolve( d1.dnabla(d) * d1(sym.S(kernel, dn_u_sym, qbx_forced_limit="avg", **knl_kwargs)) ) - d2.resolve( d2.dnabla(d) * d2(sym.D(kernel, u_sym, qbx_forced_limit="avg", **knl_kwargs))) - 0.5 * grad_u_sym)
def get_lpot_cost(which, helmholtz_k, geometry_getter, lpot_kwargs, kind): """ Parameters: which: "D" or "S" kind: "actual" or "model" """ context = cl.create_some_context(interactive=False) queue = cl.CommandQueue(context) lpot_source = geometry_getter(queue, lpot_kwargs) from sumpy.kernel import LaplaceKernel, HelmholtzKernel sigma_sym = sym.var("sigma") if helmholtz_k == 0: k_sym = LaplaceKernel(lpot_source.ambient_dim) kernel_kwargs = {} else: k_sym = HelmholtzKernel(lpot_source.ambient_dim, "k") kernel_kwargs = {"k": helmholtz_k} if which == "S": op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1, **kernel_kwargs) elif which == "D": op = sym.D(k_sym, sigma_sym, qbx_forced_limit="avg", **kernel_kwargs) else: raise ValueError("unknown lpot symbol: '%s'" % which) bound_op = bind(lpot_source, op) density_discr = lpot_source.density_discr nodes = density_discr.nodes().with_queue(queue) sigma = cl.clmath.sin(10 * nodes[0]) if kind == "actual": timing_data = {} result = bound_op.eval(queue, {"sigma": sigma}, timing_data=timing_data) assert not np.isnan(result.get(queue)).any() result = one(timing_data.values()) elif kind == "model": perf_results = bound_op.get_modeled_performance(queue, sigma=sigma) result = one(perf_results.values()) return result
def test_unregularized_off_surface_fmm_vs_direct(ctx_factory): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) nelements = 300 target_order = 8 fmm_order = 4 mesh = make_curve_mesh(WobblyCircle.random(8, seed=30), np.linspace(0, 1, nelements + 1), target_order) from pytential.unregularized import UnregularizedLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) direct = UnregularizedLayerPotentialSource( density_discr, fmm_order=False, ) fmm = direct.copy( fmm_level_to_order=lambda kernel, kernel_args, tree, level: fmm_order) sigma = density_discr.zeros(queue) + 1 fplot = FieldPlotter(np.zeros(2), extent=5, npoints=100) from pytential.target import PointsTarget ptarget = PointsTarget(fplot.points) from sumpy.kernel import LaplaceKernel op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None) direct_fld_in_vol = bind((direct, ptarget), op)(queue, sigma=sigma) fmm_fld_in_vol = bind((fmm, ptarget), op)(queue, sigma=sigma) err = cl.clmath.fabs(fmm_fld_in_vol - direct_fld_in_vol) linf_err = cl.array.max(err).get() print("l_inf error:", linf_err) assert linf_err < 5e-3
def representation(self, u, map_potentials=None, qbx_forced_limit=None, **kwargs): sqrt_w = self.get_sqrt_weight() inv_sqrt_w_u = cse(u / sqrt_w) if map_potentials is None: def map_potentials(x): # pylint:disable=function-redefined return x kwargs["qbx_forced_limit"] = qbx_forced_limit kwargs["kernel_arguments"] = self.kernel_arguments return (map_potentials(sym.S(self.kernel, inv_sqrt_w_u, **kwargs)) - self.alpha * map_potentials( sym.D(self.kernel, sym.S(self.laplace_kernel, inv_sqrt_w_u), **kwargs)))
def test_cost_model(actx_factory, dim, use_target_specific_qbx, per_box): """Test that cost model gathering can execute successfully.""" actx = actx_factory() lpot_source = get_lpot_source(actx, dim).copy( _use_target_specific_qbx=use_target_specific_qbx, cost_model=QBXCostModel()) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma = get_density(actx, density_discr) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(lpot_source.ambient_dim) sym_op_S = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) op_S = bind(places, sym_op_S) if per_box: cost_S, _ = op_S.cost_per_box("constant_one", sigma=sigma) else: cost_S, _ = op_S.cost_per_stage("constant_one", sigma=sigma) assert len(cost_S) == 1 sym_op_S_plus_D = (sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) + sym.D(k_sym, sigma_sym, qbx_forced_limit="avg")) op_S_plus_D = bind(places, sym_op_S_plus_D) if per_box: cost_S_plus_D, _ = op_S_plus_D.cost_per_box("constant_one", sigma=sigma) else: cost_S_plus_D, _ = op_S_plus_D.cost_per_stage("constant_one", sigma=sigma) assert len(cost_S_plus_D) == 2
def test_cost_model(ctx_getter, dim, use_target_specific_qbx): """Test that cost model gathering can execute successfully.""" cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) lpot_source = (get_lpot_source(queue, dim).copy( _use_target_specific_qbx=use_target_specific_qbx, cost_model=CostModel())) sigma = get_density(queue, lpot_source) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(lpot_source.ambient_dim) sym_op_S = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) op_S = bind(lpot_source, sym_op_S) cost_S = op_S.get_modeled_cost(queue, sigma=sigma) assert len(cost_S) == 1 sym_op_S_plus_D = (sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) + sym.D(k_sym, sigma_sym)) op_S_plus_D = bind(lpot_source, sym_op_S_plus_D) cost_S_plus_D = op_S_plus_D.get_modeled_cost(queue, sigma=sigma) assert len(cost_S_plus_D) == 2
def nonlocal_integral_eq( mesh, scatterer_bdy_id, outer_bdy_id, wave_number, options_prefix=None, solver_parameters=None, fspace=None, vfspace=None, true_sol_grad_expr=None, actx=None, dgfspace=None, dgvfspace=None, meshmode_src_connection=None, qbx_kwargs=None, ): r""" see run_method for descriptions of unlisted args args: gamma and beta are used to precondition with the following equation: \Delta u - \kappa^2 \gamma u = 0 (\partial_n - i\kappa\beta) u |_\Sigma = 0 """ # make sure we get outer bdy id as tuple in case it consists of multiple ids if isinstance(outer_bdy_id, int): outer_bdy_id = [outer_bdy_id] outer_bdy_id = tuple(outer_bdy_id) # away from the excluded region, but firedrake and meshmode point # into pyt_inner_normal_sign = -1 ambient_dim = mesh.geometric_dimension() # {{{ Build src and tgt # build connection meshmode near src boundary -> src boundary inside meshmode from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from meshmode.discretization.connection import make_face_restriction factory = InterpolatoryQuadratureSimplexGroupFactory( dgfspace.finat_element.degree) src_bdy_connection = make_face_restriction(actx, meshmode_src_connection.discr, factory, scatterer_bdy_id) # source is a qbx layer potential from pytential.qbx import QBXLayerPotentialSource disable_refinement = (fspace.mesh().geometric_dimension() == 3) qbx = QBXLayerPotentialSource(src_bdy_connection.to_discr, **qbx_kwargs, _disable_refinement=disable_refinement) # get target indices and point-set target_indices, target = get_target_points_and_indices( fspace, outer_bdy_id) # }}} # build the operations from pytential import bind, sym r""" ..math: x \in \Sigma grad_op(x) = \nabla( \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ) """ grad_op = pyt_inner_normal_sign * sym.grad( ambient_dim, sym.D(HelmholtzKernel(ambient_dim), sym.var("u"), k=sym.var("k"), qbx_forced_limit=None)) r""" ..math: x \in \Sigma op(x) = i \kappa \cdot \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y) """ op = pyt_inner_normal_sign * 1j * sym.var("k") * (sym.D( HelmholtzKernel(ambient_dim), sym.var("u"), k=sym.var("k"), qbx_forced_limit=None)) # bind the operations pyt_grad_op = bind((qbx, target), grad_op) pyt_op = bind((qbx, target), op) # }}} class MatrixFreeB(object): def __init__(self, A, pyt_grad_op, pyt_op, actx, kappa): """ :arg kappa: The wave number """ self.actx = actx self.k = kappa self.pyt_op = pyt_op self.pyt_grad_op = pyt_grad_op self.A = A self.meshmode_src_connection = meshmode_src_connection # {{{ Create some functions needed for multing self.x_fntn = Function(fspace) # CG self.potential_int = Function(fspace) self.potential_int.dat.data[:] = 0.0 self.grad_potential_int = Function(vfspace) self.grad_potential_int.dat.data[:] = 0.0 self.pyt_result = Function(fspace) self.n = FacetNormal(mesh) self.v = TestFunction(fspace) # some meshmode ones self.x_mm_fntn = self.meshmode_src_connection.discr.empty( self.actx, dtype='c') # }}} def mult(self, mat, x, y): # Copy function data into the fivredrake function self.x_fntn.dat.data[:] = x[:] # Transfer the function to meshmode self.meshmode_src_connection.from_firedrake(project( self.x_fntn, dgfspace), out=self.x_mm_fntn) # Restrict to boundary x_mm_fntn_on_bdy = src_bdy_connection(self.x_mm_fntn) # Apply the operation potential_int_mm = self.pyt_op(self.actx, u=x_mm_fntn_on_bdy, k=self.k) grad_potential_int_mm = self.pyt_grad_op(self.actx, u=x_mm_fntn_on_bdy, k=self.k) # Store in firedrake self.potential_int.dat.data[target_indices] = potential_int_mm.get( ) for dim in range(grad_potential_int_mm.shape[0]): self.grad_potential_int.dat.data[ target_indices, dim] = grad_potential_int_mm[dim].get() # Integrate the potential r""" Compute the inner products using firedrake. Note this will be subtracted later, hence appears off by a sign. .. math:: \langle n(x) \cdot \nabla( \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ), v \rangle_\Sigma - \langle i \kappa \cdot \int_\Gamma( u(y) \partial_n H_0^{(1)}(\kappa |x - y|) )d\gamma(y), v \rangle_\Sigma """ self.pyt_result = assemble( inner(inner(self.grad_potential_int, self.n), self.v) * ds(outer_bdy_id) - inner(self.potential_int, self.v) * ds(outer_bdy_id)) # y <- Ax - evaluated potential self.A.mult(x, y) with self.pyt_result.dat.vec_ro as ep: y.axpy(-1, ep) # {{{ Compute normal helmholtz operator u = TrialFunction(fspace) v = TestFunction(fspace) r""" .. math:: \langle \nabla u, \nabla v \rangle - \kappa^2 \cdot \langle u, v \rangle - i \kappa \langle u, v \rangle_\Sigma """ a = inner(grad(u), grad(v)) * dx \ - Constant(wave_number**2) * inner(u, v) * dx \ - Constant(1j * wave_number) * inner(u, v) * ds(outer_bdy_id) # get the concrete matrix from a general bilinear form A = assemble(a).M.handle # }}} # {{{ Setup Python matrix B = PETSc.Mat().create() # build matrix context Bctx = MatrixFreeB(A, pyt_grad_op, pyt_op, actx, wave_number) # set up B as same size as A B.setSizes(*A.getSizes()) B.setType(B.Type.PYTHON) B.setPythonContext(Bctx) B.setUp() # }}} # {{{ Create rhs # Remember f is \partial_n(true_sol)|_\Gamma # so we just need to compute \int_\Gamma\partial_n(true_sol) H(x-y) sigma = sym.make_sym_vector("sigma", ambient_dim) r""" ..math: x \in \Sigma grad_op(x) = \nabla( \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ) """ grad_op = pyt_inner_normal_sign * \ sym.grad(ambient_dim, sym.S(HelmholtzKernel(ambient_dim), sym.n_dot(sigma), k=sym.var("k"), qbx_forced_limit=None)) r""" ..math: x \in \Sigma op(x) = i \kappa \cdot \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ) """ op = 1j * sym.var("k") * pyt_inner_normal_sign * \ sym.S(HelmholtzKernel(ambient_dim), sym.n_dot(sigma), k=sym.var("k"), qbx_forced_limit=None) rhs_grad_op = bind((qbx, target), grad_op) rhs_op = bind((qbx, target), op) # Transfer to meshmode metadata = {'quadrature_degree': 2 * fspace.ufl_element().degree()} dg_true_sol_grad = project(true_sol_grad_expr, dgvfspace, form_compiler_parameters=metadata) true_sol_grad_mm = meshmode_src_connection.from_firedrake(dg_true_sol_grad, actx=actx) true_sol_grad_mm = src_bdy_connection(true_sol_grad_mm) # Apply the operations f_grad_convoluted_mm = rhs_grad_op(actx, sigma=true_sol_grad_mm, k=wave_number) f_convoluted_mm = rhs_op(actx, sigma=true_sol_grad_mm, k=wave_number) # Transfer function back to firedrake f_grad_convoluted = Function(vfspace) f_convoluted = Function(fspace) f_grad_convoluted.dat.data[:] = 0.0 f_convoluted.dat.data[:] = 0.0 for dim in range(f_grad_convoluted_mm.shape[0]): f_grad_convoluted.dat.data[target_indices, dim] = f_grad_convoluted_mm[dim].get() f_convoluted.dat.data[target_indices] = f_convoluted_mm.get() r""" \langle f, v \rangle_\Gamma + \langle i \kappa \cdot \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y), v \rangle_\Sigma - \langle n(x) \cdot \nabla( \int_\Gamma( f(y) H_0^{(1)}(\kappa |x - y|) )d\gamma(y) ), v \rangle_\Sigma """ rhs_form = inner(inner(true_sol_grad_expr, FacetNormal(mesh)), v) * ds(scatterer_bdy_id, metadata=metadata) \ + inner(f_convoluted, v) * ds(outer_bdy_id) \ - inner(inner(f_grad_convoluted, FacetNormal(mesh)), v) * ds(outer_bdy_id) rhs = assemble(rhs_form) # {{{ set up a solver: solution = Function(fspace, name="Computed Solution") # {{{ Used for preconditioning if 'gamma' in solver_parameters or 'beta' in solver_parameters: gamma = complex(solver_parameters.pop('gamma', 1.0)) import cmath beta = complex(solver_parameters.pop('beta', cmath.sqrt(gamma))) p = inner(grad(u), grad(v)) * dx \ - Constant(wave_number**2 * gamma) * inner(u, v) * dx \ - Constant(1j * wave_number * beta) * inner(u, v) * ds(outer_bdy_id) P = assemble(p).M.handle else: P = A # }}} # Set up options to contain solver parameters: ksp = PETSc.KSP().create() if solver_parameters['pc_type'] == 'pyamg': del solver_parameters['pc_type'] # We are using the AMG preconditioner pyamg_tol = solver_parameters.get('pyamg_tol', None) if pyamg_tol is not None: pyamg_tol = float(pyamg_tol) pyamg_maxiter = solver_parameters.get('pyamg_maxiter', None) if pyamg_maxiter is not None: pyamg_maxiter = int(pyamg_maxiter) ksp.setOperators(B) ksp.setUp() pc = ksp.pc pc.setType(pc.Type.PYTHON) pc.setPythonContext( AMGTransmissionPreconditioner(wave_number, fspace, A, tol=pyamg_tol, maxiter=pyamg_maxiter, use_plane_waves=True)) # Otherwise use regular preconditioner else: ksp.setOperators(B, P) options_manager = OptionsManager(solver_parameters, options_prefix) options_manager.set_from_options(ksp) import petsc4py.PETSc petsc4py.PETSc.Sys.popErrorHandler() with rhs.dat.vec_ro as b: with solution.dat.vec as x: ksp.solve(b, x) # }}} return ksp, solution
def D(density): # noqa return sym.D(self.kernel, density, kernel_arguments=self.kernel_arguments, qbx_forced_limit=qbx_forced_limit)
def op(**kwargs): kwargs.update(kernel_kwargs) #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), **kwargs)) return sym.D(kernel, sym.var("sigma"), **kwargs)
def main(): import logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.WARNING) # INFO for more progress info from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource(cad_file_name), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h]) from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5*(bbox_min+bbox_max) bbox_size = max(bbox_max-bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx, _ = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, fmm_order=qbx_order + 3, target_association_tolerance=0.15).with_refinement() nodes = density_discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) from pytential import bind, sym #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None)) op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None) sigma = cl.clmath.cos(mode_nr*angle) if 0: sigma = 0*angle from random import randrange for i in range(5): sigma[randrange(len(sigma))] = 1 if isinstance(kernel, HelmholtzKernel): sigma = sigma.astype(np.complex128) fplot = FieldPlotter(bbox_center, extent=3.5*bbox_size, npoints=150) from pytential.target import PointsTarget fld_in_vol = bind( (qbx, PointsTarget(fplot.points)), op)(queue, sigma=sigma, k=k).get() #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-3d.vts", [ ("potential", fld_in_vol) ] ) bdry_normals = bind( density_discr, sym.normal(density_discr.ambient_dim))(queue).as_vector(dtype=object) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, target_order) bdry_vis.write_vtk_file("source-3d.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ])
def main(mesh_name="ellipse", visualize=False): import logging logging.basicConfig(level=logging.INFO) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial if mesh_name == "ellipse": mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) elif mesh_name == "ellipse_array": base_mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes nx = 2 ny = 2 dx = 2 / nx meshes = [ affine_map(base_mesh, A=np.diag([dx * 0.25, dx * 0.25]), b=np.array([dx * (ix - nx / 2), dx * (iy - ny / 2)])) for ix in range(nx) for iy in range(ny) ] mesh = merge_disjoint_meshes(meshes, single_group=True) if visualize: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() else: raise ValueError(f"unknown mesh name: {mesh_name}") pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import (QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx = QBXLayerPotentialSource(pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = actx.from_numpy(fplot.points) from pytential import GeometryCollection places = GeometryCollection( { "qbx": qbx, "qbx_high_target_assoc_tol": qbx.copy(target_association_tolerance=0.05), "targets": PointsTarget(targets) }, auto_where="qbx") density_discr = places.get_discretization("qbx") # {{{ describe bvp from sumpy.kernel import LaplaceKernel, HelmholtzKernel kernel = HelmholtzKernel(2) sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = sym.cse(sigma_sym / sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 k_sym = sym.var("k") bdry_op_sym = ( -loc_sign * 0.5 * sigma_sym + sqrt_w * (alpha * sym.S(kernel, inv_sqrt_w_sigma, k=k_sym, qbx_forced_limit=+1) - sym.D(kernel, inv_sqrt_w_sigma, k=k_sym, qbx_forced_limit="avg"))) # }}} bound_op = bind(places, bdry_op_sym) # {{{ fix rhs and solve from meshmode.dof_array import thaw nodes = thaw(actx, density_discr.nodes()) k_vec = np.array([2, 1]) k_vec = k * k_vec / la.norm(k_vec, 2) def u_incoming_func(x): return actx.np.exp(1j * (x[0] * k_vec[0] + x[1] * k_vec[1])) bc = -u_incoming_func(nodes) bvp_rhs = bind(places, sqrt_w * sym.var("bc"))(actx, bc=bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(actx, sigma_sym.name, dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize repr_kwargs = dict(source="qbx_high_target_assoc_tol", target="targets", qbx_forced_limit=None) representation_sym = ( alpha * sym.S(kernel, inv_sqrt_w_sigma, k=k_sym, **repr_kwargs) - sym.D(kernel, inv_sqrt_w_sigma, k=k_sym, **repr_kwargs)) u_incoming = u_incoming_func(targets) ones_density = density_discr.zeros(actx) for elem in ones_density: elem.fill(1) indicator = actx.to_numpy( bind(places, sym.D(LaplaceKernel(2), sigma_sym, **repr_kwargs))(actx, sigma=ones_density)) try: fld_in_vol = actx.to_numpy( bind(places, representation_sym)(actx, sigma=gmres_result.solution, k=k)) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("helmholtz-dirichlet-failed-targets.vts", [("failed", e.failed_target_flags.get(queue))]) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("helmholtz-dirichlet-potential.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ("u_incoming", actx.to_numpy(u_incoming)), ])
op.representation(sym.var("u")))(queue, u=weighted_u, k=case.k) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [("failed_targets", e.failed_target_flags.get(queue))]) raise from sumpy.kernel import LaplaceKernel ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), -sym.D(LaplaceKernel(density_discr.ambient_dim), sym.var("sigma"), qbx_forced_limit=None))(queue, sigma=ones_density).get() solved_pot = solved_pot.get() true_pot = bind((point_source, PointsTarget(fplot.points)), pot_src)(queue, charges=source_charges_dev, **concrete_knl_kwargs).get() #fplot.show_scalar_in_mayavi(solved_pot.real, max_val=5) if case.prob_side == "scat": fplot.write_vtk_file("potential-%s.vts" % resolution, [ ("pot_scattered", solved_pot), ("pot_incoming", -true_pot), ("indicator", indicator),
def test_off_surface_eval_vs_direct(ctx_factory, do_plot=False): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() nelements = 300 target_order = 8 qbx_order = 3 mesh = make_curve_mesh(WobblyCircle.random(8, seed=30), np.linspace(0, 1, nelements+1), target_order) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) direct_qbx = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order, fmm_order=False, target_association_tolerance=0.05, ) fmm_qbx = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order, fmm_order=qbx_order + 3, _expansions_in_tree_have_extent=True, target_association_tolerance=0.05, ) fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) from pytential.target import PointsTarget ptarget = PointsTarget(fplot.points) from sumpy.kernel import LaplaceKernel places = GeometryCollection({ "direct_qbx": direct_qbx, "fmm_qbx": fmm_qbx, "target": ptarget}) direct_density_discr = places.get_discretization("direct_qbx") fmm_density_discr = places.get_discretization("fmm_qbx") from pytential.qbx import QBXTargetAssociationFailedException op = sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None) try: direct_sigma = direct_density_discr.zeros(actx) + 1 direct_fld_in_vol = bind(places, op, auto_where=("direct_qbx", "target"))( actx, sigma=direct_sigma) except QBXTargetAssociationFailedException as e: fplot.show_scalar_in_matplotlib( actx.to_numpy(actx.thaw(e.failed_target_flags))) import matplotlib.pyplot as pt pt.show() raise fmm_sigma = fmm_density_discr.zeros(actx) + 1 fmm_fld_in_vol = bind(places, op, auto_where=("fmm_qbx", "target"))( actx, sigma=fmm_sigma) err = actx.np.fabs(fmm_fld_in_vol - direct_fld_in_vol) linf_err = actx.to_numpy(err).max() print("l_inf error:", linf_err) if do_plot: #fplot.show_scalar_in_mayavi(0.1*.get(queue)) fplot.write_vtk_file("potential.vts", [ ("fmm_fld_in_vol", actx.to_numpy(fmm_fld_in_vol)), ("direct_fld_in_vol", actx.to_numpy(direct_fld_in_vol)) ]) assert linf_err < 1e-3
def main(nelements): import logging logging.basicConfig(level=logging.INFO) def get_obj_array(obj_array): from pytools.obj_array import make_obj_array return make_obj_array([ary.get() for ary in obj_array]) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ( # noqa make_curve_mesh, starfish, ellipse, drop) mesh = make_curve_mesh(lambda t: starfish(t), np.linspace(0, 1, nelements + 1), target_order) coarse_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource target_association_tolerance = 0.05 qbx, _ = QBXLayerPotentialSource( coarse_density_discr, fine_order=ovsmp_target_order, qbx_order=qbx_order, fmm_order=fmm_order, target_association_tolerance=target_association_tolerance, ).with_refinement() density_discr = qbx.density_discr nodes = density_discr.nodes().with_queue(queue) # Get normal vectors for the density discretization -- used in integration with stresslet mv_normal = bind(density_discr, sym.normal(2))(queue) normal = mv_normal.as_vector(np.object) # {{{ describe bvp from sumpy.kernel import LaplaceKernel from pytential.symbolic.stokes import StressletWrapper from pytools.obj_array import make_obj_array dim = 2 cse = sym.cse nvec_sym = sym.make_sym_vector("normal", dim) sigma_sym = sym.make_sym_vector("sigma", dim) mu_sym = sym.var("mu") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym / sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = -1 # Create stresslet object stresslet_obj = StressletWrapper(dim=2) # Describe boundary operator bdry_op_sym = loc_sign * 0.5 * sigma_sym + sqrt_w * stresslet_obj.apply( inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit='avg') # Bind to the qbx discretization bound_op = bind(qbx, bdry_op_sym) # }}} # {{{ fix rhs and solve def fund_soln(x, y, loc): #with direction (1,0) for point source r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = 1. / (4 * np.pi * mu) xcomp = (-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling ycomp = ((x - loc[0]) * (y - loc[1]) / r**2) * scaling return [xcomp, ycomp] def couette_soln(x, y, dp, h): scaling = 1. / (2 * mu) xcomp = scaling * dp * ((y + (h / 2.))**2 - h * (y + (h / 2.))) ycomp = scaling * 0 * y return [xcomp, ycomp] if soln_type == 'fundamental': pt_loc = np.array([2.0, 0.0]) bc = fund_soln(nodes[0], nodes[1], pt_loc) else: dp = -10. h = 2.5 bc = couette_soln(nodes[0], nodes[1], dp, h) # Get rhs vector bvp_rhs = bind(qbx, sqrt_w * sym.make_sym_vector("bc", dim))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", np.float64, mu=mu, normal=normal), bvp_rhs, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution # Describe representation of solution for evaluation in domain representation_sym = stresslet_obj.apply(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) from sumpy.visualization import FieldPlotter nsamp = 10 eval_points_1d = np.linspace(-1., 1., nsamp) eval_points = np.zeros((2, len(eval_points_1d)**2)) eval_points[0, :] = np.tile(eval_points_1d, len(eval_points_1d)) eval_points[1, :] = np.repeat(eval_points_1d, len(eval_points_1d)) gamma_sym = sym.var("gamma") inv_sqrt_w_gamma = cse(gamma_sym / sqrt_w) constant_laplace_rep = sym.D(LaplaceKernel(dim=2), inv_sqrt_w_gamma, qbx_forced_limit=None) sqrt_w_vec = bind(qbx, sqrt_w)(queue) def general_mask(test_points): const_density = bind((qbx, PointsTarget(test_points)), constant_laplace_rep)(queue, gamma=sqrt_w_vec).get() return (abs(const_density) > 0.1) def inside_domain(test_points): mask = general_mask(test_points) return np.array([row[mask] for row in test_points]) def stride_hack(arr): from numpy.lib.stride_tricks import as_strided return np.array(as_strided(arr, strides=(8 * len(arr[0]), 8))) eval_points = inside_domain(eval_points) eval_points_dev = cl.array.to_device(queue, eval_points) # Evaluate the solution at the evaluation points vel = bind((qbx, PointsTarget(eval_points_dev)), representation_sym)(queue, sigma=sigma, mu=mu, normal=normal) print("@@@@@@@@") vel = get_obj_array(vel) if soln_type == 'fundamental': exact_soln = fund_soln(eval_points_dev[0], eval_points_dev[1], pt_loc) else: exact_soln = couette_soln(eval_points_dev[0], eval_points_dev[1], dp, h) err = vel - get_obj_array(exact_soln) print("@@@@@@@@") print( "L2 error estimate: ", np.sqrt((2. / (nsamp - 1))**2 * np.sum(err[0] * err[0]) + (2. / (nsamp - 1))**2 * np.sum(err[1] * err[1]))) max_error_loc = [abs(err[0]).argmax(), abs(err[1]).argmax()] print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1]))) print("exact velocity at max error points: x -> ", err[0][max_error_loc[0]], ", y -> ", err[1][max_error_loc[1]]) from pytential.symbolic.mappers import DerivativeTaker rep_pressure = stresslet_obj.apply_pressure(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) pressure = bind((qbx, PointsTarget(eval_points_dev)), rep_pressure)(queue, sigma=sigma, mu=mu, normal=normal) pressure = pressure.get() print "pressure = ", pressure x_dir_vecs = np.zeros((2, len(eval_points[0]))) x_dir_vecs[0, :] = 1.0 y_dir_vecs = np.zeros((2, len(eval_points[0]))) y_dir_vecs[1, :] = 1.0 x_dir_vecs = cl.array.to_device(queue, x_dir_vecs) y_dir_vecs = cl.array.to_device(queue, y_dir_vecs) dir_vec_sym = sym.make_sym_vector("force_direction", dim) rep_stress = stresslet_obj.apply_stress(inv_sqrt_w_sigma, nvec_sym, dir_vec_sym, mu_sym, qbx_forced_limit=-2) applied_stress_x = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=x_dir_vecs, mu=mu) applied_stress_x = get_obj_array(applied_stress_x) applied_stress_y = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=y_dir_vecs, mu=mu) applied_stress_y = get_obj_array(applied_stress_y) print "stress applied to x direction: ", applied_stress_x print "stress applied to y direction: ", applied_stress_y import matplotlib.pyplot as plt plt.quiver(eval_points[0], eval_points[1], vel[0], vel[1], linewidth=0.1) file_name = "field-n%s.pdf" % (nelements) plt.savefig(file_name) return (max(abs(err[0])), max(abs(err[1])))
def test_ellipse_eigenvalues(ctx_factory, ellipse_aspect, mode_nr, qbx_order, force_direct, visualize=False): logging.basicConfig(level=logging.INFO) print("ellipse_aspect: %s, mode_nr: %d, qbx_order: %d" % (ellipse_aspect, mode_nr, qbx_order)) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) target_order = 8 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() if ellipse_aspect != 1: nelements_values = [60, 100, 150, 200] else: nelements_values = [30, 70] # See # # [1] G. J. Rodin and O. Steinbach, "Boundary Element Preconditioners # for Problems Defined on Slender Domains", SIAM Journal on Scientific # Computing, Vol. 24, No. 4, pg. 1450, 2003. # https://dx.doi.org/10.1137/S1064827500372067 for nelements in nelements_values: mesh = make_curve_mesh(partial(ellipse, ellipse_aspect), np.linspace(0, 1, nelements + 1), target_order) fmm_order = 12 if force_direct: fmm_order = False pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=fmm_order, _expansions_in_tree_have_extent=True, ) places = GeometryCollection(qbx) density_discr = places.get_discretization(places.auto_source.geometry) from meshmode.dof_array import thaw, flatten nodes = thaw(actx, density_discr.nodes()) if visualize: # plot geometry, centers, normals centers = bind(places, sym.expansion_centers(qbx.ambient_dim, +1))(actx) normals = bind(places, sym.normal(qbx.ambient_dim))(actx).as_vector(object) nodes_h = np.array( [actx.to_numpy(axis) for axis in flatten(nodes)]) centers_h = np.array( [actx.to_numpy(axis) for axis in flatten(centers)]) normals_h = np.array( [actx.to_numpy(axis) for axis in flatten(normals)]) pt.plot(nodes_h[0], nodes_h[1], "x-") pt.plot(centers_h[0], centers_h[1], "o") pt.quiver(nodes_h[0], nodes_h[1], normals_h[0], normals_h[1]) pt.gca().set_aspect("equal") pt.show() angle = actx.np.arctan2(nodes[1] * ellipse_aspect, nodes[0]) ellipse_fraction = ((1 - ellipse_aspect) / (1 + ellipse_aspect))**mode_nr # (2.6) in [1] J = actx.np.sqrt( # noqa actx.np.sin(angle)**2 + (1 / ellipse_aspect)**2 * actx.np.cos(angle)**2) from sumpy.kernel import LaplaceKernel lap_knl = LaplaceKernel(2) # {{{ single layer sigma_sym = sym.var("sigma") s_sigma_op = sym.S(lap_knl, sigma_sym, qbx_forced_limit=+1) sigma = actx.np.cos(mode_nr * angle) / J s_sigma = bind(places, s_sigma_op)(actx, sigma=sigma) # SIGN BINGO! :) s_eigval = 1 / (2 * mode_nr) * (1 + (-1)**mode_nr * ellipse_fraction) # (2.12) in [1] s_sigma_ref = s_eigval * J * sigma if 0: #pt.plot(s_sigma.get(), label="result") #pt.plot(s_sigma_ref.get(), label="ref") pt.plot(actx.to_numpy(flatten(s_sigma_ref - s_sigma)), label="err") pt.legend() pt.show() h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) s_err = (norm(density_discr, s_sigma - s_sigma_ref) / norm(density_discr, s_sigma_ref)) s_eoc_rec.add_data_point(h_max, s_err) # }}} # {{{ double layer d_sigma_op = sym.D(lap_knl, sigma_sym, qbx_forced_limit="avg") sigma = actx.np.cos(mode_nr * angle) d_sigma = bind(places, d_sigma_op)(actx, sigma=sigma) # SIGN BINGO! :) d_eigval = -(-1)**mode_nr * 1 / 2 * ellipse_fraction d_sigma_ref = d_eigval * sigma if 0: pt.plot(actx.to_numpy(flatten(d_sigma)), label="result") pt.plot(actx.to_numpy(flatten(d_sigma_ref)), label="ref") pt.legend() pt.show() if ellipse_aspect == 1: d_ref_norm = norm(density_discr, sigma) else: d_ref_norm = norm(density_discr, d_sigma_ref) d_err = (norm(density_discr, d_sigma - d_sigma_ref) / d_ref_norm) d_eoc_rec.add_data_point(h_max, d_err) # }}} if ellipse_aspect == 1: # {{{ S' sp_sigma_op = sym.Sp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg") sigma = actx.np.cos(mode_nr * angle) sp_sigma = bind(places, sp_sigma_op)(actx, sigma=sigma) sp_eigval = 0 sp_sigma_ref = sp_eigval * sigma sp_err = (norm(density_discr, sp_sigma - sp_sigma_ref) / norm(density_discr, sigma)) sp_eoc_rec.add_data_point(h_max, sp_err) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 1.5 if ellipse_aspect == 1: print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5
def test_sphere_eigenvalues(ctx_factory, mode_m, mode_n, qbx_order, fmm_backend): logging.basicConfig(level=logging.INFO) special = pytest.importorskip("scipy.special") cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) target_order = 8 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() dp_eoc_rec = EOCRecorder() def rel_err(comp, ref): return (norm(density_discr, comp - ref) / norm(density_discr, ref)) for nrefinements in [0, 1]: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.mesh.refinement import Refiner refiner = Refiner(mesh) for i in range(nrefinements): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=6, fmm_backend=fmm_backend, ) places = GeometryCollection(qbx) from meshmode.dof_array import flatten, unflatten, thaw density_discr = places.get_discretization(places.auto_source.geometry) nodes = thaw(actx, density_discr.nodes()) r = actx.np.sqrt(nodes[0] * nodes[0] + nodes[1] * nodes[1] + nodes[2] * nodes[2]) phi = actx.np.arccos(nodes[2] / r) theta = actx.np.arctan2(nodes[0], nodes[1]) ymn = unflatten( actx, density_discr, actx.from_numpy( special.sph_harm(mode_m, mode_n, actx.to_numpy(flatten(theta)), actx.to_numpy(flatten(phi))))) from sumpy.kernel import LaplaceKernel lap_knl = LaplaceKernel(3) # {{{ single layer s_sigma_op = bind( places, sym.S(lap_knl, sym.var("sigma"), qbx_forced_limit=+1)) s_sigma = s_sigma_op(actx, sigma=ymn) s_eigval = 1 / (2 * mode_n + 1) h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) s_eoc_rec.add_data_point(h_max, rel_err(s_sigma, s_eigval * ymn)) # }}} # {{{ double layer d_sigma_op = bind( places, sym.D(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) d_sigma = d_sigma_op(actx, sigma=ymn) d_eigval = -1 / (2 * (2 * mode_n + 1)) d_eoc_rec.add_data_point(h_max, rel_err(d_sigma, d_eigval * ymn)) # }}} # {{{ S' sp_sigma_op = bind( places, sym.Sp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) sp_sigma = sp_sigma_op(actx, sigma=ymn) sp_eigval = -1 / (2 * (2 * mode_n + 1)) sp_eoc_rec.add_data_point(h_max, rel_err(sp_sigma, sp_eigval * ymn)) # }}} # {{{ D' dp_sigma_op = bind( places, sym.Dp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) dp_sigma = dp_sigma_op(actx, sigma=ymn) dp_eigval = -(mode_n * (mode_n + 1)) / (2 * mode_n + 1) dp_eoc_rec.add_data_point(h_max, rel_err(dp_sigma, dp_eigval * ymn)) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 0.5 print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D':") print(dp_eoc_rec) required_order = qbx_order assert dp_eoc_rec.order_estimate() > required_order - 1.5
def main(mesh_name="ellipsoid"): import logging logger = logging.getLogger(__name__) logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) if mesh_name == "ellipsoid": cad_file_name = "geometries/ellipsoid.step" h = 0.6 elif mesh_name == "two-cylinders": cad_file_name = "geometries/two-cylinders-smooth.step" h = 0.4 else: raise ValueError("unknown mesh name: %s" % mesh_name) from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource(cad_file_name), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h], target_unit="MM") from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5 * (bbox_min + bbox_max) bbox_size = max(bbox_max - bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4 * target_order, qbx_order, fmm_order=qbx_order + 3, target_association_tolerance=0.15) from pytential.target import PointsTarget fplot = FieldPlotter(bbox_center, extent=3.5 * bbox_size, npoints=150) from pytential import GeometryCollection places = GeometryCollection( { "qbx": qbx, "targets": PointsTarget(fplot.points) }, auto_where="qbx") density_discr = places.get_discretization("qbx") nodes = thaw(actx, density_discr.nodes()) angle = actx.np.arctan2(nodes[1], nodes[0]) if k: kernel = HelmholtzKernel(3) else: kernel = LaplaceKernel(3) #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None)) op = sym.D(kernel, sym.var("sigma"), qbx_forced_limit=None) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None) sigma = actx.np.cos(mode_nr * angle) if 0: from meshmode.dof_array import flatten, unflatten sigma = flatten(0 * angle) from random import randrange for i in range(5): sigma[randrange(len(sigma))] = 1 sigma = unflatten(actx, density_discr, sigma) if isinstance(kernel, HelmholtzKernel): for i, elem in np.ndenumerate(sigma): sigma[i] = elem.astype(np.complex128) fld_in_vol = actx.to_numpy( bind(places, op, auto_where=("qbx", "targets"))(actx, sigma=sigma, k=k)) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("layerpot-3d-potential.vts", [("potential", fld_in_vol)]) bdry_normals = bind(places, sym.normal( density_discr.ambient_dim))(actx).as_vector(dtype=object) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(actx, density_discr, target_order) bdry_vis.write_vtk_file("layerpot-3d-density.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ])
def D(self, dom_idx, density, qbx_forced_limit="avg"): # noqa return sym.D(self.kernel, density, k=self.domain_K_exprs[dom_idx], qbx_forced_limit=qbx_forced_limit)
def test_3d_jump_relations(ctx_factory, relation, visualize=False): # logging.basicConfig(level=logging.INFO) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) if relation == "div_s": target_order = 3 else: target_order = 4 qbx_order = target_order from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() for nel_factor in [6, 10, 14]: from meshmode.mesh.generation import generate_torus mesh = generate_torus( 5, 2, order=target_order, n_major=2*nel_factor, n_minor=nel_factor) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(3)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( pre_discr, fine_order=4*target_order, qbx_order=qbx_order, fmm_order=qbx_order + 5, fmm_backend="fmmlib" ) places = GeometryCollection(qbx) density_discr = places.get_discretization(places.auto_source.geometry) from sumpy.kernel import LaplaceKernel knl = LaplaceKernel(3) def nxcurlS(qbx_forced_limit): return sym.n_cross(sym.curl(sym.S( knl, sym.cse(sym.tangential_to_xyz(density_sym), "jxyz"), qbx_forced_limit=qbx_forced_limit))) from meshmode.dof_array import thaw x, y, z = thaw(actx, density_discr.nodes()) m = actx.np if relation == "nxcurls": density_sym = sym.make_sym_vector("density", 2) jump_identity_sym = ( nxcurlS(+1) - (nxcurlS("avg") + 0.5*sym.tangential_to_xyz(density_sym))) # The tangential coordinate system is element-local, so we can't just # conjure up some globally smooth functions, interpret their values # in the tangential coordinate system, and be done. Instead, generate # an XYZ function and project it. density = bind(places, sym.xyz_to_tangential(sym.make_sym_vector("jxyz", 3)))( actx, jxyz=sym.make_obj_array([ m.cos(0.5*x) * m.cos(0.5*y) * m.cos(0.5*z), m.sin(0.5*x) * m.cos(0.5*y) * m.sin(0.5*z), m.sin(0.5*x) * m.cos(0.5*y) * m.cos(0.5*z), ])) elif relation == "sp": density = m.cos(2*x) * m.cos(2*y) * m.cos(z) density_sym = sym.var("density") jump_identity_sym = ( sym.Sp(knl, density_sym, qbx_forced_limit=+1) - (sym.Sp(knl, density_sym, qbx_forced_limit="avg") - 0.5*density_sym)) elif relation == "div_s": density = m.cos(2*x) * m.cos(2*y) * m.cos(z) density_sym = sym.var("density") jump_identity_sym = ( sym.div(sym.S(knl, sym.normal(3).as_vector()*density_sym, qbx_forced_limit="avg")) + sym.D(knl, density_sym, qbx_forced_limit="avg")) else: raise ValueError("unexpected value of 'relation': %s" % relation) bound_jump_identity = bind(places, jump_identity_sym) jump_identity = bound_jump_identity(actx, density=density) h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) err = ( norm(density_discr, jump_identity, np.inf) / norm(density_discr, density, np.inf)) print("ERROR", h_max, err) eoc_rec.add_data_point(h_max, err) # {{{ visualization if visualize and relation == "nxcurls": nxcurlS_ext = bind(places, nxcurlS(+1))(actx, density=density) nxcurlS_avg = bind(places, nxcurlS("avg"))(actx, density=density) jtxyz = bind(places, sym.tangential_to_xyz(density_sym))( actx, density=density) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(actx, qbx.density_discr, target_order+3) bdry_normals = bind(places, sym.normal(3))(actx)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("source-%s.vtu" % nel_factor, [ ("jt", jtxyz), ("nxcurlS_ext", nxcurlS_ext), ("nxcurlS_avg", nxcurlS_avg), ("bdry_normals", bdry_normals), ]) if visualize and relation == "sp": op = sym.Sp(knl, density_sym, qbx_forced_limit=+1) sp_ext = bind(places, op)(actx, density=density) op = sym.Sp(knl, density_sym, qbx_forced_limit="avg") sp_avg = bind(places, op)(actx, density=density) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(actx, qbx.density_discr, target_order+3) bdry_normals = bind(places, sym.normal(3))(actx).as_vector(dtype=object) bdry_vis.write_vtk_file("source-%s.vtu" % nel_factor, [ ("density", density), ("sp_ext", sp_ext), ("sp_avg", sp_avg), ("bdry_normals", bdry_normals), ]) # }}} print(eoc_rec) assert eoc_rec.order_estimate() >= qbx_order - 1.5