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_interpolation(ctx_factory, name, source_discr_stage, target_granularity): ctx = ctx_factory() queue = cl.CommandQueue(ctx) nelements = 32 target_order = 7 qbx_order = 4 mesh = make_curve_mesh(starfish, np.linspace(0.0, 1.0, nelements + 1), target_order) discr = Discretization( ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx, _ = QBXLayerPotentialSource(discr, fine_order=4 * target_order, qbx_order=qbx_order, fmm_order=False).with_refinement() where = 'test-interpolation' from_dd = sym.DOFDescriptor(geometry=where, discr_stage=source_discr_stage, granularity=sym.GRANULARITY_NODE) to_dd = sym.DOFDescriptor(geometry=where, discr_stage=sym.QBX_SOURCE_QUAD_STAGE2, granularity=target_granularity) sigma_sym = sym.var("sigma") op_sym = sym.sin(sym.interp(from_dd, to_dd, sigma_sym)) bound_op = bind(qbx, op_sym, auto_where=where) target_nodes = qbx.quad_stage2_density_discr.nodes().get(queue) if source_discr_stage == sym.QBX_SOURCE_STAGE2: source_nodes = qbx.stage2_density_discr.nodes().get(queue) elif source_discr_stage == sym.QBX_SOURCE_QUAD_STAGE2: source_nodes = target_nodes else: source_nodes = qbx.density_discr.nodes().get(queue) sigma_dev = cl.array.to_device(queue, la.norm(source_nodes, axis=0)) sigma_target = np.sin(la.norm(target_nodes, axis=0)) sigma_target_interp = bound_op(queue, sigma=sigma_dev).get(queue) 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('unknown test case name: {}'.format(name))
def _get_qbx_discretization(self, geometry, discr_stage): lpot_source = self.get_geometry(geometry) try: discr = self._get_discr_from_cache(geometry, discr_stage) except KeyError: from pytential.qbx.refinement import _refine_for_global_qbx # NOTE: this adds the required discretizations to the cache dofdesc = sym.DOFDescriptor(geometry, discr_stage) _refine_for_global_qbx( self, dofdesc, lpot_source.refiner_code_container.get_wrangler(), _copy_collection=False) discr = self._get_discr_from_cache(geometry, discr_stage) return discr
def _operator(self, sigma, normal, mu, qbx_forced_limit): slp_qbx_forced_limit = qbx_forced_limit if slp_qbx_forced_limit == "avg": slp_qbx_forced_limit = +1 # NOTE: we set a dofdesc here to force the evaluation of this integral # on the source instead of the target when using automatic tagging # see :meth:`pytential.symbolic.mappers.LocationTagger._default_dofdesc` dd = sym.DOFDescriptor(None, discr_stage=sym.QBX_SOURCE_STAGE1) int_sigma = sym.integral(self.ambient_dim, self.dim, sigma, dofdesc=dd) meanless_sigma = sym.cse(sigma - sym.mean(self.ambient_dim, self.dim, sigma)) op_k = self.stresslet.apply(sigma, normal, mu, qbx_forced_limit=qbx_forced_limit) op_s = ( self.alpha / (2.0 * np.pi) * int_sigma - self.stokeslet.apply(meanless_sigma, mu, qbx_forced_limit=slp_qbx_forced_limit) ) return op_k + self.eta * op_s
def test_geometry_collection_caching(ctx_factory): # NOTE: checks that the on-demand caching works properly in # the `GeometryCollection`. This is done by constructing a few separated # spheres, putting a few `QBXLayerPotentialSource`s on them and requesting # the `nodes` on each `discr_stage`. ctx = ctx_factory() queue = cl.CommandQueue(ctx) actx = PyOpenCLArrayContext(queue) ndim = 2 nelements = 1024 target_order = 7 qbx_order = 4 ngeometry = 3 # construct discretizations from meshmode.mesh.generation import ellipse, make_curve_mesh from meshmode.mesh.processing import affine_map from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory discrs = [] radius = 1.0 for k in range(ngeometry): if k == 0: mesh = make_curve_mesh(partial(ellipse, radius), np.linspace(0.0, 1.0, nelements + 1), target_order) else: mesh = affine_map(discrs[0].mesh, b=np.array([3 * k * radius, 0])) discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) discrs.append(discr) # construct qbx source from pytential.qbx import QBXLayerPotentialSource lpots = [] sources = [f"source_{k}" for k in range(ngeometry)] for k, density_discr in enumerate(discrs): qbx = QBXLayerPotentialSource(density_discr, fine_order=2 * target_order, qbx_order=qbx_order, fmm_order=False) lpots.append(qbx) # construct a geometry collection from pytential import GeometryCollection places = GeometryCollection(dict(zip(sources, lpots))) print(places.places) # check on-demand refinement from pytential import bind, sym discr_stages = [ sym.QBX_SOURCE_STAGE1, sym.QBX_SOURCE_STAGE2, sym.QBX_SOURCE_QUAD_STAGE2 ] for k in range(ngeometry): for discr_stage in discr_stages: with pytest.raises(KeyError): discr = places._get_discr_from_cache(sources[k], discr_stage) dofdesc = sym.DOFDescriptor(sources[k], discr_stage=discr_stage) bind(places, sym.nodes(ndim, dofdesc=dofdesc))(actx) discr = places._get_discr_from_cache(sources[k], discr_stage) assert discr is not None
def test_build_matrix_places(ctx_factory, source_discr_stage, target_discr_stage, visualize=False): ctx = ctx_factory() queue = cl.CommandQueue(ctx) # prevent cache explosion from sympy.core.cache import clear_cache clear_cache() qbx_forced_limit = -1 place_ids = ( sym.DOFDescriptor( geometry=sym.DEFAULT_SOURCE, discr_stage=source_discr_stage), sym.DOFDescriptor( geometry=sym.DEFAULT_TARGET, discr_stage=target_discr_stage), ) # build test operators qbx = _build_qbx_discr(queue, nelements=8, target_order=2, ndim=2, curve_f=partial(ellipse, 1.0)) op, u_sym, _ = _build_op(lpot_id=1, ndim=2, source=place_ids[0], target=place_ids[1], qbx_forced_limit=qbx_forced_limit) from pytential.symbolic.execution import GeometryCollection places = GeometryCollection(qbx, auto_where=place_ids) source_discr = places.get_discretization(place_ids[0]) target_discr = places.get_discretization(place_ids[1]) index_set = _build_block_index(source_discr, factor=0.6) from pytential.symbolic.execution import _prepare_expr op = _prepare_expr(places, op) # build full QBX matrix from pytential.symbolic.matrix import MatrixBuilder mbuilder = MatrixBuilder(queue, dep_expr=u_sym, other_dep_exprs=[], dep_source=places.get_geometry(place_ids[0]), dep_discr=places.get_discretization(place_ids[0]), places=places, context={}) qbx_mat = mbuilder(op) # build full p2p matrix from pytential.symbolic.matrix import P2PMatrixBuilder mbuilder = P2PMatrixBuilder(queue, dep_expr=u_sym, other_dep_exprs=[], dep_source=places.get_geometry(place_ids[0]), dep_discr=places.get_discretization(place_ids[0]), places=places, context={}) p2p_mat = mbuilder(op) assert p2p_mat.shape == (target_discr.nnodes, source_discr.nnodes) # build block qbx and p2p matrices from pytential.symbolic.matrix import NearFieldBlockBuilder mbuilder = NearFieldBlockBuilder(queue, dep_expr=u_sym, other_dep_exprs=[], dep_source=places.get_geometry(place_ids[0]), dep_discr=places.get_discretization(place_ids[0]), places=places, index_set=index_set, context={}) mat = mbuilder(op) if place_ids[0].discr_stage is not None: assert _max_block_error(qbx_mat, mat, index_set.get(queue)) < 1.0e-14 from pytential.symbolic.matrix import FarFieldBlockBuilder mbuilder = FarFieldBlockBuilder(queue, dep_expr=u_sym, other_dep_exprs=[], dep_source=places.get_geometry(place_ids[0]), dep_discr=places.get_discretization(place_ids[0]), places=places, index_set=index_set, context={}, exclude_self=True) mat = mbuilder(op) assert _max_block_error(p2p_mat, mat, index_set.get(queue)) < 1.0e-14
def test_qbx_block_builder(ctx_factory, factor, ndim, lpot_id, visualize=False): ctx = ctx_factory() queue = cl.CommandQueue(ctx) # prevent cache explosion from sympy.core.cache import clear_cache clear_cache() place_ids = ( sym.DOFDescriptor( geometry=sym.DEFAULT_SOURCE, discr_stage=sym.QBX_SOURCE_STAGE2), sym.DOFDescriptor( geometry=sym.DEFAULT_TARGET, discr_stage=sym.QBX_SOURCE_STAGE2), ) target_order = 2 if ndim == 3 else 7 qbx = _build_qbx_discr(queue, target_order=target_order, ndim=ndim) op, u_sym, _ = _build_op(lpot_id, ndim=ndim, source=place_ids[0], target=place_ids[1], qbx_forced_limit="avg") from pytential.symbolic.execution import GeometryCollection, _prepare_expr places = GeometryCollection(qbx, auto_where=place_ids) expr = _prepare_expr(places, op) density_discr = places.get_discretization(place_ids[0]) index_set = _build_block_index(density_discr, factor=factor) from pytential.symbolic.matrix import NearFieldBlockBuilder mbuilder = NearFieldBlockBuilder(queue, dep_expr=u_sym, other_dep_exprs=[], dep_source=places.get_geometry(place_ids[0]), dep_discr=places.get_discretization(place_ids[0]), places=places, index_set=index_set, context={}) blk = mbuilder(expr) from pytential.symbolic.matrix import MatrixBuilder mbuilder = MatrixBuilder(queue, dep_expr=u_sym, other_dep_exprs=[], dep_source=places.get_geometry(place_ids[0]), dep_discr=places.get_discretization(place_ids[0]), places=places, context={}) mat = mbuilder(expr) index_set = index_set.get(queue) if visualize: blk_full = np.zeros_like(mat) mat_full = np.zeros_like(mat) for i in range(index_set.nblocks): itgt, isrc = index_set.block_indices(i) blk_full[np.ix_(itgt, isrc)] = index_set.block_take(blk, i) mat_full[np.ix_(itgt, isrc)] = index_set.take(mat, i) import matplotlib.pyplot as mp _, (ax1, ax2) = mp.subplots(1, 2, figsize=(10, 8), constrained_layout=True) ax1.imshow(mat_full) ax1.set_title('MatrixBuilder') ax2.imshow(blk_full) ax2.set_title('NearFieldBlockBuilder') mp.savefig("test_qbx_block_builder.png", dpi=300) assert _max_block_error(mat, blk, index_set) < 1.0e-14