def main(write_output=True): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext( queue, allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)), force_device_scalars=True, ) from meshmode.mesh import BTAG_ALL from meshmode.mesh.generation import generate_warped_rect_mesh mesh = generate_warped_rect_mesh(dim=2, order=4, nelements_side=6) dcoll = DiscretizationCollection(actx, mesh, order=4) nodes = thaw(dcoll.nodes(), actx) bdry_nodes = thaw(dcoll.nodes(dd=BTAG_ALL), actx) bdry_normals = thaw(dcoll.normal(dd=BTAG_ALL), actx) if write_output: vis = shortcuts.make_visualizer(dcoll) vis.write_vtk_file("geo.vtu", [("nodes", nodes)]) bvis = shortcuts.make_boundary_visualizer(dcoll) bvis.write_vtk_file("bgeo.vtu", [("bdry normals", bdry_normals), ("bdry nodes", bdry_nodes)])
def test_nodal_dg_interop(actx_factory, dim): pytest.importorskip("oct2py") actx = actx_factory() from meshmode.interop.nodal_dg import download_nodal_dg_if_not_present download_nodal_dg_if_not_present() order = 4 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(8, ) * dim, order=order) from meshmode.interop.nodal_dg import NodalDGContext with NodalDGContext("./nodal-dg/Codes1.1") as ndgctx: ndgctx.set_mesh(mesh, order=order) discr = ndgctx.get_discr(actx) for ax in range(dim): x_ax = ndgctx.pull_dof_array(actx, ndgctx.AXES[ax]) err = flat_norm(x_ax - thaw(discr.nodes()[ax], actx), np.inf) assert err < 1e-15 n0 = thaw(discr.nodes()[0], actx) ndgctx.push_dof_array("n0", n0) n0_2 = ndgctx.pull_dof_array(actx, "n0") assert flat_norm(n0 - n0_2, np.inf) < 1e-15
def test_mesh_without_vertices(actx_factory): actx = actx_factory() # create a mesh mesh = mgen.generate_icosphere(r=1.0, order=4) # create one without the vertices grp, = mesh.groups groups = [ grp.copy(nodes=grp.nodes, vertex_indices=None) for grp in mesh.groups ] mesh = Mesh(None, groups, is_conforming=False) # try refining it from meshmode.mesh.refinement import refine_uniformly mesh = refine_uniformly(mesh, 1) # make sure the world doesn't end from meshmode.discretization import Discretization discr = Discretization(actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(4)) thaw(discr.nodes(), actx) from meshmode.discretization.visualization import make_visualizer make_visualizer(actx, discr, 4)
def map_node_coordinate_component(self, expr): discr = self.places.get_discretization(expr.dofdesc.geometry, expr.dofdesc.discr_stage) from arraycontext import thaw x = discr.nodes()[expr.ambient_axis] return thaw(x, self.array_context)
def test_chained_full_resample_matrix(actx_factory, ndim, visualize=False): from meshmode.discretization.connection.chained import \ make_full_resample_matrix actx = actx_factory() discr = create_discretization(actx, ndim, order=2, nelements=12) connections = [] conn = create_refined_connection(actx, discr) connections.append(conn) conn = create_refined_connection(actx, conn.to_discr) connections.append(conn) from meshmode.discretization.connection import \ ChainedDiscretizationConnection chained = ChainedDiscretizationConnection(connections) def f(x): from functools import reduce return 0.1 * reduce(lambda x, y: x * actx.np.sin(5 * y), x) resample_mat = actx.to_numpy(make_full_resample_matrix(actx, chained)) x = thaw(connections[0].from_discr.nodes(), actx) fx = f(x) f1 = resample_mat @ flatten_to_numpy(actx, fx) f2 = flatten_to_numpy(actx, chained(fx)) f3 = flatten_to_numpy(actx, connections[1](connections[0](fx))) assert np.allclose(f1, f2) assert np.allclose(f2, f3)
def main(): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from meshmode.mesh.generation import ( # noqa generate_icosphere, generate_icosahedron, generate_torus) #mesh = generate_icosphere(1, order=order) mesh = generate_icosahedron(1, order=order) #mesh = generate_torus(3, 1, order=order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ PolynomialWarpAndBlendGroupFactory discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(order)) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, discr, order) vis.write_vtk_file("geometry.vtu", [ ("f", thaw(discr.nodes()[0], actx)), ]) from meshmode.discretization.visualization import \ write_nodal_adjacency_vtk_file write_nodal_adjacency_vtk_file("adjacency.vtu", mesh)
def area_element(actx: ArrayContext, dcoll: DiscretizationCollection, dd=None, *, _use_geoderiv_connection=False) -> DOFArray: r"""Computes the scale factor used to transform integrals from reference to global space. This function caches its results. :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one. Defaults to the base volume discretization. :arg _use_geoderiv_connection: If *True*, process returned :class:`~meshmode.dof_array.DOFArray`\ s through :meth:`~grudge.DiscretizationCollection._base_to_geoderiv_connection`. This should be set based on whether the code using the result of this function is able to make use of these arrays. (This is an internal argument and not intended for use outside :mod:`grudge`.) :returns: a :class:`~meshmode.dof_array.DOFArray` containing the transformed volumes for each element. """ if dd is None: dd = DD_VOLUME @memoize_in(dcoll, (area_element, dd, _use_geoderiv_connection)) def _area_elements(): result = actx.np.sqrt(pseudoscalar(actx, dcoll, dd=dd).norm_squared()) if _use_geoderiv_connection: result = dcoll._base_to_geoderiv_connection(dd)(result) return freeze(result, actx) return thaw(_area_elements(), actx)
def test_geometric_factors_regular_refinement(actx_factory, name): from grudge.dt_utils import dt_geometric_factors actx = actx_factory() # {{{ cases if name == "interval": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=1) elif name == "box2d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=2) elif name == "box3d": from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=3) else: raise ValueError("unknown geometry name: %s" % name) # }}} min_factors = [] for resolution in builder.resolutions: mesh = builder.get_mesh(resolution, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) min_factors.append( actx.to_numpy( op.nodal_min(dcoll, "vol", thaw(dt_geometric_factors(dcoll), actx)))) # Resolution is doubled each refinement, so the ratio of consecutive # geometric factors should satisfy: gfi+1 / gfi = 2 min_factors = np.asarray(min_factors) ratios = min_factors[:-1] / min_factors[1:] assert np.all(np.isclose(ratios, 2))
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 evaluate_sphere_eigf(actx, discr, m: int, n: int) -> DOFArray: assert discr.ambient_dim == 3 # {{{ get spherical coordinates from arraycontext import thaw x, y, z = thaw(discr.nodes(), actx) theta = actx.np.arctan2(actx.np.sqrt(x**2 + y**2), z) phi = actx.np.arctan2(y, x) # }}} # {{{ evaluate Y^m_n from scipy.special import sph_harm # pylint: disable=no-name-in-module y_mn = [] for gtheta, gphi in zip(theta, phi): result = sph_harm(m, n, actx.to_numpy(gphi), actx.to_numpy(gtheta)) y_mn.append(actx.from_numpy(result.real.copy())) # }}} return DOFArray(actx, tuple(y_mn))
def wave_flux(dcoll, c, w_tpair): dd = w_tpair.dd dd_quad = dd.with_discr_tag(DISCR_TAG_QUAD) u = w_tpair[0] v = w_tpair[1:] normal = thaw(dcoll.normal(dd), u.int.array_context) flux_weak = flat_obj_array( np.dot(v.avg, normal), normal*u.avg, ) # upwind flux_weak += flat_obj_array( 0.5*(u.ext-u.int), 0.5*normal*np.dot(normal, v.ext-v.int), ) # FIXME this flux is only correct for continuous c dd_allfaces_quad = dd_quad.with_dtag("all_faces") c_quad = op.project(dcoll, "vol", dd_quad, c) flux_quad = op.project(dcoll, dd, dd_quad, flux_weak) return op.project(dcoll, dd_quad, dd_allfaces_quad, c_quad*flux_quad)
def test_flatten_unflatten(actx_factory): actx = actx_factory() ambient_dim = 2 from meshmode.mesh.generation import generate_regular_rect_mesh mesh = generate_regular_rect_mesh(a=(-0.5, ) * ambient_dim, b=(+0.5, ) * ambient_dim, n=(3, ) * ambient_dim, order=1) discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(3)) a = np.random.randn(discr.ndofs) from meshmode.dof_array import flatten, unflatten a_round_trip = actx.to_numpy( flatten(unflatten(actx, discr, actx.from_numpy(a)))) assert np.array_equal(a, a_round_trip) from meshmode.dof_array import flatten_to_numpy, unflatten_from_numpy a_round_trip = flatten_to_numpy(actx, unflatten_from_numpy(actx, discr, a)) assert np.array_equal(a, a_round_trip) x = thaw(discr.nodes(), actx) avg_mass = DOFArray( actx, tuple([(np.pi + actx.zeros((grp.nelements, 1), a.dtype)) for grp in discr.groups])) c = MyContainer(name="flatten", mass=avg_mass, momentum=make_obj_array([x, x, x]), enthalpy=x) from meshmode.dof_array import unflatten_like c_round_trip = unflatten_like(actx, flatten(c), c) assert flat_norm(c - c_round_trip) < 1.0e-8
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 boundary_solution(discr, btag, gas_model, state_minus, **kwargs): actx = state_minus.array_context bnd_discr = discr.discr_from_dd(btag) nodes = thaw(bnd_discr.nodes(), actx) return make_fluid_state(initializer(x_vec=nodes, eos=gas_model.eos, **kwargs), gas_model, temperature_seed=state_minus.temperature)
def absorbing_bc(self, w): """Construct part of the flux operator template for 1st order absorbing boundary conditions. """ actx = get_container_context_recursively(w) absorb_normal = thaw(self.dcoll.normal(dd=self.absorb_tag), actx) e, h = self.split_eh(w) if self.fixed_material: epsilon = self.epsilon mu = self.mu absorb_Z = (mu / epsilon)**0.5 # noqa: N806 absorb_Y = 1 / absorb_Z # noqa: N806 absorb_e = op.project(self.dcoll, "vol", self.absorb_tag, e) absorb_h = op.project(self.dcoll, "vol", self.absorb_tag, h) bc = flat_obj_array( absorb_e + 1 / 2 * (self.space_cross_h(absorb_normal, self.space_cross_e(absorb_normal, absorb_e)) - absorb_Z * self.space_cross_h(absorb_normal, absorb_h)), absorb_h + 1 / 2 * (self.space_cross_e(absorb_normal, self.space_cross_h(absorb_normal, absorb_h)) + absorb_Y * self.space_cross_e(absorb_normal, absorb_e))) return bc
def flux(self, wtpair): """The numerical flux for variable coefficients. :param flux_type: can be in [0,1] for anything between central and upwind, or "lf" for Lax-Friedrichs. As per Hesthaven and Warburton page 433. """ actx = get_container_context_recursively(wtpair) normal = thaw(self.dcoll.normal(wtpair.dd), actx) if self.fixed_material: e, h = self.split_eh(wtpair) epsilon = self.epsilon mu = self.mu Z_int = (mu / epsilon)**0.5 # noqa: N806 Y_int = 1 / Z_int # noqa: N806 Z_ext = (mu / epsilon)**0.5 # noqa: N806 Y_ext = 1 / Z_ext # noqa: N806 if self.flux_type == "lf": # if self.fixed_material: # max_c = (self.epsilon*self.mu)**(-0.5) return flat_obj_array( # flux e, 1 / 2 * ( -self.space_cross_h(normal, h.ext - h.int) # multiplication by epsilon undoes material divisor below #-max_c*(epsilon*e.int - epsilon*e.ext) ), # flux h 1 / 2 * ( self.space_cross_e(normal, e.ext - e.int) # multiplication by mu undoes material divisor below #-max_c*(mu*h.int - mu*h.ext) )) elif isinstance(self.flux_type, (int, float)): # see doc/maxima/maxwell.mac return flat_obj_array( # flux e, (-1 / (Z_int + Z_ext) * self.space_cross_h( normal, Z_ext * (h.ext - h.int) - self.flux_type * self.space_cross_e(normal, e.ext - e.int)) ), # flux h (1 / (Y_int + Y_ext) * self.space_cross_e( normal, Y_ext * (e.ext - e.int) + self.flux_type * self.space_cross_h(normal, h.ext - h.int)) ), ) else: raise ValueError("maxwell: invalid flux_type (%s)" % self.flux_type)
def operator(self, t, w): dcoll = self.dcoll u = w[0] v = w[1:] actx = u.array_context # boundary conditions ------------------------------------------------- # dirichlet BCs ------------------------------------------------------- dir_u = op.project(dcoll, "vol", self.dirichlet_tag, u) dir_v = op.project(dcoll, "vol", self.dirichlet_tag, v) if self.dirichlet_bc_f: # FIXME from warnings import warn warn("Inhomogeneous Dirichlet conditions on the wave equation " "are still having issues.") dir_g = self.dirichlet_bc_f dir_bc = flat_obj_array(2 * dir_g - dir_u, dir_v) else: dir_bc = flat_obj_array(-dir_u, dir_v) # neumann BCs --------------------------------------------------------- neu_u = op.project(dcoll, "vol", self.neumann_tag, u) neu_v = op.project(dcoll, "vol", self.neumann_tag, v) neu_bc = flat_obj_array(neu_u, -neu_v) # radiation BCs ------------------------------------------------------- rad_normal = thaw(dcoll.normal(dd=self.radiation_tag), actx) rad_u = op.project(dcoll, "vol", self.radiation_tag, u) rad_v = op.project(dcoll, "vol", self.radiation_tag, v) rad_bc = flat_obj_array( 0.5 * (rad_u - self.sign * np.dot(rad_normal, rad_v)), 0.5 * rad_normal * (np.dot(rad_normal, rad_v) - self.sign * rad_u)) # entire operator ----------------------------------------------------- def flux(tpair): return op.project(dcoll, tpair.dd, "all_faces", self.flux(tpair)) result = (op.inverse_mass( dcoll, flat_obj_array(-self.c * op.weak_local_div(dcoll, v), -self.c * op.weak_local_grad(dcoll, u)) - op.face_mass( dcoll, sum( flux(tpair) for tpair in op.interior_trace_pairs(dcoll, w)) + flux(op.bv_trace_pair(dcoll, self.dirichlet_tag, w, dir_bc)) + flux(op.bv_trace_pair(dcoll, self.neumann_tag, w, neu_bc)) + flux(op.bv_trace_pair(dcoll, self.radiation_tag, w, rad_bc))))) result[0] = result[0] + self.source_f(actx, dcoll, t) return result
def source_f(actx, dcoll, t=0): source_center = np.array([0.1, 0.22, 0.33])[:dcoll.dim] source_width = 0.05 source_omega = 3 nodes = thaw(dcoll.nodes(), actx) source_center_dist = flat_obj_array( [nodes[i] - source_center[i] for i in range(dcoll.dim)]) return (np.sin(source_omega * t) * actx.np.exp( -np.dot(source_center_dist, source_center_dist) / source_width**2))
def flux(dcoll, u_tpair): dd = u_tpair.dd velocity = np.array([2 * np.pi]) normal = thaw(dcoll.normal(dd), actx) v_dot_n = np.dot(velocity, normal) u_upwind = actx.np.where(v_dot_n > 0, u_tpair.int, u_tpair.ext) return u_upwind * v_dot_n
def test_modal_coefficients_by_projection(actx_factory, quad_group_factory): group_cls = SimplexElementGroup modal_group_factory = ModalSimplexGroupFactory actx = actx_factory() order = 10 m_order = 5 # Make a regular rectangle mesh mesh = mgen.generate_regular_rect_mesh(a=(0, 0), b=(5, 3), npoints_per_axis=(10, 6), order=order, group_cls=group_cls) # Make discretizations nodal_disc = Discretization(actx, mesh, quad_group_factory(order)) modal_disc = Discretization(actx, mesh, modal_group_factory(m_order)) # Make connections one using quadrature projection nodal_to_modal_conn_quad = NodalToModalDiscretizationConnection( nodal_disc, modal_disc, allow_approximate_quad=True) def f(x): return 2 * actx.np.sin(5 * x) x_nodal = thaw(nodal_disc.nodes()[0], actx) nodal_f = f(x_nodal) # Compute modal coefficients we expect to get import modepy as mp grp, = nodal_disc.groups shape = mp.Simplex(grp.dim) space = mp.space_for_shape(shape, order=m_order) basis = mp.orthonormal_basis_for_space(space, shape) quad = grp.quadrature_rule() nodal_f_data = actx.to_numpy(nodal_f[0]) vdm = mp.vandermonde(basis.functions, quad.nodes) w_diag = np.diag(quad.weights) modal_data = [] for _, nodal_data in enumerate(nodal_f_data): # Compute modal data in each element: V.T * W * nodal_data elem_modal_f = np.dot(vdm.T, np.dot(w_diag, nodal_data)) modal_data.append(elem_modal_f) modal_data = actx.from_numpy(np.asarray(modal_data)) modal_f_expected = DOFArray(actx, data=(modal_data, )) # Map nodal coefficients using the quadrature-based projection modal_f_computed = nodal_to_modal_conn_quad(nodal_f) err = flat_norm(modal_f_expected - modal_f_computed) assert err <= 1e-13
def _compute_characteristic_lengthscales(): return freeze( DOFArray( actx, data=tuple( # Scale each group array of geometric factors by the # corresponding group non-geometric factor cng * geo_facts for cng, geo_facts in zip( dt_non_geometric_factors(dcoll), thaw(dt_geometric_factors(dcoll), actx)))))
def map_node_coordinate_component(self, expr): discr = self.dcoll.discr_from_dd(expr.dd) return thaw( discr.nodes( # only save volume nodes or boundary nodes # (but not nodes for interior face discretizations, which # are likely only used once to compute the normals) cached=(discr.ambient_dim == discr.dim or expr.dd. is_boundary_or_partition_interface()))[expr.axis], self.array_context)
def run(nelements, order): discr = create_discretization(actx, ndim, nelements=nelements, order=order, mesh_name=mesh_name) threshold = 1.0 connections = [] conn = create_refined_connection(actx, discr, threshold=threshold) connections.append(conn) if ndim == 2: # NOTE: additional refinement makes the 3D meshes explode in size conn = create_refined_connection(actx, conn.to_discr, threshold=threshold) connections.append(conn) conn = create_refined_connection(actx, conn.to_discr, threshold=threshold) connections.append(conn) from meshmode.discretization.connection import \ ChainedDiscretizationConnection chained = ChainedDiscretizationConnection(connections) from meshmode.discretization.connection import \ L2ProjectionInverseDiscretizationConnection reverse = L2ProjectionInverseDiscretizationConnection(chained) # create test vector from_nodes = thaw(chained.from_discr.nodes(), actx) to_nodes = thaw(chained.to_discr.nodes(), actx) from_x = 0 to_x = 0 for d in range(ndim): from_x = from_x + actx.np.cos(from_nodes[d])**(d + 1) to_x = to_x + actx.np.cos(to_nodes[d])**(d + 1) from_interp = reverse(to_x) return (1.0 / nelements, flat_norm(from_interp - from_x, np.inf) / flat_norm(from_x, np.inf))
def inverse_surface_metric_derivative_mat(actx: ArrayContext, dcoll: DiscretizationCollection, dd=None, *, times_area_element=False, _use_geoderiv_connection=False): r"""Computes the matrix of inverse surface metric derivatives, indexed by ``(xyz_axis, rst_axis)``. It returns all values of :func:`inverse_surface_metric_derivative_mat` in cached matrix form. This function caches its results. :arg dd: a :class:`~grudge.dof_desc.DOFDesc`, or a value convertible to one. Defaults to the base volume discretization. :arg times_area_element: If *True*, each entry of the matrix is premultiplied with the value of :func:`area_element`, reflecting the typical use of the matrix in integrals evaluating weak derivatives. :arg _use_geoderiv_connection: If *True*, process returned :class:`~meshmode.dof_array.DOFArray`\ s through :meth:`~grudge.DiscretizationCollection._base_to_geoderiv_connection`. This should be set based on whether the code using the result of this function is able to make use of these arrays. (This is an internal argument and not intended for use outside :mod:`grudge`.) :returns: a :class:`~meshmode.dof_array.DOFArray` containing the inverse metric derivatives in per-group arrays of shape ``(xyz_dimension, rst_dimension, nelements, ndof)``. """ @memoize_in(dcoll, (inverse_surface_metric_derivative_mat, dd, times_area_element, _use_geoderiv_connection)) def _inv_surf_metric_deriv(): if times_area_element: multiplier = area_element( actx, dcoll, dd=dd, _use_geoderiv_connection=_use_geoderiv_connection) else: multiplier = 1 mat = actx.np.stack([ actx.np.stack([ multiplier * inverse_surface_metric_derivative( actx, dcoll, rst_axis, xyz_axis, dd=dd, _use_geoderiv_connection=_use_geoderiv_connection) for rst_axis in range(dcoll.dim) ]) for xyz_axis in range(dcoll.ambient_dim) ]) return freeze(mat, actx) return thaw(_inv_surf_metric_deriv(), actx)
def test_nodal_reductions(actx_factory): actx = actx_factory() from mesh_data import BoxMeshBuilder builder = BoxMeshBuilder(ambient_dim=1) mesh = builder.get_mesh(4, builder.mesh_order) dcoll = DiscretizationCollection(actx, mesh, order=builder.order) x = thaw(dcoll.nodes(), actx) def f(x): return -actx.np.sin(10 * x[0]) def g(x): return actx.np.cos(2 * x[0]) def h(x): return -actx.np.tan(5 * x[0]) fields = make_obj_array([f(x), g(x), h(x)]) f_ref = actx.to_numpy(flatten(fields[0])) g_ref = actx.to_numpy(flatten(fields[1])) h_ref = actx.to_numpy(flatten(fields[2])) concat_fields = np.concatenate([f_ref, g_ref, h_ref]) for inner_grudge_op, np_op in [(op.nodal_sum, np.sum), (op.nodal_max, np.max), (op.nodal_min, np.min)]: # FIXME: Remove this once all grudge reductions return device scalars def grudge_op(dcoll, dd, vec): res = inner_grudge_op(dcoll, dd, vec) from numbers import Number if not isinstance(res, Number): return actx.to_numpy(res) else: return res # Componentwise reduction checks assert np.isclose(grudge_op(dcoll, "vol", fields[0]), np_op(f_ref), rtol=1e-13) assert np.isclose(grudge_op(dcoll, "vol", fields[1]), np_op(g_ref), rtol=1e-13) assert np.isclose(grudge_op(dcoll, "vol", fields[2]), np_op(h_ref), rtol=1e-13) # Test nodal reductions work on object arrays assert np.isclose(grudge_op(dcoll, "vol", fields), np_op(concat_fields), rtol=1e-13)
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 test_sanity_qhull_nd(actx_factory, dim, order): pytest.importorskip("scipy") logging.basicConfig(level=logging.INFO) actx = actx_factory() from scipy.spatial import Delaunay # pylint: disable=no-name-in-module verts = np.random.rand(1000, dim) dtri = Delaunay(verts) # pylint: disable=no-member from meshmode.mesh.io import from_vertices_and_simplices mesh = from_vertices_and_simplices(dtri.points.T, dtri.simplices, fix_orientation=True) from meshmode.discretization import Discretization low_discr = Discretization(actx, mesh, PolynomialEquidistantSimplexGroupFactory(order)) high_discr = Discretization( actx, mesh, PolynomialEquidistantSimplexGroupFactory(order + 1)) from meshmode.discretization.connection import make_same_mesh_connection cnx = make_same_mesh_connection(actx, high_discr, low_discr) def f(x): return 0.1 * actx.np.sin(x) x_low = thaw(low_discr.nodes()[0], actx) f_low = f(x_low) x_high = thaw(high_discr.nodes()[0], actx) f_high_ref = f(x_high) f_high_num = cnx(f_low) err = (flat_norm(f_high_ref - f_high_num, np.inf) / flat_norm(f_high_ref, np.inf)) print(err) assert err < 1e-2
def inverse_parametrization_derivative(self): [a, b], [c, d] = thaw(self.parametrization_derivative(), self._setup_actx) result = np.zeros((2, 2), dtype=object) det = a * d - b * c result[0, 0] = d / det result[0, 1] = -b / det result[1, 0] = -c / det result[1, 1] = a / det return freeze(result)
def parametrization_derivative(actx, discr): thawed_nodes = thaw(discr.nodes(), actx) from meshmode.discretization import num_reference_derivative result = np.zeros((discr.ambient_dim, discr.dim), dtype=object) for iambient in range(discr.ambient_dim): for idim in range(discr.dim): result[iambient, idim] = num_reference_derivative(discr, (idim, ), thawed_nodes[iambient]) return result
def evaluate_circle_eigf(actx, discr, k: int) -> np.ndarray: assert discr.ambient_dim == 2 # {{{ get polar coordinates from arraycontext import thaw x, y = thaw(discr.nodes(), actx) theta = actx.np.arctan2(y, x) # }}} return actx.np.exp(-1j * k * theta)