def build_matrix(actx, places, exprs, input_exprs, domains=None, auto_where=None, context=None): """ :arg actx: a :class:`~meshmode.array_context.ArrayContext`. :arg places: a :class:`~pytential.symbolic.execution.GeometryCollection`. Alternatively, any list or mapping that is a valid argument for its constructor can also be used. :arg exprs: an array of expressions corresponding to the output block rows of the matrix. May also be a single expression. :arg input_exprs: an array of expressions corresponding to the input block columns of the matrix. May also be a single expression. :arg domains: a list of discretization identifiers (see 'places') or *None* values indicating the domains on which each component of the solution vector lives. *None* values indicate that the component is a scalar. If *None*, *auto_where* or, if it is not provided, :class:`~pytential.symbolic.primitives.DEFAULT_SOURCE` is required to be a key in :attr:`places`. :arg auto_where: For simple source-to-self or source-to-target evaluations, find 'where' attributes automatically. """ if context is None: context = {} from pytential import GeometryCollection if not isinstance(places, GeometryCollection): places = GeometryCollection(places, auto_where=auto_where) exprs = _prepare_expr(places, exprs, auto_where=auto_where) if not (isinstance(exprs, np.ndarray) and exprs.dtype.char == "O"): from pytools.obj_array import make_obj_array exprs = make_obj_array([exprs]) try: input_exprs = list(input_exprs) except TypeError: # not iterable, wrap in a list input_exprs = [input_exprs] domains = _prepare_domains(len(input_exprs), places, domains, places.auto_source) from pytential.symbolic.matrix import MatrixBuilder, is_zero nblock_rows = len(exprs) nblock_columns = len(input_exprs) blocks = np.zeros((nblock_rows, nblock_columns), dtype=np.object) dtypes = [] for ibcol in range(nblock_columns): dep_source = places.get_geometry(domains[ibcol].geometry) dep_discr = places.get_discretization(domains[ibcol].geometry, domains[ibcol].discr_stage) mbuilder = MatrixBuilder(actx, dep_expr=input_exprs[ibcol], other_dep_exprs=(input_exprs[:ibcol] + input_exprs[ibcol + 1:]), dep_source=dep_source, dep_discr=dep_discr, places=places, context=context) for ibrow in range(nblock_rows): block = mbuilder(exprs[ibrow]) assert is_zero(block) or isinstance(block, np.ndarray) blocks[ibrow, ibcol] = block if isinstance(block, np.ndarray): dtypes.append(block.dtype) return actx.from_numpy(_bmat(blocks, dtypes))
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
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
places=places, context=case.knl_concrete_kwargs) if block_builder_type == "qbx": from pytential.symbolic.matrix import MatrixBuilder from pytential.symbolic.matrix import \ NearFieldBlockBuilder as BlockMatrixBuilder elif block_builder_type == "p2p": from pytential.symbolic.matrix import P2PMatrixBuilder as MatrixBuilder from pytential.symbolic.matrix import \ FarFieldBlockBuilder as BlockMatrixBuilder kwargs["exclude_self"] = True else: raise ValueError(f"unknown block builder type: '{block_builder_type}'") mat = MatrixBuilder(actx, **kwargs)(sym_prep_op) blk = BlockMatrixBuilder(actx, index_set=index_set, **kwargs)(sym_prep_op) # }}} # {{{ check if visualize and ambient_dim == 2: try: import matplotlib.pyplot as pt except ImportError: visualize = False index_set = index_set.get(actx.queue) if visualize and ambient_dim == 2: blk_full = np.zeros_like(mat)