def connection_from_dds(places, from_dd, to_dd): """ :arg places: a :class:`~pytential.symbolic.execution.GeometryCollection` or an argument taken by its constructor. :arg from_dd: a descriptor for the incoming degrees of freedom. This can be a :class:`~pytential.symbolic.primitives.DOFDescriptor` or an identifier that can be transformed into one by :func:`~pytential.symbolic.primitives.as_dofdesc`. :arg to_dd: a descriptor for the outgoing degrees of freedom. :return: a :class:`DOFConnection` transporting between the two kinds of DOF vectors. """ from pytential import sym from_dd = sym.as_dofdesc(from_dd) to_dd = sym.as_dofdesc(to_dd) from pytential import GeometryCollection if not isinstance(places, GeometryCollection): places = GeometryCollection(places) lpot = places.get_geometry(from_dd.geometry) from_discr = places.get_discretization(from_dd.geometry, from_dd.discr_stage) to_discr = places.get_discretization(to_dd.geometry, to_dd.discr_stage) if from_dd.geometry != to_dd.geometry: raise ValueError("cannot interpolate between different geometries") if from_dd.granularity is not sym.GRANULARITY_NODE: raise ValueError("can only interpolate from `GRANULARITY_NODE`") connections = [] if from_dd.discr_stage is not to_dd.discr_stage: from pytential.qbx import QBXLayerPotentialSource if not isinstance(lpot, QBXLayerPotentialSource): raise ValueError("can only interpolate on a " "`QBXLayerPotentialSource`") if to_dd.discr_stage is not sym.QBX_SOURCE_QUAD_STAGE2: # TODO: can probably extend this to project from a QUAD_STAGE2 # using L2ProjectionInverseDiscretizationConnection raise ValueError("can only interpolate to " "`QBX_SOURCE_QUAD_STAGE2`") # FIXME: would be nice if these were ordered by themselves stage_name_to_index_map = { None: 0, sym.QBX_SOURCE_STAGE1: 1, sym.QBX_SOURCE_STAGE2: 2, sym.QBX_SOURCE_QUAD_STAGE2: 3 } stage_index_to_name_map = { i: name for name, i in stage_name_to_index_map.items() } from_stage = stage_name_to_index_map[from_dd.discr_stage] to_stage = stage_name_to_index_map[to_dd.discr_stage] for istage in range(from_stage, to_stage): conn = places._get_conn_from_cache( from_dd.geometry, stage_index_to_name_map[istage], stage_index_to_name_map[istage + 1]) connections.append(conn) if from_dd.granularity is not to_dd.granularity: if to_dd.granularity is sym.GRANULARITY_NODE: pass elif to_dd.granularity is sym.GRANULARITY_CENTER: connections.append(CenterGranularityConnection(to_discr)) elif to_dd.granularity is sym.GRANULARITY_ELEMENT: raise ValueError("Creating a connection to element granularity " "is not allowed. Use Elementwise{Max,Min,Sum}.") else: raise ValueError(f"invalid to_dd granularity: {to_dd.granularity}") if from_dd.granularity is not to_dd.granularity: conn = DOFConnection(connections, from_dd=from_dd, to_dd=to_dd) else: from meshmode.discretization.connection import \ ChainedDiscretizationConnection conn = ChainedDiscretizationConnection(connections, from_discr=from_discr) return conn
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))
# {{{ symbolic sym_u, sym_op = case.get_operator(ambient_dim) from pytential.symbolic.execution import _prepare_expr sym_prep_op = _prepare_expr(places, sym_op) # }}} # {{{ matrix index_set = case.get_block_indices(actx, density_discr) kwargs = dict(dep_expr=sym_u, other_dep_exprs=[], dep_source=places.get_geometry(dd.geometry), dep_discr=density_discr, 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}'")