def test_tangential_onb(actx_factory): actx = actx_factory() from meshmode.mesh.generation import generate_torus mesh = generate_torus(5, 2, order=3) discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(3)) tob = sym.tangential_onb(mesh.ambient_dim) nvecs = tob.shape[1] # make sure tangential_onb is mutually orthogonal and normalized orth_check = bind(discr, sym.make_obj_array([ np.dot(tob[:, i], tob[:, j]) - (1 if i == j else 0) for i in range(nvecs) for j in range(nvecs)]) )(actx) for orth_i in orth_check: assert actx.to_numpy( actx.np.all(actx.np.abs(orth_i) < 1e-13) ) # make sure tangential_onb is orthogonal to normal orth_check = bind(discr, sym.make_obj_array([ np.dot(tob[:, i], sym.normal(mesh.ambient_dim).as_vector()) for i in range(nvecs)]) )(actx) for orth_i in orth_check: assert actx.to_numpy( actx.np.all(actx.np.abs(orth_i) < 1e-13) )
def test_tangential_onb(ctx_factory): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import generate_torus mesh = generate_torus(5, 2, order=3) discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(3)) tob = sym.tangential_onb(mesh.ambient_dim) nvecs = tob.shape[1] # make sure tangential_onb is mutually orthogonal and normalized orth_check = bind(discr, sym.make_obj_array([ np.dot(tob[:, i], tob[:, j]) - (1 if i == j else 0) for i in range(nvecs) for j in range(nvecs)]) )(queue) for i, orth_i in enumerate(orth_check): assert (cl.clmath.fabs(orth_i) < 1e-13).get().all() # make sure tangential_onb is orthogonal to normal orth_check = bind(discr, sym.make_obj_array([ np.dot(tob[:, i], sym.normal(mesh.ambient_dim).as_vector()) for i in range(nvecs)]) )(queue) for i, orth_i in enumerate(orth_check): assert (cl.clmath.fabs(orth_i) < 1e-13).get().all()
def test_tangential_onb(ctx_factory): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import generate_torus mesh = generate_torus(5, 2, order=3) discr = Discretization(cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(3)) tob = sym.tangential_onb(mesh.ambient_dim) nvecs = tob.shape[1] # make sure tangential_onb is mutually orthogonal and normalized orth_check = bind( discr, sym.make_obj_array([ np.dot(tob[:, i], tob[:, j]) - (1 if i == j else 0) for i in range(nvecs) for j in range(nvecs) ]))(queue) for i, orth_i in enumerate(orth_check): assert (cl.clmath.fabs(orth_i) < 1e-13).get().all() # make sure tangential_onb is orthogonal to normal orth_check = bind( discr, sym.make_obj_array([ np.dot(tob[:, i], sym.normal(mesh.ambient_dim).as_vector()) for i in range(nvecs) ]))(queue) for i, orth_i in enumerate(orth_check): assert (cl.clmath.fabs(orth_i) < 1e-13).get().all()
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 __call__(self, actx: PyOpenCLArrayContext, source_dd, indices: BlockIndexRanges, **kwargs) -> BlockProxyPoints: from pytential import bind, sym source_dd = sym.as_dofdesc(source_dd) radii = bind(self.places, sym.expansion_radii(self.ambient_dim, dofdesc=source_dd))(actx) center_int = bind( self.places, sym.expansion_centers(self.ambient_dim, -1, dofdesc=source_dd))(actx) center_ext = bind( self.places, sym.expansion_centers(self.ambient_dim, +1, dofdesc=source_dd))(actx) return super().__call__(actx, source_dd, indices, expansion_radii=flatten(radii, actx), center_int=flatten(center_int, actx, leaf_class=DOFArray), center_ext=flatten(center_ext, actx, leaf_class=DOFArray), **kwargs)
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 targets_from_sources(sign, dist, dim=2): nodes = dof_array_to_numpy( actx, bind(places, sym.nodes(dim, dofdesc=dd))(actx).as_vector(object)) normals = dof_array_to_numpy( actx, bind(places, sym.normal(dim, dofdesc=dd))(actx).as_vector(object)) return actx.from_numpy(nodes + normals * sign * dist)
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_cost_model_order_varying_by_level(ctx_factory): """For FMM order varying by level, this checks to ensure that the costs are different. The varying-level case should have larger cost. """ cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ constant level to order def level_to_order_constant(kernel, kernel_args, tree, level): return 1 lpot_source = get_lpot_source(actx, 2).copy( cost_model=QBXCostModel(), fmm_level_to_order=level_to_order_constant) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(2) sym_op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) sigma = get_density(actx, density_discr) cost_constant, metadata = bind(places, sym_op).cost_per_stage( "constant_one", sigma=sigma) cost_constant = one(cost_constant.values()) metadata = one(metadata.values()) # }}} # {{{ varying level to order def level_to_order_varying(kernel, kernel_args, tree, level): return metadata["nlevels"] - level lpot_source = get_lpot_source(actx, 2).copy( cost_model=QBXCostModel(), fmm_level_to_order=level_to_order_varying) places = GeometryCollection(lpot_source) density_discr = places.get_discretization(places.auto_source.geometry) sigma = get_density(actx, density_discr) cost_varying, _ = bind(lpot_source, sym_op).cost_per_stage( "constant_one", sigma=sigma) cost_varying = one(cost_varying.values()) # }}} assert sum(cost_varying.values()) > sum(cost_constant.values())
def get_centers_on_side(lpot_src, sign): adim = lpot_src.density_discr.ambient_dim dim = lpot_src.density_discr.dim from pytential import sym, bind with cl.CommandQueue(lpot_src.cl_context) as queue: nodes = bind(lpot_src.density_discr, sym.nodes(adim))(queue) normals = bind(lpot_src.density_discr, sym.normal(adim, dim=dim))(queue) expansion_radii = lpot_src._expansion_radii("nsources").with_queue(queue) return (nodes + normals * sign * expansion_radii).as_vector(np.object)
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 targets_from_sources(sign, dist, dim=2): nodes = actx.to_numpy( flatten( bind(places, sym.nodes(dim, dofdesc=dd))(actx).as_vector(), actx)).reshape(dim, -1) normals = actx.to_numpy( flatten( bind(places, sym.normal(dim, dofdesc=dd))(actx).as_vector(), actx)).reshape(dim, -1) return actx.from_numpy(nodes + normals * sign * dist)
def test_3d_orientation(ctx_factory, what, mesh_gen_func, visualize=False): pytest.importorskip("pytential") logging.basicConfig(level=logging.INFO) ctx = ctx_factory() queue = cl.CommandQueue(ctx) mesh = mesh_gen_func() logger.info("%d elements" % mesh.nelements) from meshmode.discretization import Discretization discr = Discretization(ctx, mesh, PolynomialWarpAndBlendGroupFactory(1)) from pytential import bind, sym # {{{ check normals point outward if what == "torus": nodes = sym.nodes(mesh.ambient_dim).as_vector() angle = sym.atan2(nodes[1], nodes[0]) center_nodes = sym.make_obj_array([ 5*sym.cos(angle), 5*sym.sin(angle), 0*angle]) normal_outward_expr = ( sym.normal(mesh.ambient_dim) | (nodes-center_nodes)) else: normal_outward_expr = ( sym.normal(mesh.ambient_dim) | sym.nodes(mesh.ambient_dim)) normal_outward_check = bind(discr, normal_outward_expr)(queue).as_scalar() > 0 assert normal_outward_check.get().all(), normal_outward_check.get() # }}} normals = bind(discr, sym.normal(mesh.ambient_dim).xproject(1))(queue) if visualize: from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(queue, discr, 1) vis.write_vtk_file("normals.vtu", [ ("normals", normals), ])
def weights_and_area_elements(self): import pytential.symbolic.primitives as p from pytential.symbolic.execution import bind with cl.CommandQueue(self.cl_context) as queue: # fine_density_discr is not guaranteed to be usable for # interpolation/differentiation. Use density_discr to find # area element instead, then upsample that. area_element = self.resampler(queue, bind(self.density_discr, p.area_element())(queue)) qweight = bind(self.fine_density_discr, p.QWeight())(queue) return (area_element.with_queue(queue)*qweight).with_queue(None)
def get_arclength_parametrization_derivative(queue, density_discr, where=None): """Return x'(s), y'(s). s Follows the same direction as the parametrization. (Remark: t is the reference-to-global parametrization of the discretization). """ queue = setup_command_queue(queue=queue) dim = 2 # xp = dx/dt, yp = dy/dt, sp = ds/dt xp, yp = sym.parametrization_derivative_matrix(dim, dim - 1, where) sp = (xp[0]**2 + yp[0]**2)**(1 / 2) xps = xp[0] / sp yps = yp[0] / sp return bind(density_discr, xps)(queue), bind(density_discr, yps)(queue)
def get_bound_op(places): from sumpy.kernel import LaplaceKernel op = sym.S(LaplaceKernel(places.ambient_dim), sym.var("sigma"), qbx_forced_limit=+1) return bind(places, op)
def weights_and_area_elements(self): from pytential import bind, sym with cl.CommandQueue(self.cl_context) as queue: waa = bind(self, sym.weights_and_area_elements(self.ambient_dim))(queue) return waa.with_queue(None)
def _get_layer_potential_args(actx, places, expr, context=None, include_args=None): """ :arg expr: symbolic layer potential expression containing the kernel arguments. :arg include_args: subset of the kernel arguments to evaluate. """ from pytential import bind if context is None: context = {} if include_args is not None: kernel_arguments = { k: v for k, v in expr.kernel_arguments.items() if k in include_args } else: kernel_arguments = expr.kernel_arguments from pytential.source import evaluate_kernel_arguments return evaluate_kernel_arguments(actx, lambda expr: bind(places, expr) (actx, **context), kernel_arguments, flat=True)
def get_lpot_cost(queue, geometry_getter, kind): lpot_source = geometry_getter(queue) from pytential import sym, bind sigma_sym = sym.var("sigma") from sumpy.kernel import LaplaceKernel k_sym = LaplaceKernel(lpot_source.ambient_dim) op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) 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]) from pytools import one 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_timing_data_gathering(ctx_factory): """Test that timing data gathering can execute succesfully.""" pytest.importorskip("pyfmmlib") cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx, properties=cl.command_queue_properties.PROFILING_ENABLE) actx = PyOpenCLArrayContext(queue) lpot_source = get_lpot_source(actx, 2) places = GeometryCollection(lpot_source) dofdesc = places.auto_source.to_stage1() density_discr = places.get_discretization(dofdesc.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) timing_data = {} op_S.eval(dict(sigma=sigma), timing_data=timing_data, array_context=actx) assert timing_data print(timing_data)
def eval_inc_field_at(tgt): if 0: # plane wave return bind( tgt, get_sym_maxwell_plane_wave( amplitude_vec=np.array([1, 1, 1]), v=np.array([1, 0, 0]), omega=case.k) )(queue) else: # point source return bind( (test_source, tgt), get_sym_maxwell_point_source(mfie.kernel, j_sym, mfie.k) )(queue, j=src_j, k=case.k)
def test_geometry(ctx_getter): cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) nelements = 30 order = 5 mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements+1), order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory discr = Discretization(cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(order)) import pytential.symbolic.primitives as prim area_sym = prim.integral(2, 1, 1) area = bind(discr, area_sym)(queue) err = abs(area-2*np.pi) print(err) assert err < 1e-3
def get_interleaved_centers(queue, lpot_source): """ Return an array of shape (dim, ncenters) in which interior centers are placed next to corresponding exterior centers. """ from pytential import bind, sym int_centers = bind(lpot_source, sym.expansion_centers(lpot_source.ambient_dim, -1))(queue) ext_centers = bind(lpot_source, sym.expansion_centers(lpot_source.ambient_dim, +1))(queue) from pytential.symbolic.dof_connection import CenterGranularityConnection interleaver = CenterGranularityConnection(lpot_source.density_discr) return interleaver(queue, [int_centers, ext_centers])
def check_expansion_disks_undisturbed_by_sources(self, stage1_density_discr, tree, peer_lists, expansion_disturbance_tolerance, refine_flags, debug, wait_for=None): # Avoid generating too many kernels. from pytools import div_ceil max_levels = MAX_LEVELS_INCREMENT * div_ceil( tree.nlevels, MAX_LEVELS_INCREMENT) knl = self.code_container.expansion_disk_undisturbed_by_sources_checker( tree.dimensions, tree.coord_dtype, tree.box_id_dtype, peer_lists.peer_list_starts.dtype, tree.particle_id_dtype, max_levels) if debug: npanels_to_refine_prev = cl.array.sum(refine_flags).get() found_panel_to_refine = cl.array.zeros(self.queue, 1, np.int32) found_panel_to_refine.finish() unwrap_args = AreaQueryElementwiseTemplate.unwrap_args from pytential import bind, sym center_danger_zone_radii = flatten( bind(stage1_density_discr, sym.expansion_radii(stage1_density_discr.ambient_dim, granularity=sym.GRANULARITY_CENTER))(self.array_context)) evt = knl( *unwrap_args( tree, peer_lists, tree.box_to_qbx_source_starts, tree.box_to_qbx_source_lists, tree.qbx_panel_to_source_starts, tree.qbx_panel_to_center_starts, tree.qbx_user_source_slice.start, tree.qbx_user_center_slice.start, tree.sorted_target_ids, center_danger_zone_radii, expansion_disturbance_tolerance, tree.nqbxpanels, refine_flags, found_panel_to_refine, *tree.sources), range=slice(tree.nqbxcenters), queue=self.queue, wait_for=wait_for) cl.wait_for_events([evt]) if debug: npanels_to_refine = cl.array.sum(refine_flags).get() if npanels_to_refine > npanels_to_refine_prev: logger.debug("refiner: found {} panel(s) to refine".format( npanels_to_refine - npanels_to_refine_prev)) return found_panel_to_refine.get()[0] == 1
def test_geometry(ctx_factory): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) nelements = 30 order = 5 mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements+1), order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory discr = Discretization(actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(order)) import pytential.symbolic.primitives as prim area_sym = prim.integral(2, 1, 1) area = bind(discr, area_sym)(actx) err = abs(area-2*np.pi) print(err) assert err < 1e-3
def get_bound_op(lpot_source): from sumpy.kernel import LaplaceKernel sigma_sym = sym.var("sigma") k_sym = LaplaceKernel(lpot_source.ambient_dim) op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) return bind(lpot_source, op)
def get_slp_wall_times(lpot_source, fmm_order, qbx_order): queue = cl.CommandQueue(lpot_source.cl_context) lpot_source = lpot_source.copy( qbx_order=qbx_order, fmm_level_to_order=(False if fmm_order is False else lambda *args: fmm_order)) d = lpot_source.ambient_dim u_sym = sym.var("u") from sumpy.kernel import LaplaceKernel S = sym.S(LaplaceKernel(d), u_sym, qbx_forced_limit=-1) density_discr = lpot_source.density_discr u = cl.array.empty(queue, density_discr.nnodes, np.float64) u.fill(1) op = bind(lpot_source, S) # Warmup op(queue, u=u) times = [] from time import perf_counter as curr_time for _ in range(WALL_TIME_EXPERIMENT_TIMING_ROUNDS): t_start = curr_time() op(queue, u=u) t_end = curr_time() times.append(t_end - t_start) return times
def map_num_reference_derivative(self, expr): from pytential import bind, sym rec_operand = self.rec(expr.operand) assert isinstance(rec_operand, np.ndarray) if self.is_kind_matrix(rec_operand): raise NotImplementedError("derivatives") actx = self.array_context dofdesc = expr.dofdesc op = sym.NumReferenceDerivative(ref_axes=expr.ref_axes, operand=sym.var("u"), dofdesc=dofdesc) discr = self.places.get_discretization(dofdesc.geometry, dofdesc.discr_stage) template_ary = thaw(discr.nodes()[0], actx) rec_operand = unflatten(template_ary, actx.from_numpy(rec_operand), actx) return actx.to_numpy( flatten( bind(self.places, op)(self.array_context, u=rec_operand), actx))
def test_mean_curvature(ctx_factory, discr_name, resolutions, discr_and_ref_mean_curvature_getter, visualize=False): ctx = ctx_factory() queue = cl.CommandQueue(ctx) actx = PyOpenCLArrayContext(queue) from pytools.convergence import EOCRecorder eoc = EOCRecorder() for r in resolutions: discr, ref_mean_curvature = \ discr_and_ref_mean_curvature_getter(actx, r) mean_curvature = bind(discr, sym.mean_curvature(discr.ambient_dim))(actx) h = 1.0 / r from meshmode.dof_array import flat_norm h_error = flat_norm(mean_curvature - ref_mean_curvature, np.inf) eoc.add_data_point(h, h_error) print(eoc) order = min([g.order for g in discr.groups]) assert eoc.order_estimate() > order - 1.1
def map_node_coordinate_component(self, expr): from pytential import bind, sym op = sym.NodeCoordinateComponent(expr.ambient_axis, dofdesc=expr.dofdesc) actx = self.array_context return actx.to_numpy(flatten(bind(self.places, op)(actx), actx))
def test_interpolation(actx_factory, name, source_discr_stage, target_granularity): actx = actx_factory() nelements = 32 target_order = 7 qbx_order = 4 where = sym.as_dofdesc("test_interpolation") from_dd = sym.DOFDescriptor( geometry=where.geometry, discr_stage=source_discr_stage, granularity=sym.GRANULARITY_NODE) to_dd = sym.DOFDescriptor( geometry=where.geometry, discr_stage=sym.QBX_SOURCE_QUAD_STAGE2, granularity=target_granularity) mesh = mgen.make_curve_mesh(mgen.starfish, np.linspace(0.0, 1.0, nelements + 1), target_order) discr = Discretization(actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource(discr, fine_order=4 * target_order, qbx_order=qbx_order, fmm_order=False) from pytential import GeometryCollection places = GeometryCollection(qbx, auto_where=where) sigma_sym = sym.var("sigma") op_sym = sym.sin(sym.interp(from_dd, to_dd, sigma_sym)) bound_op = bind(places, op_sym, auto_where=where) def discr_and_nodes(stage): density_discr = places.get_discretization(where.geometry, stage) return density_discr, actx.to_numpy( flatten(density_discr.nodes(), actx) ).reshape(density_discr.ambient_dim, -1) _, target_nodes = discr_and_nodes(sym.QBX_SOURCE_QUAD_STAGE2) source_discr, source_nodes = discr_and_nodes(source_discr_stage) sigma_target = np.sin(la.norm(target_nodes, axis=0)) sigma_dev = unflatten( thaw(source_discr.nodes()[0], actx), actx.from_numpy(la.norm(source_nodes, axis=0)), actx) sigma_target_interp = actx.to_numpy( flatten(bound_op(actx, sigma=sigma_dev), actx) ) if name in ("default", "default_explicit", "stage2", "quad"): error = la.norm(sigma_target_interp - sigma_target) / la.norm(sigma_target) assert error < 1.0e-10 elif name in ("stage2_center",): assert len(sigma_target_interp) == 2 * len(sigma_target) else: raise ValueError(f"unknown test case name: {name}")
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_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 eval_repr_at(tgt, source=None): if source is None: source = qbx return bind((source, tgt), sym_repr)(queue, jt=jt, rho=rho, **knl_kwargs)
def weights_and_area_elements(self): from pytential import bind, sym with cl.CommandQueue(self.cl_context) as queue: return bind( self, sym.weights_and_area_elements( self.ambient_dim, dofdesc=sym.QBX_SOURCE_QUAD_STAGE2))( queue).with_queue(None)
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 test_unregularized_off_surface_fmm_vs_direct(ctx_getter): cl_ctx = ctx_getter() 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 test_unregularized_with_ones_kernel(ctx_getter): cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) nelements = 10 order = 8 mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements+1), order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory discr = Discretization(cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(order)) from pytential.unregularized import UnregularizedLayerPotentialSource lpot_src = UnregularizedLayerPotentialSource(discr) from sumpy.kernel import one_kernel_2d expr = sym.IntG(one_kernel_2d, sym.var("sigma"), qbx_forced_limit=None) from pytential.target import PointsTarget op_self = bind(lpot_src, expr) op_nonself = bind((lpot_src, PointsTarget(np.zeros((2, 1), dtype=float))), expr) with cl.CommandQueue(cl_ctx) as queue: sigma = cl.array.zeros(queue, discr.nnodes, dtype=float) sigma.fill(1) sigma.finish() result_self = op_self(queue, sigma=sigma) result_nonself = op_nonself(queue, sigma=sigma) assert np.allclose(result_self.get(), 2 * np.pi) assert np.allclose(result_nonself.get(), 2 * np.pi)
def test_mean_curvature(ctx_factory, discr_name, discr_and_ref_mean_curvature_getter): if discr_name == "unit sphere": pytest.skip("not implemented in 3D yet") import pytential.symbolic.primitives as prim ctx = ctx_factory() discr, ref_mean_curvature = discr_and_ref_mean_curvature_getter(ctx) with cl.CommandQueue(ctx) as queue: from pytential import bind mean_curvature = bind( discr, prim.mean_curvature(discr.ambient_dim))(queue) assert np.allclose(mean_curvature.get(), ref_mean_curvature)
def visualize_refinement(niter, stage_nr, stage_name, flags): if not visualize: return if stage_nr == 1: discr = lpot_source.density_discr elif stage_nr == 2: discr = lpot_source.stage2_density_discr else: raise ValueError("unexpected stage number") flags = flags.get() logger.info("for stage %s: splitting %d/%d stage-%d elements", stage_name, np.sum(flags), discr.mesh.nelements, stage_nr) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(wrangler.queue, discr, 3) assert len(flags) == discr.mesh.nelements flags = flags.astype(np.bool) nodes_flags = np.zeros(discr.nnodes) for grp in discr.groups: meg = grp.mesh_el_group grp.view(nodes_flags)[ flags[meg.element_nr_base:meg.nelements+meg.element_nr_base]] = 1 nodes_flags = cl.array.to_device(wrangler.queue, nodes_flags) vis_data = [ ("refine_flags", nodes_flags), ] if 0: from pytential import sym, bind bdry_normals = bind(discr, sym.normal(discr.ambient_dim))( wrangler.queue).as_vector(dtype=object) vis_data.append(("bdry_normals", bdry_normals),) vis.write_vtk_file("refinement-%s-%03d.vtu" % (stage_name, niter), vis_data)
def test_identities(ctx_getter, zero_op_name, curve_name, curve_f, qbx_order, k): cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() target_order = 7 u_sym = sym.var("u") grad_u_sym = sym.VectorVariable("grad_u") dn_u_sym = sym.var("dn_u") if k == 0: k_sym = 0 else: k_sym = "k" zero_op_table = { "green": sym.S(k_sym, dn_u_sym) - sym.D(k_sym, u_sym) - 0.5*u_sym, "green_grad": d1.nabla * d1(sym.S(k_sym, dn_u_sym)) - d2.nabla * d2(sym.D(k_sym, u_sym)) - 0.5*grad_u_sym, # only for k==0: "zero_calderon": -sym.Dp(0, sym.S(0, u_sym)) - 0.25*u_sym + sym.Sp(0, sym.Sp(0, u_sym)) } order_table = { "green": qbx_order, "green_grad": qbx_order-1, "zero_calderon": qbx_order-1, } zero_op = zero_op_table[zero_op_name] from pytools.convergence import EOCRecorder eoc_rec = EOCRecorder() for nelements in [30, 50, 70]: mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements+1), target_order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, # Don't use FMM for now fmm_order=False) # {{{ compute values of a solution to the PDE nodes_host = density_discr.nodes().get(queue) normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) normal_host = [normal[0].get(), normal[1].get()] if k != 0: angle = 0.3 wave_vec = np.array([np.cos(angle), np.sin(angle)]) u = np.exp(1j*k*np.tensordot(wave_vec, nodes_host, axes=1)) grad_u = 1j*k*wave_vec[:, np.newaxis]*u else: center = np.array([3, 1]) diff = nodes_host - center[:, np.newaxis] dist_squared = np.sum(diff**2, axis=0) dist = np.sqrt(dist_squared) u = np.log(dist) grad_u = diff/dist_squared dn_u = normal_host[0]*grad_u[0] + normal_host[1]*grad_u[1] # }}} u_dev = cl.array.to_device(queue, u) dn_u_dev = cl.array.to_device(queue, dn_u) grad_u_dev = cl.array.to_device(queue, grad_u) key = (qbx_order, curve_name, nelements, zero_op_name) bound_op = bind(qbx, zero_op) error = bound_op( queue, u=u_dev, dn_u=dn_u_dev, grad_u=grad_u_dev, k=k) if 0: pt.plot(error) pt.show() l2_error_norm = norm(density_discr, queue, error) print(key, l2_error_norm) eoc_rec.add_data_point(1/nelements, l2_error_norm) print(eoc_rec) tgt_order = order_table[zero_op_name] assert eoc_rec.order_estimate() > tgt_order - 1.3
def main(): import logging logging.basicConfig(level=logging.INFO) ctx = cl.create_some_context() queue = cl.CommandQueue(ctx) 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.discretization.connection import ( make_boundary_restriction, make_same_mesh_connection) bdry_mesh, bdry_discr, bdry_connection = make_boundary_restriction( queue, vol_discr, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) vol_to_ovsmp_vol = make_same_mesh_connection( queue, 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())(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, Variable as var) r = pymbolic_real_norm_2(make_sym_vector("d", 3)) expr = var("log")(r) scaling = 1/(2*var("pi")) from sumpy.kernel import ExpressionKernel return ExpressionKernel( dim=3, expression=expr, scaling=scaling, is_complex_valued=False) laplace_2d_in_3d_kernel = get_kernel() layer_pot = LayerPotential(ctx, [ LineTaylorLocalExpansion(laplace_2d_in_3d_kernel, order=vol_qbx_order)]) targets = cl.array.zeros(queue, (3,) + vol_x.shape[1:], vol_x.dtype) targets[:2] = vol_x center_dist = np.min( cl.clmath.sqrt( bind(vol_discr, p.area_element())(queue)).get()) centers = make_obj_array([ci.copy().reshape(vol_discr.nnodes) for ci in targets]) centers[2][:] = 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() * p.QWeight())(queue) 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),) ) 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"), 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)
def main(): # cl.array.to_device(queue, numpy_array) from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource("ellipsoid.step"), 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)) print("%d elements" % 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 + 10, fmm_backend="fmmlib") from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator pde_op = MuellerAugmentedMFIEOperator( omega=0.4, epss=[1.4, 1.0], mus=[1.2, 1.0], ) from pytential import bind, sym unk = pde_op.make_unknown("sigma") sym_operator = pde_op.operator(unk) sym_rhs = pde_op.rhs( sym.make_sym_vector("Einc", 3), sym.make_sym_vector("Hinc", 3)) sym_repr = pde_op.representation(0, unk) if 1: expr = sym_repr print(sym.pretty(expr)) print("#"*80) from pytential.target import PointsTarget tgt_points=np.zeros((3,1)) tgt_points[0,0] = 100 tgt_points[1,0] = -200 tgt_points[2,0] = 300 bound_op = bind((qbx, PointsTarget(tgt_points)), expr) print(bound_op.code) if 1: def green3e(x,y,z,source,strength,k): # electric field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # E = (I + Hess)(exp(ikr)/r) dot (strength) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout = np.exp(1j*k*rr)/rr evec = fout*strength qmat = np.zeros((3,3),dtype=np.complex128) qmat[0,0]=(2*dx**2-dy**2-dz**2)*(1-1j*k*rr) qmat[1,1]=(2*dy**2-dz**2-dx**2)*(1-1j*k*rr) qmat[2,2]=(2*dz**2-dx**2-dy**2)*(1-1j*k*rr) qmat[0,0]=qmat[0,0]+(-k**2*dx**2*rr**2) qmat[1,1]=qmat[1,1]+(-k**2*dy**2*rr**2) qmat[2,2]=qmat[2,2]+(-k**2*dz**2*rr**2) qmat[0,1]=(3-k**2*rr**2-3*1j*k*rr)*(dx*dy) qmat[1,2]=(3-k**2*rr**2-3*1j*k*rr)*(dy*dz) qmat[2,0]=(3-k**2*rr**2-3*1j*k*rr)*(dz*dx) qmat[1,0]=qmat[0,1] qmat[2,1]=qmat[1,2] qmat[0,2]=qmat[2,0] fout=np.exp(1j*k*rr)/rr**5/k**2 fvec = fout*np.dot(qmat,strength) evec = evec + fvec return evec def green3m(x,y,z,source,strength,k): # magnetic field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # H = curl((I + Hess)(exp(ikr)/r) dot (strength)) = # strength \cross \grad (exp(ikr)/r) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout=(1-1j*k*rr)*np.exp(1j*k*rr)/rr**3 fvec = np.zeros(3,dtype=np.complex128) fvec[0] = fout*dx fvec[1] = fout*dy fvec[2] = fout*dz hvec = np.cross(strength,fvec) return hvec def dipole3e(x,y,z,source,strength,k): # # evalaute electric and magnetic field due # to monochromatic electric dipole located at "source" # with intensity "strength" evec = green3e(x,y,z,source,strength,k) evec = evec*1j*k hvec = green3m(x,y,z,source,strength,k) return evec,hvec def dipole3m(x,y,z,source,strength,k): # # evalaute electric and magnetic field due # to monochromatic magnetic dipole located at "source" # with intensity "strength" evec = green3m(x,y,z,source,strength,k) hvec = green3e(x,y,z,source,strength,k) hvec = -hvec*1j*k return evec,hvec def dipole3eall(x,y,z,sources,strengths,k): ns = len(strengths) evec = np.zeros(3,dtype=np.complex128) hvec = np.zeros(3,dtype=np.complex128) for i in range(ns): evect,hvect = dipole3e(x,y,z,sources[i],strengths[i],k) evec = evec + evect hvec = hvec + hvect nodes = density_discr.nodes().with_queue(queue).get() source = [0.01,-0.03,0.02] # source = cl.array.to_device(queue,np.zeros(3)) # source[0] = 0.01 # source[1] =-0.03 # source[2] = 0.02 strength = np.ones(3) # evec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) # hvec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) evec = np.zeros((3,len(nodes[0])),dtype=np.complex128) hvec = np.zeros((3,len(nodes[0])),dtype=np.complex128) for i in range(len(nodes[0])): evec[:,i],hvec[:,i] = dipole3e(nodes[0][i],nodes[1][i],nodes[2][i],source,strength,k) print(np.shape(hvec)) print(type(evec)) print(type(hvec)) evec = cl.array.to_device(queue,evec) hvec = cl.array.to_device(queue,hvec) bvp_rhs = bind(qbx, sym_rhs)(queue,Einc=evec,Hinc=hvec) print(np.shape(bvp_rhs)) print(type(bvp_rhs)) # print(bvp_rhs) 1/-1 bound_op = bind(qbx, sym_operator) from pytential.solve import gmres if 0: gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) sigma = gmres_result.solution fld_at_tgt = bind((qbx, PointsTarget(tgt_points)), sym_repr)(queue, sigma=bvp_rhs,k=k) fld_at_tgt = np.array([ fi.get() for fi in fld_at_tgt ]) print(fld_at_tgt) 1/0 # }}} #mlab.figure(bgcolor=(1, 1, 1)) if 1: from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, target_order) bdry_normals = bind(density_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("source.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ]) fplot = FieldPlotter(bbox_center, extent=2*bbox_size, npoints=(150, 150, 1)) qbx_tgt_tol = qbx.copy(target_association_tolerance=0.1) from pytential.target import PointsTarget from pytential.qbx import QBXTargetAssociationFailedException rho_sym = sym.var("rho") try: fld_in_vol = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), sym.make_obj_array([ sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None), sym.d_dx(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dy(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dz(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), ]) )(queue, jt=jt, rho=rho, k=k) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed_targets", e.failed_target_flags.get(queue)) ]) raise fld_in_vol = sym.make_obj_array( [fiv.get() for fiv in fld_in_vol]) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("potential", fld_in_vol[0]), ("grad", fld_in_vol[1:]), ] )
from pytential.discretization.qbx import make_upsampling_qbx_discr discr = make_upsampling_qbx_discr( cl_ctx, mesh, target_order, qbx_order) nodes = discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) from pytential import bind, sym representation = sym.S(0, sym.var("sigma")) op = representation bc = cl.clmath.cos(mode_nr*angle) bound_op = bind(discr, op) from pytential.gmres import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma"), bc, tol=1e-14, progress=True, hard_failure=True) import sys sys.exit() sigma = gmres_result.solution fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) from pytential.discretization.target import PointsTarget fld_in_vol = bind( (discr, PointsTarget(fplot.points)),
def centers(self, target_discr, sign): from pytential import sym, bind with cl.CommandQueue(self.cl_context) as queue: return bind(target_discr, sym.Nodes() + 2*sign*sym.area_element()*sym.normal())(queue) \ .as_vector(np.object)
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 test_sanity_single_element(ctx_getter, dim, order, visualize=False): pytest.importorskip("pytential") cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) from modepy.tools import UNIT_VERTICES vertices = UNIT_VERTICES[dim].T.copy() center = np.empty(dim, np.float64) center.fill(-0.5) import modepy as mp from meshmode.mesh import SimplexElementGroup, Mesh mg = SimplexElementGroup( order=order, vertex_indices=np.arange(dim+1, dtype=np.int32).reshape(1, -1), nodes=mp.warp_and_blend_nodes(dim, order).reshape(dim, 1, -1), dim=dim) mesh = Mesh(vertices, [mg]) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ PolynomialWarpAndBlendGroupFactory vol_discr = Discretization(cl_ctx, mesh, PolynomialWarpAndBlendGroupFactory(order+3)) # {{{ volume calculation check vol_x = vol_discr.nodes().with_queue(queue) vol_one = vol_x[0].copy() vol_one.fill(1) from pytential import norm, integral # noqa from pytools import factorial true_vol = 1/factorial(dim) * 2**dim comp_vol = integral(vol_discr, queue, vol_one) rel_vol_err = abs(true_vol - comp_vol) / true_vol assert rel_vol_err < 1e-12 # }}} # {{{ boundary discretization from meshmode.discretization.connection import make_boundary_restriction bdry_mesh, bdry_discr, bdry_connection = make_boundary_restriction( queue, vol_discr, PolynomialWarpAndBlendGroupFactory(order + 3)) # }}} # {{{ visualizers from meshmode.discretization.visualization import make_visualizer #vol_vis = make_visualizer(queue, vol_discr, 4) bdry_vis = make_visualizer(queue, bdry_discr, 4) # }}} from pytential import bind, sym bdry_normals = bind(bdry_discr, sym.normal())(queue).as_vector(dtype=object) if visualize: bdry_vis.write_vtk_file("boundary.vtu", [ ("bdry_normals", bdry_normals) ]) from pytential import bind, sym normal_outward_check = bind(bdry_discr, sym.normal() | (sym.Nodes() + 0.5*sym.ones_vec(dim)), )(queue).as_scalar() > 0 assert normal_outward_check.get().all(), normal_outward_check.get()
def main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import generate_torus rout = 10 rin = 1 if 1: base_mesh = generate_torus( rout, rin, 40, 4, mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes # nx = 1 # ny = 1 nz = 1 dz = 0 meshes = [ affine_map( base_mesh, A=np.diag([1, 1, 1]), b=np.array([0, 0, iz*dz])) for iz in range(nz)] mesh = merge_disjoint_meshes(meshes, single_group=True) if 0: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() pre_density_discr = Discretization( cl_ctx, 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 ).with_refinement() density_discr = qbx.density_discr # {{{ describe bvp from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(3) cse = sym.cse sigma_sym = sym.var("sigma") #sqrt_w = sym.sqrt_jac_q_weight(3) sqrt_w = 1 inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (loc_sign*0.5*sigma_sym + sqrt_w*( sym.S(kernel, inv_sqrt_w_sigma) + sym.D(kernel, inv_sqrt_w_sigma) )) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) source = np.array([rout, 0, 0]) def u_incoming_func(x): # return 1/cl.clmath.sqrt( (x[0] - source[0])**2 # +(x[1] - source[1])**2 # +(x[2] - source[2])**2 ) return 1.0/la.norm(x.get()-source[:, None], axis=0) bc = cl.array.to_device(queue, u_incoming_func(nodes)) bvp_rhs = bind(qbx, sqrt_w*sym.var("bc"))(queue, bc=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, stall_iterations=0, hard_failure=True) sigma = bind(qbx, sym.var("sigma")/sqrt_w)(queue, sigma=gmres_result.solution) # }}} from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, 20) bdry_vis.write_vtk_file("laplace.vtu", [ ("sigma", sigma), ]) # {{{ postprocess/visualize repr_kwargs = dict(qbx_forced_limit=None) representation_sym = ( sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) + sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(3), extent=20, npoints=50) targets = cl.array.to_device(queue, fplot.points) qbx_stick_out = qbx.copy(target_stick_out_factor=0.2) try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), representation_sym)(queue, sigma=sigma).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "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( "potential-laplace-3d.vts", [ ("potential", fld_in_vol), ] )
np.linspace(0, 1, nelements+1), target_order) from pytential.discretization.qbx import make_upsampling_qbx_discr discr = make_upsampling_qbx_discr( cl_ctx, mesh, target_order, qbx_order) nodes = discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) from pytential import bind, sym representation = sym.S(0, sym.var("sigma")) op = representation bc = cl.clmath.cos(mode_nr*angle) bound_op = bind(discr, op) from sumpy.tools import build_matrix mat = build_matrix(bound_op.scipy_op(queue, "sigma")) w, v = la.eig(mat) import matplotlib.pyplot as pt pt.plot(w.real, w.imag, "x") pt.rc("font", size=20) pt.grid() pt.show()
def run_dielectric_test(cl_ctx, queue, nelements, qbx_order, op_class, mode, k0=3, k1=2.9, mesh_order=10, bdry_quad_order=None, bdry_ovsmp_quad_order=None, use_l2_weighting=False, fmm_order=None, visualize=False): if fmm_order is None: fmm_order = qbx_order * 2 if bdry_quad_order is None: bdry_quad_order = mesh_order if bdry_ovsmp_quad_order is None: bdry_ovsmp_quad_order = 4*bdry_quad_order from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh( partial(ellipse, 3), np.linspace(0, 1, nelements+1), mesh_order) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) logger.info("%d elements" % mesh.nelements) # from meshmode.discretization.visualization import make_visualizer # bdry_vis = make_visualizer(queue, density_discr, 20) # {{{ solve bvp from sumpy.kernel import HelmholtzKernel, AxisTargetDerivative kernel = HelmholtzKernel(2) beta = 2.5 K0 = np.sqrt(k0**2-beta**2) # noqa K1 = np.sqrt(k1**2-beta**2) # noqa pde_op = op_class( mode, k_vacuum=1, interfaces=((0, 1, sym.DEFAULT_SOURCE),), domain_k_exprs=(k0, k1), beta=beta, use_l2_weighting=use_l2_weighting) op_unknown_sym = pde_op.make_unknown("unknown") representation0_sym = pde_op.representation(op_unknown_sym, 0) representation1_sym = pde_op.representation(op_unknown_sym, 1) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ).with_refinement() #print(sym.pretty(pde_op.operator(op_unknown_sym))) #1/0 bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym)) e_factor = float(pde_op.ez_enabled) h_factor = float(pde_op.hz_enabled) e_sources_0 = make_obj_array(list(np.array([ [0.1, 0.2] ]).T.copy())) e_strengths_0 = np.array([1*e_factor]) e_sources_1 = make_obj_array(list(np.array([ [4, 4] ]).T.copy())) e_strengths_1 = np.array([1*e_factor]) h_sources_0 = make_obj_array(list(np.array([ [0.2, 0.1] ]).T.copy())) h_strengths_0 = np.array([1*h_factor]) h_sources_1 = make_obj_array(list(np.array([ [4, 5] ]).T.copy())) h_strengths_1 = np.array([1*h_factor]) kernel_grad = [ AxisTargetDerivative(i, kernel) for i in range(density_discr.ambient_dim)] from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False) pot_p2p_grad = P2P(cl_ctx, kernel_grad, exclude_self=False) normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) tangent = bind( density_discr, sym.pseudoscalar()/sym.area_element())(queue).as_vector(np.object) _, (E0,) = pot_p2p(queue, density_discr.nodes(), e_sources_0, [e_strengths_0], out_host=False, k=K0) _, (E1,) = pot_p2p(queue, density_discr.nodes(), e_sources_1, [e_strengths_1], out_host=False, k=K1) _, (grad0_E0, grad1_E0) = pot_p2p_grad( queue, density_discr.nodes(), e_sources_0, [e_strengths_0], out_host=False, k=K0) _, (grad0_E1, grad1_E1) = pot_p2p_grad( queue, density_discr.nodes(), e_sources_1, [e_strengths_1], out_host=False, k=K1) _, (H0,) = pot_p2p(queue, density_discr.nodes(), h_sources_0, [h_strengths_0], out_host=False, k=K0) _, (H1,) = pot_p2p(queue, density_discr.nodes(), h_sources_1, [h_strengths_1], out_host=False, k=K1) _, (grad0_H0, grad1_H0) = pot_p2p_grad( queue, density_discr.nodes(), h_sources_0, [h_strengths_0], out_host=False, k=K0) _, (grad0_H1, grad1_H1) = pot_p2p_grad( queue, density_discr.nodes(), h_sources_1, [h_strengths_1], out_host=False, k=K1) E0_dntarget = (grad0_E0*normal[0] + grad1_E0*normal[1]) # noqa E1_dntarget = (grad0_E1*normal[0] + grad1_E1*normal[1]) # noqa H0_dntarget = (grad0_H0*normal[0] + grad1_H0*normal[1]) # noqa H1_dntarget = (grad0_H1*normal[0] + grad1_H1*normal[1]) # noqa E0_dttarget = (grad0_E0*tangent[0] + grad1_E0*tangent[1]) # noqa E1_dttarget = (grad0_E1*tangent[0] + grad1_E1*tangent[1]) # noqa H0_dttarget = (grad0_H0*tangent[0] + grad1_H0*tangent[1]) # noqa H1_dttarget = (grad0_H1*tangent[0] + grad1_H1*tangent[1]) # noqa sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue) bvp_rhs = np.zeros(len(pde_op.bcs), dtype=np.object) for i_bc, terms in enumerate(pde_op.bcs): for term in terms: assert term.i_interface == 0 if term.field_kind == pde_op.field_kind_e: if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += ( term.coeff_outer * E0 + term.coeff_inner * E1) elif term.direction == pde_op.dir_normal: bvp_rhs[i_bc] += ( term.coeff_outer * E0_dntarget + term.coeff_inner * E1_dntarget) elif term.direction == pde_op.dir_tangential: bvp_rhs[i_bc] += ( term.coeff_outer * E0_dttarget + term.coeff_inner * E1_dttarget) else: raise NotImplementedError("direction spec in RHS") elif term.field_kind == pde_op.field_kind_h: if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += ( term.coeff_outer * H0 + term.coeff_inner * H1) elif term.direction == pde_op.dir_normal: bvp_rhs[i_bc] += ( term.coeff_outer * H0_dntarget + term.coeff_inner * H1_dntarget) elif term.direction == pde_op.dir_tangential: bvp_rhs[i_bc] += ( term.coeff_outer * H0_dttarget + term.coeff_inner * H1_dttarget) else: raise NotImplementedError("direction spec in RHS") if use_l2_weighting: bvp_rhs[i_bc] *= sqrt_w scipy_op = bound_pde_op.scipy_op(queue, "unknown", domains=[sym.DEFAULT_TARGET]*len(pde_op.bcs), K0=K0, K1=K1, dtype=np.complex128) if mode == "tem" or op_class is SRep: from sumpy.tools import vector_from_device, vector_to_device from pytential.solve import lu unknown = lu(scipy_op, vector_from_device(queue, bvp_rhs)) unknown = vector_to_device(queue, unknown) else: from pytential.solve import gmres gmres_result = gmres(scipy_op, bvp_rhs, tol=1e-14, progress=True, hard_failure=True, stall_iterations=0) unknown = gmres_result.solution # }}} targets_0 = make_obj_array(list(np.array([ [3.2 + t, -4] for t in [0, 0.5, 1] ]).T.copy())) targets_1 = make_obj_array(list(np.array([ [t*-0.3, t*-0.2] for t in [0, 0.5, 1] ]).T.copy())) from pytential.target import PointsTarget from sumpy.tools import vector_from_device F0_tgt = vector_from_device(queue, bind( # noqa (qbx, PointsTarget(targets_0)), representation0_sym)(queue, unknown=unknown, K0=K0, K1=K1)) F1_tgt = vector_from_device(queue, bind( # noqa (qbx, PointsTarget(targets_1)), representation1_sym)(queue, unknown=unknown, K0=K0, K1=K1)) _, (E0_tgt_true,) = pot_p2p(queue, targets_0, e_sources_0, [e_strengths_0], out_host=True, k=K0) _, (E1_tgt_true,) = pot_p2p(queue, targets_1, e_sources_1, [e_strengths_1], out_host=True, k=K1) _, (H0_tgt_true,) = pot_p2p(queue, targets_0, h_sources_0, [h_strengths_0], out_host=True, k=K0) _, (H1_tgt_true,) = pot_p2p(queue, targets_1, h_sources_1, [h_strengths_1], out_host=True, k=K1) err_F0_total = 0 # noqa err_F1_total = 0 # noqa i_field = 0 def vec_norm(ary): return la.norm(ary.reshape(-1)) def field_kind_to_string(field_kind): return {pde_op.field_kind_e: "E", pde_op.field_kind_h: "H"}[field_kind] for field_kind in pde_op.field_kinds: if not pde_op.is_field_present(field_kind): continue if field_kind == pde_op.field_kind_e: F0_tgt_true = E0_tgt_true # noqa F1_tgt_true = E1_tgt_true # noqa elif field_kind == pde_op.field_kind_h: F0_tgt_true = H0_tgt_true # noqa F1_tgt_true = H1_tgt_true # noqa else: assert False abs_err_F0 = vec_norm(F0_tgt[i_field] - F0_tgt_true) # noqa abs_err_F1 = vec_norm(F1_tgt[i_field] - F1_tgt_true) # noqa rel_err_F0 = abs_err_F0/vec_norm(F0_tgt_true) # noqa rel_err_F1 = abs_err_F1/vec_norm(F1_tgt_true) # noqa err_F0_total = max(rel_err_F0, err_F0_total) # noqa err_F1_total = max(rel_err_F1, err_F1_total) # noqa print("Abs Err %s0" % field_kind_to_string(field_kind), abs_err_F0) print("Abs Err %s1" % field_kind_to_string(field_kind), abs_err_F1) print("Rel Err %s0" % field_kind_to_string(field_kind), rel_err_F0) print("Rel Err %s1" % field_kind_to_string(field_kind), rel_err_F1) i_field += 1 if visualize: from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300) from pytential.target import PointsTarget fld0 = bind( (qbx, PointsTarget(fplot.points)), representation0_sym)(queue, unknown=unknown, K0=K0) fld1 = bind( (qbx, PointsTarget(fplot.points)), representation1_sym)(queue, unknown=unknown, K1=K1) comp_fields = [] i_field = 0 for field_kind in pde_op.field_kinds: if not pde_op.is_field_present(field_kind): continue fld_str = field_kind_to_string(field_kind) comp_fields.extend([ ("%s_fld0" % fld_str, fld0[i_field].get()), ("%s_fld1" % fld_str, fld1[i_field].get()), ]) i_field += 0 low_order_qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=2, fmm_order=3).with_refinement() from sumpy.kernel import LaplaceKernel from pytential.target import PointsTarget ones = (cl.array.empty(queue, (density_discr.nnodes,), dtype=np.float64) .fill(1)) ind_func = - bind((low_order_qbx, PointsTarget(fplot.points)), sym.D(LaplaceKernel(2), sym.var("u")))( queue, u=ones).get() _, (e_fld0_true,) = pot_p2p( queue, fplot.points, e_sources_0, [e_strengths_0], out_host=True, k=K0) _, (e_fld1_true,) = pot_p2p( queue, fplot.points, e_sources_1, [e_strengths_1], out_host=True, k=K1) _, (h_fld0_true,) = pot_p2p( queue, fplot.points, h_sources_0, [h_strengths_0], out_host=True, k=K0) _, (h_fld1_true,) = pot_p2p( queue, fplot.points, h_sources_1, [h_strengths_1], out_host=True, k=K1) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-n%d.vts" % nelements, [ ("e_fld0_true", e_fld0_true), ("e_fld1_true", e_fld1_true), ("h_fld0_true", h_fld0_true), ("h_fld1_true", h_fld1_true), ("ind", ind_func), ] + comp_fields ) return err_F0_total, err_F1_total
def test_off_surface_eval_vs_direct(ctx_getter, do_plot=False): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) # 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( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) direct_qbx, _ = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order, fmm_order=False, target_association_tolerance=0.05, ).with_refinement() 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, ).with_refinement() fplot = FieldPlotter(np.zeros(2), extent=5, npoints=1000) 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) from pytential.qbx import QBXTargetAssociationFailedException try: direct_density_discr = direct_qbx.density_discr direct_sigma = direct_density_discr.zeros(queue) + 1 direct_fld_in_vol = bind((direct_qbx, ptarget), op)( queue, sigma=direct_sigma) except QBXTargetAssociationFailedException as e: fplot.show_scalar_in_matplotlib(e.failed_target_flags.get(queue)) import matplotlib.pyplot as pt pt.show() raise fmm_density_discr = fmm_qbx.density_discr fmm_sigma = fmm_density_discr.zeros(queue) + 1 fmm_fld_in_vol = bind((fmm_qbx, ptarget), op)(queue, sigma=fmm_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) if do_plot: #fplot.show_scalar_in_mayavi(0.1*.get(queue)) fplot.write_vtk_file("potential.vts", [ ("fmm_fld_in_vol", fmm_fld_in_vol.get(queue)), ("direct_fld_in_vol", direct_fld_in_vol.get(queue)) ]) assert linf_err < 1e-3
def run_int_eq_test( cl_ctx, queue, curve_f, nelements, qbx_order, bc_type, loc_sign, k, target_order, source_order): mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements+1), target_order) if 0: from pytential.visualization import show_mesh show_mesh(mesh) pt.gca().set_aspect("equal") pt.show() 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)) if source_order is None: source_order = 4*target_order qbx = QBXLayerPotentialSource( density_discr, fine_order=source_order, qbx_order=qbx_order, # Don't use FMM for now fmm_order=False) # {{{ set up operator from pytential.symbolic.pde.scalar import ( DirichletOperator, NeumannOperator) from sumpy.kernel import LaplaceKernel, HelmholtzKernel, AxisTargetDerivative if k: knl = HelmholtzKernel(2) knl_kwargs = {"k": k} else: knl = LaplaceKernel(2) knl_kwargs = {} if knl.is_complex_valued: dtype = np.complex128 else: dtype = np.float64 if bc_type == "dirichlet": op = DirichletOperator((knl, knl_kwargs), loc_sign, use_l2_weighting=True) elif bc_type == "neumann": op = NeumannOperator((knl, knl_kwargs), loc_sign, use_l2_weighting=True, use_improved_operator=False) else: assert False op_u = op.operator(sym.var("u")) # }}} # {{{ set up test data inner_radius = 0.1 outer_radius = 2 if loc_sign < 0: test_src_geo_radius = outer_radius test_tgt_geo_radius = inner_radius else: test_src_geo_radius = inner_radius test_tgt_geo_radius = outer_radius point_sources = make_circular_point_group(10, test_src_geo_radius, func=lambda x: x**1.5) test_targets = make_circular_point_group(20, test_tgt_geo_radius) np.random.seed(22) source_charges = np.random.randn(point_sources.shape[1]) source_charges[-1] = -np.sum(source_charges[:-1]) source_charges = source_charges.astype(dtype) assert np.sum(source_charges) < 1e-15 # }}} if 0: # show geometry, centers, normals nodes_h = density_discr.nodes().get(queue=queue) pt.plot(nodes_h[0], nodes_h[1], "x-") normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) pt.quiver(nodes_h[0], nodes_h[1], normal[0].get(queue), normal[1].get(queue)) pt.gca().set_aspect("equal") pt.show() # {{{ establish BCs from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [knl], exclude_self=False, value_dtypes=dtype) evt, (test_direct,) = pot_p2p( queue, test_targets, point_sources, [source_charges], out_host=False, **knl_kwargs) nodes = density_discr.nodes() evt, (src_pot,) = pot_p2p( queue, nodes, point_sources, [source_charges], **knl_kwargs) grad_p2p = P2P(cl_ctx, [AxisTargetDerivative(0, knl), AxisTargetDerivative(1, knl)], exclude_self=False, value_dtypes=dtype) evt, (src_grad0, src_grad1) = grad_p2p( queue, nodes, point_sources, [source_charges], **knl_kwargs) if bc_type == "dirichlet": bc = src_pot elif bc_type == "neumann": normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) bc = (src_grad0*normal[0] + src_grad1*normal[1]) # }}} # {{{ solve bound_op = bind(qbx, op_u) rhs = bind(density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "u", k=k), rhs, tol=1e-14, progress=True, hard_failure=False) u = gmres_result.solution print("gmres state:", gmres_result.state) if 0: # {{{ build matrix for spectrum check from sumpy.tools import build_matrix mat = build_matrix(bound_op.scipy_op("u")) w, v = la.eig(mat) if 0: pt.imshow(np.log10(1e-20+np.abs(mat))) pt.colorbar() pt.show() #assert abs(s[-1]) < 1e-13, "h #assert abs(s[-2]) > 1e-7 #from pudb import set_trace; set_trace() # }}} # }}} # {{{ error check from pytential.target import PointsTarget bound_tgt_op = bind((qbx, PointsTarget(test_targets)), op.representation(sym.var("u"))) test_via_bdry = bound_tgt_op(queue, u=u, k=k) err = test_direct-test_via_bdry err = err.get() test_direct = test_direct.get() test_via_bdry = test_via_bdry.get() # {{{ remove effect of net source charge if k == 0 and bc_type == "neumann" and loc_sign == -1: # remove constant offset in interior Laplace Neumann error tgt_ones = np.ones_like(test_direct) tgt_ones = tgt_ones/la.norm(tgt_ones) err = err - np.vdot(tgt_ones, err)*tgt_ones # }}} rel_err_2 = la.norm(err)/la.norm(test_direct) rel_err_inf = la.norm(err, np.inf)/la.norm(test_direct, np.inf) # }}} print("rel_err_2: %g rel_err_inf: %g" % (rel_err_2, rel_err_inf)) # {{{ test tangential derivative bound_t_deriv_op = bind(qbx, op.representation( sym.var("u"), map_potentials=sym.tangential_derivative, qbx_forced_limit=loc_sign)) #print(bound_t_deriv_op.code) tang_deriv_from_src = bound_t_deriv_op(queue, u=u).as_scalar().get() tangent = bind( density_discr, sym.pseudoscalar()/sym.area_element())(queue).as_vector(np.object) tang_deriv_ref = (src_grad0 * tangent[0] + src_grad1 * tangent[1]).get() if 0: pt.plot(tang_deriv_ref.real) pt.plot(tang_deriv_from_src.real) pt.show() td_err = tang_deriv_from_src - tang_deriv_ref rel_td_err_inf = la.norm(td_err, np.inf)/la.norm(tang_deriv_ref, np.inf) print("rel_td_err_inf: %g" % rel_td_err_inf) # }}} # {{{ plotting if 0: fplot = FieldPlotter(np.zeros(2), extent=1.25*2*max(test_src_geo_radius, test_tgt_geo_radius), npoints=200) #pt.plot(u) #pt.show() evt, (fld_from_src,) = pot_p2p( queue, fplot.points, point_sources, [source_charges], **knl_kwargs) fld_from_bdry = bind( (qbx, PointsTarget(fplot.points)), op.representation(sym.var("u")) )(queue, u=u, k=k) fld_from_src = fld_from_src.get() fld_from_bdry = fld_from_bdry.get() nodes = density_discr.nodes().get(queue=queue) def prep(): pt.plot(point_sources[0], point_sources[1], "o", label="Monopole 'Point Charges'") pt.plot(test_targets[0], test_targets[1], "v", label="Observation Points") pt.plot(nodes[0], nodes[1], "k-", label=r"$\Gamma$") from matplotlib.cm import get_cmap cmap = get_cmap() cmap._init() if 0: cmap._lut[(cmap.N*99)//100:, -1] = 0 # make last percent transparent? prep() if 1: pt.subplot(131) pt.title("Field error (loc_sign=%s)" % loc_sign) log_err = np.log10(1e-20+np.abs(fld_from_src-fld_from_bdry)) log_err = np.minimum(-3, log_err) fplot.show_scalar_in_matplotlib(log_err, cmap=cmap) #from matplotlib.colors import Normalize #im.set_norm(Normalize(vmin=-6, vmax=1)) cb = pt.colorbar(shrink=0.9) cb.set_label(r"$\log_{10}(\mathdefault{Error})$") if 1: pt.subplot(132) prep() pt.title("Source Field") fplot.show_scalar_in_matplotlib( fld_from_src.real, max_val=3) pt.colorbar(shrink=0.9) if 1: pt.subplot(133) prep() pt.title("Solved Field") fplot.show_scalar_in_matplotlib( fld_from_bdry.real, max_val=3) pt.colorbar(shrink=0.9) # total field #fplot.show_scalar_in_matplotlib( #fld_from_src.real+fld_from_bdry.real, max_val=0.1) #pt.colorbar() pt.legend(loc="best", prop=dict(size=15)) from matplotlib.ticker import NullFormatter pt.gca().xaxis.set_major_formatter(NullFormatter()) pt.gca().yaxis.set_major_formatter(NullFormatter()) pt.gca().set_aspect("equal") if 0: border_factor_top = 0.9 border_factor = 0.3 xl, xh = pt.xlim() xhsize = 0.5*(xh-xl) pt.xlim(xl-border_factor*xhsize, xh+border_factor*xhsize) yl, yh = pt.ylim() yhsize = 0.5*(yh-yl) pt.ylim(yl-border_factor_top*yhsize, yh+border_factor*yhsize) #pt.savefig("helmholtz.pdf", dpi=600) pt.show() # }}} class Result(Record): pass return Result( rel_err_2=rel_err_2, rel_err_inf=rel_err_inf, rel_td_err_inf=rel_td_err_inf, gmres_result=gmres_result)
def test_perf_data_gathering(ctx_getter, n_arms=5): cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) # prevent cache 'splosion from sympy.core.cache import clear_cache clear_cache() target_order = 8 starfish_func = NArmedStarfish(n_arms, 0.8) mesh = make_curve_mesh( starfish_func, np.linspace(0, 1, n_arms * 30), target_order) sigma_sym = sym.var("sigma") # The kernel doesn't really matter here from sumpy.kernel import LaplaceKernel k_sym = LaplaceKernel(mesh.ambient_dim) sym_op = sym.S(k_sym, sigma_sym, qbx_forced_limit=+1) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) results = [] def inspect_geo_data(insn, bound_expr, geo_data): from pytential.qbx.fmm import assemble_performance_data perf_data = assemble_performance_data(geo_data, uses_pde_expansions=True) results.append(perf_data) return False # no need to do the actual FMM from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource( pre_density_discr, 4*target_order, # qbx order and fmm order don't really matter 10, fmm_order=10, _expansions_in_tree_have_extent=True, _expansion_stick_out_factor=0.5, geometry_data_inspector=inspect_geo_data, target_association_tolerance=1e-10, ) lpot_source, _ = lpot_source.with_refinement() density_discr = lpot_source.density_discr if 0: from meshmode.discretization.visualization import draw_curve draw_curve(density_discr) import matplotlib.pyplot as plt plt.show() nodes = density_discr.nodes().with_queue(queue) sigma = cl.clmath.sin(10 * nodes[0]) bind(lpot_source, sym_op)(queue, sigma=sigma)
def test_3d_jump_relations(ctx_factory, relation, visualize=False): # logging.basicConfig(level=logging.INFO) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) 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_outer=2*nel_factor, n_inner=nel_factor) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_discr = Discretization( cl_ctx, 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" ).with_refinement() 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))) x, y, z = qbx.density_discr.nodes().with_queue(queue) m = cl.clmath 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( qbx, sym.xyz_to_tangential(sym.make_sym_vector("jxyz", 3)))( queue, 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(qbx, jump_identity_sym) jump_identity = bound_jump_identity(queue, density=density) err = ( norm(qbx, queue, jump_identity, np.inf) / norm(qbx, queue, density, np.inf)) print("ERROR", qbx.h_max, err) eoc_rec.add_data_point(qbx.h_max, err) # {{{ visualization if visualize and relation == "nxcurls": nxcurlS_ext = bind(qbx, nxcurlS(+1))(queue, density=density) nxcurlS_avg = bind(qbx, nxcurlS("avg"))(queue, density=density) jtxyz = bind(qbx, sym.tangential_to_xyz(density_sym))( queue, density=density) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, qbx.density_discr, target_order+3) bdry_normals = bind(qbx, sym.normal(3))(queue)\ .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": sp_ext = bind(qbx, sym.Sp(knl, density_sym, qbx_forced_limit=+1))( queue, density=density) sp_avg = bind(qbx, sym.Sp(knl, density_sym, qbx_forced_limit="avg"))( queue, density=density) from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, qbx.density_discr, target_order+3) bdry_normals = bind(qbx, sym.normal(3))(queue)\ .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
def refine_for_global_qbx(lpot_source, wrangler, group_factory, kernel_length_scale=None, force_stage2_uniform_refinement_rounds=None, scaled_max_curvature_threshold=None, debug=None, maxiter=None, visualize=None, expansion_disturbance_tolerance=None, refiner=None): """ Entry point for calling the refiner. :arg lpot_source: An instance of :class:`QBXLayerPotentialSource`. :arg wrangler: An instance of :class:`RefinerWrangler`. :arg group_factory: An instance of :class:`meshmode.mesh.discretization.ElementGroupFactory`. Used for discretizing the coarse refined mesh. :arg kernel_length_scale: The kernel length scale, or *None* if not applicable. All panels are refined to below this size. :arg maxiter: The maximum number of refiner iterations. :returns: A tuple ``(lpot_source, *conn*)`` where ``lpot_source`` is the refined layer potential source, and ``conn`` is a :class:`meshmode.discretization.connection.DiscretizationConnection` going from the original mesh to the refined mesh. """ if maxiter is None: maxiter = 10 if debug is None: # FIXME: Set debug=False by default once everything works. debug = True if expansion_disturbance_tolerance is None: expansion_disturbance_tolerance = 0.025 if force_stage2_uniform_refinement_rounds is None: force_stage2_uniform_refinement_rounds = 0 # TODO: Stop doing redundant checks by avoiding panels which no longer need # refinement. from meshmode.mesh.refinement import RefinerWithoutAdjacency from meshmode.discretization.connection import ( ChainedDiscretizationConnection, make_same_mesh_connection) if refiner is not None: assert refiner.get_current_mesh() == lpot_source.density_discr.mesh else: # We may be handed a mesh that's already non-conforming, we don't rely # on adjacency, and the no-adjacency refiner is faster. refiner = RefinerWithoutAdjacency(lpot_source.density_discr.mesh) connections = [] # {{{ first stage refinement def visualize_refinement(niter, stage_nr, stage_name, flags): if not visualize: return if stage_nr == 1: discr = lpot_source.density_discr elif stage_nr == 2: discr = lpot_source.stage2_density_discr else: raise ValueError("unexpected stage number") flags = flags.get() logger.info("for stage %s: splitting %d/%d stage-%d elements", stage_name, np.sum(flags), discr.mesh.nelements, stage_nr) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(wrangler.queue, discr, 3) assert len(flags) == discr.mesh.nelements flags = flags.astype(np.bool) nodes_flags = np.zeros(discr.nnodes) for grp in discr.groups: meg = grp.mesh_el_group grp.view(nodes_flags)[ flags[meg.element_nr_base:meg.nelements+meg.element_nr_base]] = 1 nodes_flags = cl.array.to_device(wrangler.queue, nodes_flags) vis_data = [ ("refine_flags", nodes_flags), ] if 0: from pytential import sym, bind bdry_normals = bind(discr, sym.normal(discr.ambient_dim))( wrangler.queue).as_vector(dtype=object) vis_data.append(("bdry_normals", bdry_normals),) vis.write_vtk_file("refinement-%s-%03d.vtu" % (stage_name, niter), vis_data) def warn_max_iterations(): from warnings import warn warn( "QBX layer potential source refiner did not terminate " "after %d iterations (the maximum). " "You may pass 'visualize=True' to with_refinement() " "to see what area of the geometry is causing trouble. " "If the issue is disturbance of expansion disks, you may " "pass a slightly increased value (currently: %g) for " "_expansion_disturbance_tolerance in with_refinement(). " "As a last resort, " "you may use Python's warning filtering mechanism to " "not treat this warning as an error. " "The criteria triggering refinement in each iteration " "were: %s. " % ( len(violated_criteria), expansion_disturbance_tolerance, ", ".join( "%d: %s" % (i+1, vc_text) for i, vc_text in enumerate(violated_criteria))), RefinerNotConvergedWarning) violated_criteria = [] iter_violated_criteria = ["start"] niter = 0 while iter_violated_criteria: iter_violated_criteria = [] niter += 1 if niter > maxiter: warn_max_iterations() break refine_flags = make_empty_refine_flags(wrangler.queue, lpot_source) if kernel_length_scale is not None: with ProcessLogger(logger, "checking kernel length scale to panel size ratio"): violates_kernel_length_scale = \ wrangler.check_element_prop_threshold( element_property=( lpot_source._coarsest_quad_resolution( "npanels")), threshold=kernel_length_scale, refine_flags=refine_flags, debug=debug) if violates_kernel_length_scale: iter_violated_criteria.append("kernel length scale") visualize_refinement( niter, 1, "kernel-length-scale", refine_flags) if scaled_max_curvature_threshold is not None: with ProcessLogger(logger, "checking scaled max curvature threshold"): from pytential.qbx.utils import to_last_dim_length from pytential import sym, bind scaled_max_curv = to_last_dim_length( lpot_source.density_discr, bind(lpot_source, sym.ElementwiseMax( sym._scaled_max_curvature( lpot_source.density_discr.ambient_dim))) (wrangler.queue), "npanels") violates_scaled_max_curv = \ wrangler.check_element_prop_threshold( element_property=scaled_max_curv, threshold=scaled_max_curvature_threshold, refine_flags=refine_flags, debug=debug) if violates_scaled_max_curv: iter_violated_criteria.append("curvature") visualize_refinement(niter, 1, "curvature", refine_flags) if not iter_violated_criteria: # Only start building trees once the simple length-based criteria # are happy. # Build tree and auxiliary data. # FIXME: The tree should not have to be rebuilt at each iteration. tree = wrangler.build_tree(lpot_source) peer_lists = wrangler.find_peer_lists(tree) has_disturbed_expansions = \ wrangler.check_expansion_disks_undisturbed_by_sources( lpot_source, tree, peer_lists, expansion_disturbance_tolerance, refine_flags, debug) if has_disturbed_expansions: iter_violated_criteria.append("disturbed expansions") visualize_refinement(niter, 1, "disturbed-expansions", refine_flags) del tree del peer_lists if iter_violated_criteria: violated_criteria.append(" and ".join(iter_violated_criteria)) conn = wrangler.refine( lpot_source.density_discr, refiner, refine_flags, group_factory, debug) connections.append(conn) lpot_source = lpot_source.copy(density_discr=conn.to_discr) del refine_flags # }}} # {{{ second stage refinement iter_violated_criteria = ["start"] niter = 0 fine_connections = [] stage2_density_discr = lpot_source.density_discr while iter_violated_criteria: iter_violated_criteria = [] niter += 1 if niter > maxiter: warn_max_iterations() break # Build tree and auxiliary data. # FIXME: The tree should not have to be rebuilt at each iteration. tree = wrangler.build_tree(lpot_source, use_stage2_discr=True) peer_lists = wrangler.find_peer_lists(tree) refine_flags = make_empty_refine_flags( wrangler.queue, lpot_source, use_stage2_discr=True) has_insufficient_quad_res = \ wrangler.check_sufficient_source_quadrature_resolution( lpot_source, tree, peer_lists, refine_flags, debug) if has_insufficient_quad_res: iter_violated_criteria.append("insufficient quadrature resolution") visualize_refinement(niter, 2, "quad-resolution", refine_flags) if iter_violated_criteria: violated_criteria.append(" and ".join(iter_violated_criteria)) conn = wrangler.refine( stage2_density_discr, refiner, refine_flags, group_factory, debug) stage2_density_discr = conn.to_discr fine_connections.append(conn) lpot_source = lpot_source.copy( to_refined_connection=ChainedDiscretizationConnection( fine_connections)) del tree del refine_flags del peer_lists for round in range(force_stage2_uniform_refinement_rounds): conn = wrangler.refine( stage2_density_discr, refiner, np.ones(stage2_density_discr.mesh.nelements, dtype=np.bool), group_factory, debug) stage2_density_discr = conn.to_discr fine_connections.append(conn) lpot_source = lpot_source.copy( to_refined_connection=ChainedDiscretizationConnection( fine_connections)) # }}} lpot_source = lpot_source.copy(debug=debug, _refined_for_global_qbx=True) if len(connections) == 0: # FIXME: This is inefficient connection = make_same_mesh_connection( lpot_source.density_discr, lpot_source.density_discr) else: connection = ChainedDiscretizationConnection(connections) return lpot_source, connection
def run_int_eq_test(cl_ctx, queue, case, resolution, visualize): mesh = case.get_mesh(resolution, case.target_order) print("%d elements" % mesh.nelements) 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(case.target_order)) source_order = 4*case.target_order refiner_extra_kwargs = {} qbx_lpot_kwargs = {} if case.fmm_backend is None: qbx_lpot_kwargs["fmm_order"] = False else: if hasattr(case, "fmm_tol"): from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder qbx_lpot_kwargs["fmm_level_to_order"] = SimpleExpansionOrderFinder( case.fmm_tol) elif hasattr(case, "fmm_order"): qbx_lpot_kwargs["fmm_order"] = case.fmm_order else: qbx_lpot_kwargs["fmm_order"] = case.qbx_order + 5 qbx = QBXLayerPotentialSource( pre_density_discr, fine_order=source_order, qbx_order=case.qbx_order, _box_extent_norm=getattr(case, "box_extent_norm", None), _from_sep_smaller_crit=getattr(case, "from_sep_smaller_crit", None), _from_sep_smaller_min_nsources_cumul=30, fmm_backend=case.fmm_backend, **qbx_lpot_kwargs) if case.use_refinement: if case.k != 0 and getattr(case, "refine_on_helmholtz_k", True): refiner_extra_kwargs["kernel_length_scale"] = 5/case.k if hasattr(case, "scaled_max_curvature_threshold"): refiner_extra_kwargs["_scaled_max_curvature_threshold"] = \ case.scaled_max_curvature_threshold if hasattr(case, "expansion_disturbance_tolerance"): refiner_extra_kwargs["_expansion_disturbance_tolerance"] = \ case.expansion_disturbance_tolerance if hasattr(case, "refinement_maxiter"): refiner_extra_kwargs["maxiter"] = case.refinement_maxiter #refiner_extra_kwargs["visualize"] = True print("%d elements before refinement" % pre_density_discr.mesh.nelements) qbx, _ = qbx.with_refinement(**refiner_extra_kwargs) print("%d stage-1 elements after refinement" % qbx.density_discr.mesh.nelements) print("%d stage-2 elements after refinement" % qbx.stage2_density_discr.mesh.nelements) print("quad stage-2 elements have %d nodes" % qbx.quad_stage2_density_discr.groups[0].nunit_nodes) density_discr = qbx.density_discr if hasattr(case, "visualize_geometry") and case.visualize_geometry: bdry_normals = bind( density_discr, sym.normal(mesh.ambient_dim) )(queue).as_vector(dtype=object) bdry_vis = make_visualizer(queue, density_discr, case.target_order) bdry_vis.write_vtk_file("geometry.vtu", [ ("normals", bdry_normals) ]) # {{{ plot geometry if 0: if mesh.ambient_dim == 2: # show geometry, centers, normals nodes_h = density_discr.nodes().get(queue=queue) pt.plot(nodes_h[0], nodes_h[1], "x-") normal = bind(density_discr, sym.normal(2))(queue).as_vector(np.object) pt.quiver(nodes_h[0], nodes_h[1], normal[0].get(queue), normal[1].get(queue)) pt.gca().set_aspect("equal") pt.show() elif mesh.ambient_dim == 3: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_normals = bind(density_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("pre-solve-source-%s.vtu" % resolution, [ ("bdry_normals", bdry_normals), ]) else: raise ValueError("invalid mesh dim") # }}} # {{{ set up operator from pytential.symbolic.pde.scalar import ( DirichletOperator, NeumannOperator) from sumpy.kernel import LaplaceKernel, HelmholtzKernel if case.k: knl = HelmholtzKernel(mesh.ambient_dim) knl_kwargs = {"k": sym.var("k")} concrete_knl_kwargs = {"k": case.k} else: knl = LaplaceKernel(mesh.ambient_dim) knl_kwargs = {} concrete_knl_kwargs = {} if knl.is_complex_valued: dtype = np.complex128 else: dtype = np.float64 loc_sign = +1 if case.prob_side in [+1, "scat"] else -1 if case.bc_type == "dirichlet": op = DirichletOperator(knl, loc_sign, use_l2_weighting=True, kernel_arguments=knl_kwargs) elif case.bc_type == "neumann": op = NeumannOperator(knl, loc_sign, use_l2_weighting=True, use_improved_operator=False, kernel_arguments=knl_kwargs) else: assert False op_u = op.operator(sym.var("u")) # }}} # {{{ set up test data if case.prob_side == -1: test_src_geo_radius = case.outer_radius test_tgt_geo_radius = case.inner_radius elif case.prob_side == +1: test_src_geo_radius = case.inner_radius test_tgt_geo_radius = case.outer_radius elif case.prob_side == "scat": test_src_geo_radius = case.outer_radius test_tgt_geo_radius = case.outer_radius else: raise ValueError("unknown problem_side") point_sources = make_circular_point_group( mesh.ambient_dim, 10, test_src_geo_radius, func=lambda x: x**1.5) test_targets = make_circular_point_group( mesh.ambient_dim, 20, test_tgt_geo_radius) np.random.seed(22) source_charges = np.random.randn(point_sources.shape[1]) source_charges[-1] = -np.sum(source_charges[:-1]) source_charges = source_charges.astype(dtype) assert np.sum(source_charges) < 1e-15 source_charges_dev = cl.array.to_device(queue, source_charges) # }}} # {{{ establish BCs from pytential.source import PointPotentialSource from pytential.target import PointsTarget point_source = PointPotentialSource(cl_ctx, point_sources) pot_src = sym.IntG( # FIXME: qbx_forced_limit--really? knl, sym.var("charges"), qbx_forced_limit=None, **knl_kwargs) test_direct = bind((point_source, PointsTarget(test_targets)), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs) if case.bc_type == "dirichlet": bc = bind((point_source, density_discr), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs) elif case.bc_type == "neumann": bc = bind( (point_source, density_discr), sym.normal_derivative( qbx.ambient_dim, pot_src, where=sym.DEFAULT_TARGET) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) # }}} # {{{ solve bound_op = bind(qbx, op_u) rhs = bind(density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bc) try: from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "u", dtype, **concrete_knl_kwargs), rhs, tol=case.gmres_tol, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) except QBXTargetAssociationFailedException as e: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_vis.write_vtk_file("failed-targets-%s.vtu" % resolution, [ ("failed_targets", e.failed_target_flags), ]) raise print("gmres state:", gmres_result.state) weighted_u = gmres_result.solution # }}} # {{{ build matrix for spectrum check if 0: from sumpy.tools import build_matrix mat = build_matrix( bound_op.scipy_op( queue, arg_name="u", dtype=dtype, k=case.k)) w, v = la.eig(mat) if 0: pt.imshow(np.log10(1e-20+np.abs(mat))) pt.colorbar() pt.show() #assert abs(s[-1]) < 1e-13, "h #assert abs(s[-2]) > 1e-7 #from pudb import set_trace; set_trace() # }}} if case.prob_side != "scat": # {{{ error check points_target = PointsTarget(test_targets) bound_tgt_op = bind((qbx, points_target), op.representation(sym.var("u"))) test_via_bdry = bound_tgt_op(queue, u=weighted_u, k=case.k) err = test_via_bdry - test_direct err = err.get() test_direct = test_direct.get() test_via_bdry = test_via_bdry.get() # {{{ remove effect of net source charge if case.k == 0 and case.bc_type == "neumann" and loc_sign == -1: # remove constant offset in interior Laplace Neumann error tgt_ones = np.ones_like(test_direct) tgt_ones = tgt_ones/la.norm(tgt_ones) err = err - np.vdot(tgt_ones, err)*tgt_ones # }}} rel_err_2 = la.norm(err)/la.norm(test_direct) rel_err_inf = la.norm(err, np.inf)/la.norm(test_direct, np.inf) # }}} print("rel_err_2: %g rel_err_inf: %g" % (rel_err_2, rel_err_inf)) else: rel_err_2 = None rel_err_inf = None # {{{ test gradient if case.check_gradient and case.prob_side != "scat": bound_grad_op = bind((qbx, points_target), op.representation( sym.var("u"), map_potentials=lambda pot: sym.grad(mesh.ambient_dim, pot), qbx_forced_limit=None)) #print(bound_t_deriv_op.code) grad_from_src = bound_grad_op( queue, u=weighted_u, **concrete_knl_kwargs) grad_ref = (bind( (point_source, points_target), sym.grad(mesh.ambient_dim, pot_src) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) ) grad_err = (grad_from_src - grad_ref) rel_grad_err_inf = ( la.norm(grad_err[0].get(), np.inf) / la.norm(grad_ref[0].get(), np.inf)) print("rel_grad_err_inf: %g" % rel_grad_err_inf) # }}} # {{{ test tangential derivative if case.check_tangential_deriv and case.prob_side != "scat": bound_t_deriv_op = bind(qbx, op.representation( sym.var("u"), map_potentials=lambda pot: sym.tangential_derivative(2, pot), qbx_forced_limit=loc_sign)) #print(bound_t_deriv_op.code) tang_deriv_from_src = bound_t_deriv_op( queue, u=weighted_u, **concrete_knl_kwargs).as_scalar().get() tang_deriv_ref = (bind( (point_source, density_discr), sym.tangential_derivative(2, pot_src) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) .as_scalar().get()) if 0: pt.plot(tang_deriv_ref.real) pt.plot(tang_deriv_from_src.real) pt.show() td_err = (tang_deriv_from_src - tang_deriv_ref) rel_td_err_inf = la.norm(td_err, np.inf)/la.norm(tang_deriv_ref, np.inf) print("rel_td_err_inf: %g" % rel_td_err_inf) else: rel_td_err_inf = None # }}} # {{{ any-D file plotting if visualize: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_normals = bind(density_discr, sym.normal(qbx.ambient_dim))(queue)\ .as_vector(dtype=object) sym_sqrt_j = sym.sqrt_jac_q_weight(density_discr.ambient_dim) u = bind(density_discr, sym.var("u")/sym_sqrt_j)(queue, u=weighted_u) bdry_vis.write_vtk_file("source-%s.vtu" % resolution, [ ("u", u), ("bc", bc), #("bdry_normals", bdry_normals), ]) from sumpy.visualization import make_field_plotter_from_bbox # noqa from meshmode.mesh.processing import find_bounding_box vis_grid_spacing = (0.1, 0.1, 0.1)[:qbx.ambient_dim] if hasattr(case, "vis_grid_spacing"): vis_grid_spacing = case.vis_grid_spacing vis_extend_factor = 0.2 if hasattr(case, "vis_extend_factor"): vis_grid_spacing = case.vis_grid_spacing fplot = make_field_plotter_from_bbox( find_bounding_box(mesh), h=vis_grid_spacing, extend_factor=vis_extend_factor) qbx_tgt_tol = qbx.copy(target_association_tolerance=0.15) from pytential.target import PointsTarget try: solved_pot = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), 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), ] ) else: fplot.write_vtk_file( "potential-%s.vts" % resolution, [ ("solved_pot", solved_pot), ("true_pot", true_pot), ("indicator", indicator), ] ) # }}} class Result(Record): pass return Result( h_max=qbx.h_max, rel_err_2=rel_err_2, rel_err_inf=rel_err_inf, rel_td_err_inf=rel_td_err_inf, gmres_result=gmres_result)
def test_off_surface_eval(ctx_getter, use_fmm, do_plot=False): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_getter() 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 main(): logging.basicConfig(level=logging.INFO) nelements = 60 qbx_order = 3 k_fac = 4 k0 = 3*k_fac k1 = 2.9*k_fac mesh_order = 10 bdry_quad_order = mesh_order bdry_ovsmp_quad_order = bdry_quad_order * 4 fmm_order = qbx_order * 2 cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh( partial(ellipse, 3), np.linspace(0, 1, nelements+1), mesh_order) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) logger.info("%d elements" % mesh.nelements) # from meshmode.discretization.visualization import make_visualizer # bdry_vis = make_visualizer(queue, density_discr, 20) # {{{ solve bvp from sumpy.kernel import HelmholtzKernel kernel = HelmholtzKernel(2) beta = 2.5*k_fac K0 = np.sqrt(k0**2-beta**2) K1 = np.sqrt(k1**2-beta**2) from pytential.symbolic.pde.scalar import DielectricSDRep2DBoundaryOperator pde_op = DielectricSDRep2DBoundaryOperator( mode='tm', k_vacuum=1, interfaces=((0, 1, sym.DEFAULT_SOURCE),), domain_k_exprs=(k0, k1), beta=beta) op_unknown_sym = pde_op.make_unknown("unknown") representation0_sym = pde_op.representation(op_unknown_sym, 0) representation1_sym = pde_op.representation(op_unknown_sym, 1) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ) bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym)) # in inner domain sources_1 = make_obj_array(list(np.array([ [-1.5, 0.5] ]).T.copy())) strengths_1 = np.array([1]) from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False) _, (Einc,) = pot_p2p(queue, density_discr.nodes(), sources_1, [strengths_1], out_host=False, k=K0) sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue) bvp_rhs = np.zeros(len(pde_op.bcs), dtype=np.object) for i_bc, terms in enumerate(pde_op.bcs): for term in terms: assert term.i_interface == 0 assert term.field_kind == pde_op.field_kind_e if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += ( term.coeff_outer * (-Einc) ) elif term.direction == pde_op.dir_normal: # no jump in normal derivative bvp_rhs[i_bc] += 0*Einc else: raise NotImplementedError("direction spec in RHS") bvp_rhs[i_bc] *= sqrt_w from pytential.solve import gmres gmres_result = gmres( bound_pde_op.scipy_op(queue, "unknown", dtype=np.complex128, domains=[sym.DEFAULT_TARGET]*2, K0=K0, K1=K1), bvp_rhs, tol=1e-6, progress=True, hard_failure=True, stall_iterations=0) # }}} unknown = gmres_result.solution # {{{ visualize from pytential.qbx import QBXLayerPotentialSource lap_qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=qbx_order ) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300) from pytential.target import PointsTarget fld0 = bind( (qbx, PointsTarget(fplot.points)), representation0_sym)(queue, unknown=unknown, K0=K0).get() fld1 = bind( (qbx, PointsTarget(fplot.points)), representation1_sym)(queue, unknown=unknown, K1=K1).get() ones = cl.array.empty(queue, density_discr.nnodes, np.float64) dom1_indicator = -bind( (lap_qbx, PointsTarget(fplot.points)), sym.D(0, sym.var("sigma")))( queue, sigma=ones.fill(1)).get() _, (fld_inc_vol,) = pot_p2p(queue, fplot.points, sources_1, [strengths_1], out_host=True, k=K0) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("fld0", fld0), ("fld1", fld1), ("fld_inc_vol", fld_inc_vol), ("fld_total", ( (fld_inc_vol + fld0)*(1-dom1_indicator) + fld1*dom1_indicator )), ("dom1_indicator", dom1_indicator), ] )
def test_sanity_balls(ctx_getter, src_file, dim, mesh_order, visualize=False): pytest.importorskip("pytential") logging.basicConfig(level=logging.INFO) ctx = ctx_getter() queue = cl.CommandQueue(ctx) from pytools.convergence import EOCRecorder vol_eoc_rec = EOCRecorder() surf_eoc_rec = EOCRecorder() # overkill quad_order = mesh_order from pytential import bind, sym for h in [0.2, 0.14, 0.1]: from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource(src_file), dim, order=mesh_order, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h], force_ambient_dim=dim) logger.info("%d elements" % mesh.nelements) # {{{ discretizations and connections from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory vol_discr = Discretization(ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(quad_order)) from meshmode.discretization.connection import make_boundary_restriction bdry_mesh, bdry_discr, bdry_connection = make_boundary_restriction( queue, vol_discr, InterpolatoryQuadratureSimplexGroupFactory(quad_order)) # }}} # {{{ visualizers from meshmode.discretization.visualization import make_visualizer vol_vis = make_visualizer(queue, vol_discr, 20) bdry_vis = make_visualizer(queue, bdry_discr, 20) # }}} from math import gamma true_surf = 2*np.pi**(dim/2)/gamma(dim/2) true_vol = true_surf/dim vol_x = vol_discr.nodes().with_queue(queue) vol_one = vol_x[0].copy() vol_one.fill(1) from pytential import norm, integral # noqa comp_vol = integral(vol_discr, queue, vol_one) rel_vol_err = abs(true_vol - comp_vol) / true_vol vol_eoc_rec.add_data_point(h, rel_vol_err) print("VOL", true_vol, comp_vol) bdry_x = bdry_discr.nodes().with_queue(queue) bdry_one_exact = bdry_x[0].copy() bdry_one_exact.fill(1) bdry_one = bdry_connection(queue, vol_one).with_queue(queue) intp_err = norm(bdry_discr, queue, bdry_one-bdry_one_exact) assert intp_err < 1e-14 comp_surf = integral(bdry_discr, queue, bdry_one) rel_surf_err = abs(true_surf - comp_surf) / true_surf surf_eoc_rec.add_data_point(h, rel_surf_err) print("SURF", true_surf, comp_surf) if visualize: vol_vis.write_vtk_file("volume-h=%g.vtu" % h, [ ("f", vol_one), ("area_el", bind(vol_discr, sym.area_element())(queue)), ]) bdry_vis.write_vtk_file("boundary-h=%g.vtu" % h, [("f", bdry_one)]) # {{{ check normals point outward normal_outward_check = bind(bdry_discr, sym.normal() | sym.Nodes(), )(queue).as_scalar() > 0 assert normal_outward_check.get().all(), normal_outward_check.get() # }}} print("---------------------------------") print("VOLUME") print("---------------------------------") print(vol_eoc_rec) assert vol_eoc_rec.order_estimate() >= mesh_order print("---------------------------------") print("SURFACE") print("---------------------------------") print(surf_eoc_rec) assert surf_eoc_rec.order_estimate() >= mesh_order