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 exec_compute_potential_insn_direct(self, actx: PyOpenCLArrayContext, insn, bound_expr, evaluate): kernel_args = {} for arg_name, arg_expr in insn.kernel_arguments.items(): kernel_args[arg_name] = flatten(evaluate(arg_expr), actx, leaf_class=DOFArray) from pytential import bind, sym waa = bind( bound_expr.places, sym.weights_and_area_elements(self.ambient_dim, dofdesc=insn.source))(actx) strengths = [waa * evaluate(density) for density in insn.densities] flat_strengths = [flatten(strength, actx) for strength in strengths] results = [] p2p = None for o in insn.outputs: target_discr = bound_expr.places.get_discretization( o.target_name.geometry, o.target_name.discr_stage) if p2p is None: p2p = self.get_p2p(actx, source_kernels=insn.source_kernels, target_kernels=insn.target_kernels) evt, output_for_each_kernel = p2p( actx.queue, targets=flatten(target_discr.nodes(), actx, leaf_class=DOFArray), sources=flatten(self.density_discr.nodes(), actx, leaf_class=DOFArray), strength=flat_strengths, **kernel_args) from meshmode.discretization import Discretization result = output_for_each_kernel[o.target_kernel_index] if isinstance(target_discr, Discretization): template_ary = thaw(target_discr.nodes()[0], actx) result = unflatten(template_ary, result, actx, strict=False) results.append((o.name, result)) timing_data = {} return results, timing_data
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 check_element_prop_threshold(self, element_property, threshold, refine_flags, debug, wait_for=None): actx = self.array_context knl = self.code_container.element_prop_threshold_checker() if debug: nelements_to_refine_prev = actx.to_numpy( actx.np.sum(refine_flags)).item() element_property = flatten(element_property, self.array_context) evt, out = knl(actx.queue, element_property=element_property, refine_flags=refine_flags, refine_flags_updated=np.array(0), threshold=np.array(threshold), wait_for=wait_for) import pyopencl as cl cl.wait_for_events([evt]) if debug: nelements_to_refine = actx.to_numpy( actx.np.sum(refine_flags)).item() if nelements_to_refine > nelements_to_refine_prev: logger.debug("refiner: found %d element(s) to refine", nelements_to_refine - nelements_to_refine_prev) return out["refine_flags_updated"] == 1
def target_info(self): """Return a :class:`TargetInfo`. |cached|""" actx = self._setup_actx code_getter = self.code_getter ntargets = self.ncenters target_discr_starts = [] for target_discr, _qbx_side in self.target_discrs_and_qbx_sides: target_discr_starts.append(ntargets) ntargets += target_discr.ndofs target_discr_starts.append(ntargets) targets = actx.empty((self.ambient_dim, ntargets), self.coord_dtype) code_getter.copy_targets_kernel()(actx.queue, targets=targets[:, :self.ncenters], points=self.flat_centers()) for start, (target_discr, _) in zip(target_discr_starts, self.target_discrs_and_qbx_sides): code_getter.copy_targets_kernel()( actx.queue, targets=targets[:, start:start + target_discr.ndofs], points=flatten(target_discr.nodes(), actx, leaf_class=DOFArray), ) return TargetInfo(targets=actx.freeze(targets), target_discr_starts=target_discr_starts, ntargets=ntargets)
def target_info(self): code_getter = self.code_getter lpot_src = self.lpot_source target_discrs = self.target_discrs ntargets = 0 target_discr_starts = [] for target_discr in target_discrs: target_discr_starts.append(ntargets) ntargets += target_discr.ndofs actx = self.array_context target_discr_starts.append(ntargets) targets = actx.empty((lpot_src.ambient_dim, ntargets), self.coord_dtype) for start, target_discr in zip(target_discr_starts, target_discrs): code_getter.copy_targets_kernel()( actx.queue, targets=targets[:, start:start + target_discr.ndofs], points=flatten(target_discr.nodes(), actx, leaf_class=DOFArray), ) return _TargetInfo(targets=targets, target_discr_starts=target_discr_starts, ntargets=ntargets).with_queue(None)
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 tree(self): """Build and return a :class:`boxtree.tree.Tree` for this source with these targets. |cached| """ code_getter = self.code_getter lpot_src = self.lpot_source target_info = self.target_info() actx = self.array_context nsources = lpot_src.density_discr.ndofs nparticles = nsources + target_info.ntargets refine_weights = actx.zeros(nparticles, dtype=np.int32) refine_weights[:nsources] = 1 refine_weights.finish() MAX_LEAF_REFINE_WEIGHT = 32 # noqa tree, _ = code_getter.build_tree( actx.queue, particles=flatten(lpot_src.density_discr.nodes(), actx, leaf_class=DOFArray), targets=target_info.targets, max_leaf_refine_weight=MAX_LEAF_REFINE_WEIGHT, refine_weights=refine_weights, debug=self.debug, kind="adaptive") return tree
def tree(self): """Build and return a :class:`boxtree.Tree` for this source with these targets. |cached| """ actx = self._setup_actx code_getter = self.code_getter lpot_source = self.lpot_source target_info = self.target_info() from pytential import sym quad_stage2_discr = self.places.get_discretization( self.source_dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2) nsources = sum(grp.ndofs for grp in quad_stage2_discr.groups) nparticles = nsources + target_info.ntargets target_radii = None if lpot_source._expansions_in_tree_have_extent: target_radii = actx.zeros(target_info.ntargets, self.coord_dtype) target_radii[:self.ncenters] = self.flat_expansion_radii() refine_weights = actx.empty(nparticles, dtype=np.int32) # Assign a weight of 1 to all sources, QBX centers, and conventional # (non-QBX) targets. Assign a weight of 0 to all targets that need # QBX centers. The potential at the latter targets is mediated # entirely by the QBX center, so as a matter of evaluation cost, # their location in the tree is irrelevant. refine_weights[:-target_info.ntargets] = 1 user_ttc = actx.thaw(self.user_target_to_center()) refine_weights[-target_info.ntargets:] = ( user_ttc == target_state.NO_QBX_NEEDED).astype(np.int32) refine_weights.finish() tree, _ = code_getter.build_tree()( actx.queue, particles=flatten(quad_stage2_discr.nodes(), actx, leaf_class=DOFArray), targets=target_info.targets, target_radii=target_radii, max_leaf_refine_weight=lpot_source._max_leaf_refine_weight, refine_weights=refine_weights, debug=self.debug, stick_out_factor=lpot_source._expansion_stick_out_factor, extent_norm=lpot_source._box_extent_norm, kind=self.tree_kind) if self.debug: tgt_count_2 = actx.to_numpy( actx.np.sum(tree.box_target_counts_nonchild)) assert (tree.ntargets == tgt_count_2), (tree.ntargets, tgt_count_2) return tree.with_queue(None)
def flatten_and_reorder_sources(source_array): if isinstance(source_array, DOFArray): source_array = flatten(source_array, actx) if isinstance(source_array, actx.array_types): return actx.freeze( actx.thaw(source_array)[tree_user_source_ids]) else: return source_array
def check_sufficient_source_quadrature_resolution(self, stage2_density_discr, tree, peer_lists, refine_flags, debug, wait_for=None): actx = self.array_context # 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.sufficient_source_quadrature_resolution_checker( tree.dimensions, tree.coord_dtype, tree.box_id_dtype, peer_lists.peer_list_starts.dtype, tree.particle_id_dtype, max_levels) if debug: nelements_to_refine_prev = actx.to_numpy( actx.np.sum(refine_flags)).item() found_element_to_refine = actx.zeros(1, dtype=np.int32) found_element_to_refine.finish() from pytential import bind, sym dd = sym.as_dofdesc(sym.GRANULARITY_ELEMENT).to_stage2() source_danger_zone_radii_by_element = flatten( bind( stage2_density_discr, sym._source_danger_zone_radii(stage2_density_discr.ambient_dim, dofdesc=dd))(self.array_context), self.array_context) unwrap_args = AreaQueryElementwiseTemplate.unwrap_args evt = knl(*unwrap_args( tree, peer_lists, tree.box_to_qbx_center_starts, tree.box_to_qbx_center_lists, tree.qbx_element_to_source_starts, tree.qbx_user_source_slice.start, tree.qbx_user_center_slice.start, tree.sorted_target_ids, source_danger_zone_radii_by_element, tree.nqbxelements, refine_flags, found_element_to_refine, *tree.sources), range=slice(tree.nqbxsources), queue=actx.queue, wait_for=wait_for) import pyopencl as cl cl.wait_for_events([evt]) if debug: nelements_to_refine = actx.to_numpy( actx.np.sum(refine_flags)).item() if nelements_to_refine > nelements_to_refine_prev: logger.debug("refiner: found %d element(s) to refine", nelements_to_refine - nelements_to_refine_prev) return actx.to_numpy(found_element_to_refine)[0] == 1
def evaluate_kernel_arguments(actx, evaluate, kernel_arguments, flat=True): kernel_args = {} for arg_name, arg_expr in kernel_arguments.items(): value = evaluate(arg_expr) if flat: value = flatten(value, actx, leaf_class=DOFArray) kernel_args[arg_name] = value return kernel_args
def get_flat_strengths_from_densities( actx, places, evaluate, densities, dofdesc=None): from pytential import bind, sym waa = bind( places, sym.weights_and_area_elements(places.ambient_dim, dofdesc=dofdesc), )(actx) strength_vecs = [waa * evaluate(density) for density in densities] return [flatten(strength, actx) for strength in strength_vecs]
def _isclose(discr, x, y, rel_tol=1e-9, abs_tol=0, return_operands=False): from mirgecom.simutil import componentwise_norms from arraycontext import flatten actx = x.array_context lhs = actx.to_numpy(flatten(componentwise_norms(discr, x - y, np.inf), actx)) rhs = np.maximum( rel_tol * np.maximum( actx.to_numpy(flatten(componentwise_norms(discr, x, np.inf), actx)), actx.to_numpy(flatten(componentwise_norms(discr, y, np.inf), actx))), abs_tol) is_close = np.all(lhs <= rhs) if return_operands: return is_close, lhs, rhs else: return is_close
def max_component_norm(discr, fields, order=np.inf): """Return the max *order*-norm over the components of *fields*. .. note:: This is a collective routine and must be called by all MPI ranks. """ actx = fields.array_context return max( actx.to_numpy(flatten(componentwise_norms(discr, fields, order), actx)))
def partition_by_nodes( actx: PyOpenCLArrayContext, discr: Discretization, *, tree_kind: Optional[str] = "adaptive-level-restricted", max_particles_in_box: Optional[int] = None) -> BlockIndexRanges: """Generate equally sized ranges of nodes. The partition is created at the lowest level of granularity, i.e. nodes. This results in balanced ranges of points, but will split elements across different ranges. :arg tree_kind: if not *None*, it is passed to :class:`boxtree.TreeBuilder`. :arg max_particles_in_box: passed to :class:`boxtree.TreeBuilder`. """ if max_particles_in_box is None: # FIXME: this is just an arbitrary value max_particles_in_box = 32 if tree_kind is not None: from boxtree import box_flags_enum from boxtree import TreeBuilder builder = TreeBuilder(actx.context) from arraycontext import thaw tree, _ = builder(actx.queue, particles=flatten(thaw(discr.nodes(), actx), actx, leaf_class=DOFArray), max_particles_in_box=max_particles_in_box, kind=tree_kind) tree = tree.get(actx.queue) leaf_boxes, = (tree.box_flags & box_flags_enum.HAS_CHILDREN == 0).nonzero() indices = np.empty(len(leaf_boxes), dtype=object) ranges = None for i, ibox in enumerate(leaf_boxes): box_start = tree.box_source_starts[ibox] box_end = box_start + tree.box_source_counts_cumul[ibox] indices[i] = tree.user_source_ids[box_start:box_end] else: if discr.ambient_dim != 2 and discr.dim == 1: raise ValueError("only curves are supported for 'tree_kind=None'") nblocks = max(discr.ndofs // max_particles_in_box, 2) indices = np.arange(0, discr.ndofs, dtype=np.int64) ranges = np.linspace(0, discr.ndofs, nblocks + 1, dtype=np.int64) assert ranges[-1] == discr.ndofs from pytential.linalg import make_block_index_from_array return make_block_index_from_array(indices, ranges=ranges)
def compare_fluid_solutions(discr, red_state, blue_state): """Return inf norm of (*red_state* - *blue_state*) for each component. .. note:: This is a collective routine and must be called by all MPI ranks. """ actx = red_state.array_context resid = red_state - blue_state resid_errs = actx.to_numpy( flatten(componentwise_norms(discr, resid, order=np.inf), actx)) return resid_errs.tolist()
def map_interpolation(self, expr): from pytential import sym if expr.to_dd.discr_stage != sym.QBX_SOURCE_QUAD_STAGE2: raise RuntimeError( "can only interpolate to QBX_SOURCE_QUAD_STAGE2") operand = self.rec(expr.operand) actx = self.array_context if isinstance(operand, (int, float, complex, np.number)): return operand elif isinstance(operand, np.ndarray) and operand.ndim == 1: conn = self.places.get_connection(expr.from_dd, expr.to_dd) discr = self.places.get_discretization(expr.from_dd.geometry, expr.from_dd.discr_stage) template_ary = thaw(discr.nodes()[0], actx) from pytools.obj_array import make_obj_array return make_obj_array([ actx.to_numpy( flatten( conn(unflatten(template_ary, actx.from_numpy(o), actx)), actx)) for o in operand ]) elif isinstance(operand, np.ndarray) and operand.ndim == 2: cache = self.places._get_cache( MatrixBuilderDirectResamplerCacheKey) key = (expr.from_dd.geometry, expr.from_dd.discr_stage, expr.to_dd.discr_stage) try: mat = cache[key] except KeyError: from meshmode.discretization.connection import \ flatten_chained_connection from meshmode.discretization.connection.direct import \ make_direct_full_resample_matrix conn = self.places.get_connection(expr.from_dd, expr.to_dd) conn = flatten_chained_connection(actx, conn) mat = actx.to_numpy( make_direct_full_resample_matrix(actx, conn)) # FIXME: the resample matrix is slow to compute and very big # to store, so caching it may not be the best idea cache[key] = mat return mat.dot(operand) else: raise RuntimeError("unknown operand type: {}".format( type(operand)))
def flat_centers(self): """Return an object array of (interleaved) center coordinates. ``coord_t [ambient_dim][ncenters]`` """ from pytential import bind, sym actx = self._setup_actx centers = bind( self.places, sym.interleaved_expansion_centers( self.ambient_dim, dofdesc=self.source_dd.to_stage1()))(actx) return freeze(flatten(centers, actx, leaf_class=DOFArray), actx)
def __init__(self, dcoll: DiscretizationCollection, array_container: ArrayOrContainerT, remote_rank, tag=None): actx = get_container_context_recursively(array_container) btag = BTAG_PARTITION(remote_rank) local_bdry_data = project(dcoll, "vol", btag, array_container) comm = dcoll.mpi_communicator self.dcoll = dcoll self.array_context = actx self.remote_btag = btag self.bdry_discr = dcoll.discr_from_dd(btag) self.local_bdry_data = local_bdry_data self.local_bdry_data_np = \ to_numpy(flatten(self.local_bdry_data, actx), actx) self.tag = self.base_tag if tag is not None: self.tag += tag # Here, we initialize both send and recieve operations through # mpi4py `Request` (MPI_Request) instances for comm.Isend (MPI_Isend) # and comm.Irecv (MPI_Irecv) respectively. These initiate non-blocking # point-to-point communication requests and require explicit management # via the use of wait (MPI_Wait, MPI_Waitall, MPI_Waitany, MPI_Waitsome), # test (MPI_Test, MPI_Testall, MPI_Testany, MPI_Testsome), and cancel # (MPI_Cancel). The rank-local data `self.local_bdry_data_np` will have its # associated memory buffer sent across connected ranks and must not be # modified at the Python level during this process. Completion of the # requests is handled in :meth:`finish`. # # For more details on the mpi4py semantics, see: # https://mpi4py.readthedocs.io/en/stable/overview.html#nonblocking-communications # # NOTE: mpi4py currently (2021-11-03) holds a reference to the send # memory buffer for (i.e. `self.local_bdry_data_np`) until the send # requests is complete, however it is not clear that this is documented # behavior. We hold on to the buffer (via the instance attribute) # as well, just in case. self.send_req = comm.Isend(self.local_bdry_data_np, remote_rank, tag=self.tag) self.remote_data_host_numpy = np.empty_like(self.local_bdry_data_np) self.recv_req = comm.Irecv(self.remote_data_host_numpy, remote_rank, tag=self.tag)
def map_call(self, expr): arg, = expr.parameters rec_arg = self.rec(arg) if isinstance(rec_arg, np.ndarray) and self.is_kind_matrix(rec_arg): raise RuntimeError("expression is nonlinear in variable") from numbers import Number if isinstance(rec_arg, Number): return getattr(np, expr.function.name)(rec_arg) else: actx = self.array_context rec_arg = actx.from_numpy(rec_arg) result = getattr(actx.np, expr.function.name)(rec_arg) return actx.to_numpy(flatten(result, actx))
def flat_expansion_radii(self): """Return an array of radii associated with the (interleaved) expansion centers. ``coord_t [ncenters]`` """ from pytential import bind, sym actx = self._setup_actx radii = bind( self.places, sym.expansion_radii(self.ambient_dim, granularity=sym.GRANULARITY_CENTER, dofdesc=self.source_dd.to_stage1()))(actx) return freeze(flatten(radii, actx), actx)
def exec_compute_potential_insn(self, actx, insn, bound_expr, evaluate, return_timing_data): if return_timing_data: from warnings import warn warn("Timing data collection not supported.", category=UnableToCollectTimingData) p2p = None kernel_args = evaluate_kernel_arguments(actx, evaluate, insn.kernel_arguments, flat=False) strengths = [evaluate(density) for density in insn.densities] # FIXME: Do this all at once results = [] for o in insn.outputs: target_discr = bound_expr.places.get_discretization( o.target_name.geometry, o.target_name.discr_stage) # no on-disk kernel caching if p2p is None: p2p = self.get_p2p(actx, source_kernels=insn.source_kernels, target_kernels=insn.target_kernels) evt, output_for_each_kernel = p2p(actx.queue, targets=flatten( target_discr.nodes(), actx, leaf_class=DOFArray), sources=self._nodes, strength=strengths, **kernel_args) from meshmode.discretization import Discretization result = output_for_each_kernel[o.target_kernel_index] if isinstance(target_discr, Discretization): template_ary = thaw(target_discr.nodes()[0], actx) result = unflatten(template_ary, result, actx, strict=False) results.append((o.name, result)) timing_data = {} return results, timing_data
def test_unregularized_with_ones_kernel(actx_factory): actx = actx_factory() nelements = 10 order = 8 mesh = mgen.make_curve_mesh(partial(mgen.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)) from pytential.unregularized import UnregularizedLayerPotentialSource lpot_source = UnregularizedLayerPotentialSource(discr) from pytential.target import PointsTarget targets = PointsTarget(actx.from_numpy(np.zeros((2, 1), dtype=np.float64))) places = GeometryCollection({ sym.DEFAULT_SOURCE: lpot_source, sym.DEFAULT_TARGET: lpot_source, "target_non_self": targets }) from sumpy.kernel import one_kernel_2d sigma_sym = sym.var("sigma") op = sym.int_g_vec(one_kernel_2d, sigma_sym, qbx_forced_limit=None) sigma = discr.zeros(actx) + 1 result_self = bind(places, op, auto_where=places.auto_where)(actx, sigma=sigma) result_nonself = bind(places, op, auto_where=(places.auto_source, "target_non_self"))(actx, sigma=sigma) assert np.allclose(actx.to_numpy(flatten(result_self, actx)), 2 * np.pi) assert np.allclose(actx.to_numpy(result_nonself), 2 * np.pi)
def test_analytic_comparison(actx_factory): """Quick test of state comparison routine.""" from mirgecom.initializers import Vortex2D from mirgecom.simutil import compare_fluid_solutions, componentwise_norms actx = actx_factory() nel_1d = 4 dim = 2 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(1.0, ) * dim, b=(2.0, ) * dim, nelements_per_axis=(nel_1d, ) * dim) order = 2 discr = EagerDGDiscretization(actx, mesh, order=order) nodes = thaw(discr.nodes(), actx) zeros = discr.zeros(actx) ones = zeros + 1.0 mass = ones energy = ones velocity = 2 * nodes mom = mass * velocity vortex_init = Vortex2D() vortex_soln = vortex_init(x_vec=nodes, eos=IdealSingleGas()) cv = make_conserved(dim, mass=mass, energy=energy, momentum=mom) resid = vortex_soln - cv expected_errors = actx.to_numpy( flatten(componentwise_norms(discr, resid, order=np.inf), actx)).tolist() errors = compare_fluid_solutions(discr, cv, cv) assert max(errors) == 0 errors = compare_fluid_solutions(discr, cv, vortex_soln) assert errors == expected_errors
def _flat_centers(dofdesc, qbx_forced_limit): centers = bind(bound_expr.places, sym.expansion_centers( self.ambient_dim, qbx_forced_limit, dofdesc=dofdesc), )(actx) return freeze(flatten(centers, actx, leaf_class=DOFArray), actx)
def _flat_expansion_radii(dofdesc): radii = bind( bound_expr.places, sym.expansion_radii(self.ambient_dim, dofdesc=dofdesc), )(actx) return freeze(flatten(radii, actx), actx)
def _flat_nodes(dofdesc): discr = bound_expr.places.get_discretization( dofdesc.geometry, dofdesc.discr_stage) return freeze(flatten(discr.nodes(), actx, leaf_class=DOFArray), actx)
def main(curve_fn=starfish, visualize=True): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info import pyopencl as cl cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue, force_device_scalars=True) from meshmode.mesh.generation import make_curve_mesh mesh = make_curve_mesh( curve_fn, 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=qbx_order+3, target_association_tolerance=0.005, #fmm_backend="fmmlib", ) from pytential.target import PointsTarget fplot = FieldPlotter(np.zeros(2), extent=5, npoints=1000) targets_dev = actx.from_numpy(fplot.points) from pytential import GeometryCollection places = GeometryCollection({ "qbx": qbx, "targets": PointsTarget(targets_dev), }, auto_where="qbx") density_discr = places.get_discretization("qbx") nodes = thaw(density_discr.nodes(), actx) angle = actx.np.arctan2(nodes[1], nodes[0]) if k: kernel = HelmholtzKernel(2) kernel_kwargs = {"k": sym.var("k")} else: kernel = LaplaceKernel(2) kernel_kwargs = {} def op(**kwargs): kwargs.update(kernel_kwargs) #op = sym.d_dx(sym.S(kernel, sym.var("sigma"), **kwargs)) return sym.D(kernel, sym.var("sigma"), **kwargs) #op = sym.S(kernel, sym.var("sigma"), qbx_forced_limit=None, **kwargs) if 0: from random import randrange sigma = actx.zeros(density_discr.ndofs, angle.entry_dtype) for _ in range(5): sigma[randrange(len(sigma))] = 1 from arraycontext import unflatten sigma = unflatten(angle, sigma, actx) else: sigma = actx.np.cos(mode_nr*angle) if isinstance(kernel, HelmholtzKernel): for i, elem in np.ndenumerate(sigma): sigma[i] = elem.astype(np.complex128) bound_bdry_op = bind(places, op()) if visualize: fld_in_vol = actx.to_numpy( bind(places, op( source="qbx", target="targets", qbx_forced_limit=None))(actx, sigma=sigma, k=k)) if enable_mayavi: fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) else: fplot.write_vtk_file("layerpot-potential.vts", [ ("potential", fld_in_vol) ]) if 0: apply_op = bound_bdry_op.scipy_op(actx, "sigma", np.float64, k=k) from sumpy.tools import build_matrix mat = build_matrix(apply_op) import matplotlib.pyplot as pt pt.imshow(mat) pt.colorbar() pt.show() if enable_mayavi: # {{{ plot boundary field from arraycontext import flatten fld_on_bdry = actx.to_numpy( flatten(bound_bdry_op(actx, sigma=sigma, k=k), actx)) nodes_host = actx.to_numpy( flatten(density_discr.nodes(), actx) ).reshape(density_discr.ambient_dim, -1) mlab.points3d(nodes_host[0], nodes_host[1], fld_on_bdry.real, scale_factor=0.03) mlab.colorbar() mlab.show()