def get_observation_mesh(self, target_order): from meshmode.mesh.generation import generate_icosphere if self.is_interior: return generate_icosphere(5, target_order) else: return generate_icosphere(0.5, target_order)
def test_mesh_without_vertices(ctx_factory): ctx = ctx_factory() queue = cl.CommandQueue(ctx) # create a mesh from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(r=1.0, order=4) # create one without the vertices from meshmode.mesh import Mesh 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 from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory as GroupFactory discr = Discretization(ctx, mesh, GroupFactory(4)) discr.nodes().with_queue(queue) from meshmode.discretization.visualization import make_visualizer make_visualizer(queue, discr, 4)
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 get_mesh(self, resolution, target_order): from meshmode.mesh.generation import generate_icosphere from meshmode.mesh.refinement import refine_uniformly mesh = refine_uniformly(generate_icosphere(1, target_order), resolution) return mesh
def get_mesh(self, resolution, target_order): from meshmode.mesh.generation import generate_icosphere from meshmode.mesh.refinement import refine_uniformly mesh = refine_uniformly( generate_icosphere(1, target_order), resolution) return mesh
def test_conformity_of_uniform_mesh(refinement_rounds): mesh = mgen.generate_icosphere(r=1.0, order=4, uniform_refinement_rounds=refinement_rounds) assert mesh.is_conforming from meshmode.mesh import is_boundary_tag_empty, BTAG_ALL assert is_boundary_tag_empty(mesh, BTAG_ALL)
def get_unit_sphere_with_ref_mean_curvature(cl_ctx): order = 8 from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, order) discr = Discretization(cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(order)) return discr, 1
def get_sphere_mesh(refinement_increment, target_order): from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.mesh.refinement import Refiner refiner = Refiner(mesh) for i in range(refinement_increment): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() return mesh
def test_mesh_with_interior_unit_nodes(actx_factory, ambient_dim): actx = actx_factory() # NOTE: smaller orders or coarser meshes make the cases fail the # node_vertex_consistency test; the default warp_and_blend_nodes have # nodes at the vertices, so they pass for much smaller tolerances order = 8 nelements = 32 n_minor = 2 * nelements uniform_refinement_rounds = 4 import modepy as mp if ambient_dim == 2: unit_nodes = mp.LegendreGaussQuadrature(order, force_dim_axis=True).nodes mesh = mgen.make_curve_mesh(partial(mgen.ellipse, 2.0), np.linspace(0.0, 1.0, nelements + 1), order=order, unit_nodes=unit_nodes) elif ambient_dim == 3: unit_nodes = mp.VioreanuRokhlinSimplexQuadrature(order, 2).nodes mesh = mgen.generate_torus(4.0, 2.0, n_major=2 * n_minor, n_minor=n_minor, order=order, unit_nodes=unit_nodes) mesh = mgen.generate_icosphere( 1.0, uniform_refinement_rounds=uniform_refinement_rounds, order=order, unit_nodes=unit_nodes) else: raise ValueError(f"unsupported dimension: '{ambient_dim}'") assert mesh.facial_adjacency_groups assert mesh.nodal_adjacency from meshmode.discretization import Discretization from meshmode.discretization.poly_element import QuadratureSimplexGroupFactory discr = Discretization(actx, mesh, QuadratureSimplexGroupFactory(order)) from meshmode.discretization.connection import make_face_restriction conn = make_face_restriction( actx, discr, group_factory=QuadratureSimplexGroupFactory(order), boundary_tag=FACE_RESTR_ALL) assert conn
def test_copy_visualizer(actx_factory, ambient_dim, visualize=True): actx = actx_factory() target_order = 4 if ambient_dim == 2: nelements = 128 mesh = mgen.make_curve_mesh(partial(mgen.ellipse, 1.0), np.linspace(0.0, 1.0, nelements + 1), target_order) elif ambient_dim == 3: mesh = mgen.generate_icosphere(1.0, target_order, uniform_refinement_rounds=2) else: raise ValueError(f"unsupported dimension: {ambient_dim}") from meshmode.mesh.processing import affine_map translated_mesh = affine_map(mesh, b=np.array([2.5, 0.0, 0.0][:ambient_dim])) from meshmode.discretization import Discretization discr = Discretization(actx, mesh, PolynomialWarpAndBlendGroupFactory(target_order)) translated_discr = Discretization( actx, translated_mesh, PolynomialWarpAndBlendGroupFactory(target_order)) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, discr, target_order, force_equidistant=True) assert vis._vtk_connectivity assert vis._vtk_lagrange_connectivity translated_vis = vis.copy_with_same_connectivity(actx, translated_discr) assert translated_vis._cached_vtk_connectivity is not None assert translated_vis._cached_vtk_lagrange_connectivity is not None assert translated_vis._vtk_connectivity \ is vis._vtk_connectivity assert translated_vis._vtk_lagrange_connectivity \ is vis._vtk_lagrange_connectivity if not visualize: return vis.write_vtk_file(f"visualizer_copy_{ambient_dim}d_orig.vtu", [], overwrite=True) translated_vis.write_vtk_file( f"visualizer_copy_{ambient_dim}d_translated.vtu", [], overwrite=True)
def test_is_affine_group_check(mesh_name): order = 4 nelements = 16 if mesh_name.startswith("box"): dim = int(mesh_name[-2]) is_affine = True mesh = mgen.generate_regular_rect_mesh( a=(-0.5, ) * dim, b=(0.5, ) * dim, nelements_per_axis=(nelements, ) * dim, order=order) elif mesh_name.startswith("warped_box"): dim = int(mesh_name[-2]) is_affine = False mesh = mgen.generate_warped_rect_mesh(dim, order, nelements_side=nelements) elif mesh_name == "cross_warped_box": dim = 2 is_affine = False mesh = _generate_cross_warped_rect_mesh(dim, order, nelements) elif mesh_name == "circle": is_affine = False mesh = mgen.make_curve_mesh(lambda t: mgen.ellipse(1.0, t), np.linspace(0.0, 1.0, nelements + 1), order=order) elif mesh_name == "ellipse": is_affine = False mesh = mgen.make_curve_mesh(lambda t: mgen.ellipse(2.0, t), np.linspace(0.0, 1.0, nelements + 1), order=order) elif mesh_name == "sphere": is_affine = False mesh = mgen.generate_icosphere(r=1.0, order=order) elif mesh_name == "torus": is_affine = False mesh = mgen.generate_torus(10.0, 2.0, order=order) else: raise ValueError(f"unknown mesh name: {mesh_name}") assert all(grp.is_affine for grp in mesh.groups) == is_affine
def test_refine_surfaces(actx_factory, mesh_name, visualize=False): if mesh_name == "torus": mesh = mgen.generate_torus(10, 1, 40, 4, order=4) elif mesh_name == "icosphere": mesh = mgen.generate_icosphere(1, order=4) else: raise ValueError(f"invalid mesh name '{mesh_name}'") if visualize: actx = actx_factory() from meshmode.mesh.visualization import vtk_visualize_mesh vtk_visualize_mesh(actx, mesh, "surface.vtu") # check for absence of node-vertex consistency error from meshmode.mesh.refinement import refine_uniformly refined_mesh = refine_uniformly(mesh, 1) if visualize: actx = actx_factory() from meshmode.mesh.visualization import vtk_visualize_mesh vtk_visualize_mesh(actx, refined_mesh, "surface-refined.vtu")
def get_sphere_lpot_source(queue): from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) target_order = 8 from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) pre_density_discr = Discretization( queue.context, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource lpot_source = QBXLayerPotentialSource(pre_density_discr, qbx_order=5, fmm_order=10, fine_order=4 * target_order, fmm_backend="fmmlib") lpot_source, _ = lpot_source.with_refinement() return lpot_source
def get_mesh(self, resolution, mesh_order): from meshmode.mesh.generation import generate_icosphere return generate_icosphere(self.radius, order=mesh_order, uniform_refinement_rounds=resolution)
def test_sphere_eigenvalues(ctx_factory, mode_m, mode_n, qbx_order, fmm_backend): logging.basicConfig(level=logging.INFO) special = pytest.importorskip("scipy.special") cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) target_order = 8 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() dp_eoc_rec = EOCRecorder() def rel_err(comp, ref): return (norm(density_discr, comp - ref) / norm(density_discr, ref)) for nrefinements in [0, 1]: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.mesh.refinement import Refiner refiner = Refiner(mesh) for i in range(nrefinements): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order, fmm_order=6, fmm_backend=fmm_backend, ) places = GeometryCollection(qbx) from meshmode.dof_array import flatten, unflatten, thaw density_discr = places.get_discretization(places.auto_source.geometry) nodes = thaw(actx, density_discr.nodes()) r = actx.np.sqrt(nodes[0] * nodes[0] + nodes[1] * nodes[1] + nodes[2] * nodes[2]) phi = actx.np.arccos(nodes[2] / r) theta = actx.np.arctan2(nodes[0], nodes[1]) ymn = unflatten( actx, density_discr, actx.from_numpy( special.sph_harm(mode_m, mode_n, actx.to_numpy(flatten(theta)), actx.to_numpy(flatten(phi))))) from sumpy.kernel import LaplaceKernel lap_knl = LaplaceKernel(3) # {{{ single layer s_sigma_op = bind( places, sym.S(lap_knl, sym.var("sigma"), qbx_forced_limit=+1)) s_sigma = s_sigma_op(actx, sigma=ymn) s_eigval = 1 / (2 * mode_n + 1) h_max = bind(places, sym.h_max(qbx.ambient_dim))(actx) s_eoc_rec.add_data_point(h_max, rel_err(s_sigma, s_eigval * ymn)) # }}} # {{{ double layer d_sigma_op = bind( places, sym.D(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) d_sigma = d_sigma_op(actx, sigma=ymn) d_eigval = -1 / (2 * (2 * mode_n + 1)) d_eoc_rec.add_data_point(h_max, rel_err(d_sigma, d_eigval * ymn)) # }}} # {{{ S' sp_sigma_op = bind( places, sym.Sp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) sp_sigma = sp_sigma_op(actx, sigma=ymn) sp_eigval = -1 / (2 * (2 * mode_n + 1)) sp_eoc_rec.add_data_point(h_max, rel_err(sp_sigma, sp_eigval * ymn)) # }}} # {{{ D' dp_sigma_op = bind( places, sym.Dp(lap_knl, sym.var("sigma"), qbx_forced_limit="avg")) dp_sigma = dp_sigma_op(actx, sigma=ymn) dp_eigval = -(mode_n * (mode_n + 1)) / (2 * mode_n + 1) dp_eoc_rec.add_data_point(h_max, rel_err(dp_sigma, dp_eigval * ymn)) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 0.5 print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D':") print(dp_eoc_rec) required_order = qbx_order assert dp_eoc_rec.order_estimate() > required_order - 1.5
def run(actx, *, ambient_dim: int = 3, resolution: int = None, target_order: int = 4, tmax: float = 1.0, timestep: float = 1.0e-2, group_factory_name: str = "warp_and_blend", visualize: bool = True): if ambient_dim not in (2, 3): raise ValueError(f"unsupported dimension: {ambient_dim}") mesh_order = target_order radius = 1.0 # {{{ geometry # {{{ element groups import modepy as mp import meshmode.discretization.poly_element as poly # NOTE: picking the same unit nodes for the mesh and the discr saves # a bit of work when reconstructing after a time step if group_factory_name == "warp_and_blend": group_factory_cls = poly.PolynomialWarpAndBlendGroupFactory unit_nodes = mp.warp_and_blend_nodes(ambient_dim - 1, mesh_order) elif group_factory_name == "quadrature": group_factory_cls = poly.InterpolatoryQuadratureSimplexGroupFactory if ambient_dim == 2: unit_nodes = mp.LegendreGaussQuadrature( mesh_order, force_dim_axis=True).nodes else: unit_nodes = mp.VioreanuRokhlinSimplexQuadrature(mesh_order, 2).nodes else: raise ValueError(f"unknown group factory: '{group_factory_name}'") # }}} # {{{ discretization import meshmode.mesh.generation as gen if ambient_dim == 2: nelements = 8192 if resolution is None else resolution mesh = gen.make_curve_mesh( lambda t: radius * gen.ellipse(1.0, t), np.linspace(0.0, 1.0, nelements + 1), order=mesh_order, unit_nodes=unit_nodes) else: nrounds = 4 if resolution is None else resolution mesh = gen.generate_icosphere(radius, uniform_refinement_rounds=nrounds, order=mesh_order, unit_nodes=unit_nodes) from meshmode.discretization import Discretization discr0 = Discretization(actx, mesh, group_factory_cls(target_order)) logger.info("ndofs: %d", discr0.ndofs) logger.info("nelements: %d", discr0.mesh.nelements) # }}} if visualize: from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, discr0, vis_order=target_order, # NOTE: setting this to True will add some unnecessary # resampling in Discretization.nodes for the vis_discr underneath force_equidistant=False) # }}} # {{{ ode def velocity_field(nodes, alpha=1.0): return make_obj_array([ alpha * nodes[0], -alpha * nodes[1], 0.0 * nodes[0] ][:ambient_dim]) def source(t, x): discr = reconstruct_discr_from_nodes(actx, discr0, x) u = velocity_field(thaw(discr.nodes(), actx)) # {{{ # NOTE: these are just here because this was at some point used to # profile some more operators (turned out well!) from meshmode.discretization import num_reference_derivative x = thaw(discr.nodes()[0], actx) gradx = sum( num_reference_derivative(discr, (i,), x) for i in range(discr.dim)) intx = sum(actx.np.sum(xi * wi) for xi, wi in zip(x, discr.quad_weights())) assert gradx is not None assert intx is not None # }}} return u # }}} # {{{ evolve maxiter = int(tmax // timestep) + 1 dt = tmax / maxiter + 1.0e-15 x = thaw(discr0.nodes(), actx) t = 0.0 if visualize: filename = f"moving-geometry-{0:09d}.vtu" plot_solution(actx, vis, filename, discr0, t, x) for n in range(1, maxiter + 1): x = advance(actx, dt, t, x, source) t += dt if visualize: discr = reconstruct_discr_from_nodes(actx, discr0, x) vis = make_visualizer(actx, discr, vis_order=target_order) # vis = vis.copy_with_same_connectivity(actx, discr) filename = f"moving-geometry-{n:09d}.vtu" plot_solution(actx, vis, filename, discr, t, x) logger.info("[%05d/%05d] t = %.5e/%.5e dt = %.5e", n, maxiter, t, tmax, dt)
pt.ylim([-1.5, 1.5]) filename = "test_proxy_generator_{}d_{:04}.png".format( ambient_dim, i) pt.savefig(filename, dpi=300) pt.clf() else: from meshmode.discretization.visualization import make_visualizer from meshmode.mesh.processing import ( # noqa affine_map, merge_disjoint_meshes) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from meshmode.mesh.generation import generate_icosphere ref_mesh = generate_icosphere(1, generator.nproxy) # NOTE: this does not plot the actual proxy points for i in range(srcindices.nblocks): mesh = affine_map(ref_mesh, A=(pxyradii[i] * np.eye(ambient_dim)), b=pxycenters[:, i].reshape(-1)) mesh = merge_disjoint_meshes([mesh, density_discr.mesh]) discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(10)) vis = make_visualizer(actx, discr, 10) filename = "test_proxy_generator_{}d_{:04}.vtu".format( ambient_dim, i) vis.write_vtk_file(filename, [])
def test_harmonic_extension_exterior_3d(ctx_factory): dim = 3 # noqa: F841 mesh_order = 8 fmm_order = 3 bdry_quad_order = mesh_order bdry_ovsmp_quad_order = 4 * bdry_quad_order qbx_order = mesh_order cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import generate_icosphere from meshmode.mesh.refinement import refine_uniformly radius = 2.5 base_mesh = generate_icosphere(radius, order=mesh_order) mesh = refine_uniformly(base_mesh, 1) pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import QBXLayerPotentialSource qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order, ).with_refinement() density_discr = qbx.density_discr ntgts = 200 rho = np.random.rand(ntgts) * 3 + radius + 0.05 theta = np.random.rand(ntgts) * 2 * np.pi phi = (np.random.rand(ntgts) - 0.5) * np.pi nodes = density_discr.nodes().with_queue(queue) source = np.array([0, 1, 2]) def test_func(x): return 1.0 / la.norm(x.get() - source[:, None], axis=0) f = cl.array.to_device(queue, test_func(nodes)) targets = cl.array.to_device( queue, np.array([ rho * np.cos(phi) * np.cos(theta), rho * np.cos(phi) * np.sin(theta), rho * np.sin(phi) ])) exact_f = test_func(targets) ext_f, _ = compute_harmonic_extension(queue, PointsTarget(targets), qbx, density_discr, f, loc_sign=1) assert np.linalg.norm(exact_f - ext_f.get()) < 1e-3 * np.linalg.norm(exact_f)
def test_proxy_generator(ctx_factory, ndim, factor, visualize=False): ctx = ctx_factory() queue = cl.CommandQueue(ctx) qbx = _build_qbx_discr(queue, ndim=ndim) srcindices = _build_block_index(qbx.density_discr, factor=factor) from pytential.linalg.proxy import ProxyGenerator generator = ProxyGenerator(qbx, ratio=1.1) proxies, pxyranges, pxycenters, pxyradii = generator(queue, srcindices) proxies = np.vstack([p.get() for p in proxies]) pxyranges = pxyranges.get() pxycenters = np.vstack([c.get() for c in pxycenters]) pxyradii = pxyradii.get() for i in range(srcindices.nblocks): ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]] r = la.norm(proxies[:, ipxy] - pxycenters[:, i].reshape(-1, 1), axis=0) assert np.allclose(r - pxyradii[i], 0.0, atol=1.0e-14) srcindices = srcindices.get(queue) if visualize: if qbx.ambient_dim == 2: import matplotlib.pyplot as pt density_nodes = qbx.density_discr.nodes().get(queue) ci = bind(qbx, sym.expansion_centers(qbx.ambient_dim, -1))(queue) ci = np.vstack([c.get(queue) for c in ci]) ce = bind(qbx, sym.expansion_centers(qbx.ambient_dim, +1))(queue) ce = np.vstack([c.get(queue) for c in ce]) r = bind(qbx, sym.expansion_radii(qbx.ambient_dim))(queue).get() for i in range(srcindices.nblocks): isrc = srcindices.block_indices(i) ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]] pt.figure(figsize=(10, 8)) axis = pt.gca() for j in isrc: c = pt.Circle(ci[:, j], r[j], color='k', alpha=0.1) axis.add_artist(c) c = pt.Circle(ce[:, j], r[j], color='k', alpha=0.1) axis.add_artist(c) pt.plot(density_nodes[0], density_nodes[1], 'ko', ms=2.0, alpha=0.5) pt.plot(density_nodes[0, srcindices.indices], density_nodes[1, srcindices.indices], 'o', ms=2.0) pt.plot(density_nodes[0, isrc], density_nodes[1, isrc], 'o', ms=2.0) pt.plot(proxies[0, ipxy], proxies[1, ipxy], 'o', ms=2.0) pt.xlim([-1.5, 1.5]) pt.ylim([-1.5, 1.5]) filename = "test_proxy_generator_{}d_{:04}.png".format(ndim, i) pt.savefig(filename, dpi=300) pt.clf() else: from meshmode.discretization.visualization import make_visualizer from meshmode.mesh.processing import ( # noqa affine_map, merge_disjoint_meshes) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from meshmode.mesh.generation import generate_icosphere ref_mesh = generate_icosphere(1, generator.nproxy) # NOTE: this does not plot the actual proxy points for i in range(srcindices.nblocks): mesh = affine_map(ref_mesh, A=(pxyradii[i] * np.eye(ndim)), b=pxycenters[:, i].reshape(-1)) mesh = merge_disjoint_meshes([mesh, qbx.density_discr.mesh]) discr = Discretization( ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(10)) vis = make_visualizer(queue, discr, 10) filename = "test_proxy_generator_{}d_{:04}.vtu".format(ndim, i) vis.write_vtk_file(filename, [])
def test_sphere_eigenvalues(ctx_getter, mode_m, mode_n, qbx_order, fmm_backend): logging.basicConfig(level=logging.INFO) special = pytest.importorskip("scipy.special") cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) target_order = 8 from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource from pytools.convergence import EOCRecorder s_eoc_rec = EOCRecorder() d_eoc_rec = EOCRecorder() sp_eoc_rec = EOCRecorder() dp_eoc_rec = EOCRecorder() def rel_err(comp, ref): return ( norm(density_discr, queue, comp - ref) / norm(density_discr, queue, ref)) for nrefinements in [0, 1]: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.mesh.refinement import Refiner refiner = Refiner(mesh) for i in range(nrefinements): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx, _ = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order, fmm_order=6, fmm_backend=fmm_backend, ).with_refinement() density_discr = qbx.density_discr nodes = density_discr.nodes().with_queue(queue) r = cl.clmath.sqrt(nodes[0]**2 + nodes[1]**2 + nodes[2]**2) phi = cl.clmath.acos(nodes[2]/r) theta = cl.clmath.atan2(nodes[0], nodes[1]) ymn = cl.array.to_device(queue, special.sph_harm(mode_m, mode_n, theta.get(), phi.get())) from sumpy.kernel import LaplaceKernel lap_knl = LaplaceKernel(3) # {{{ single layer s_sigma_op = bind(qbx, sym.S(lap_knl, sym.var("sigma"))) s_sigma = s_sigma_op(queue=queue, sigma=ymn) s_eigval = 1/(2*mode_n + 1) s_eoc_rec.add_data_point(qbx.h_max, rel_err(s_sigma, s_eigval*ymn)) # }}} # {{{ double layer d_sigma_op = bind(qbx, sym.D(lap_knl, sym.var("sigma"))) d_sigma = d_sigma_op(queue=queue, sigma=ymn) d_eigval = -1/(2*(2*mode_n + 1)) d_eoc_rec.add_data_point(qbx.h_max, rel_err(d_sigma, d_eigval*ymn)) # }}} # {{{ S' sp_sigma_op = bind(qbx, sym.Sp(lap_knl, sym.var("sigma"))) sp_sigma = sp_sigma_op(queue=queue, sigma=ymn) sp_eigval = -1/(2*(2*mode_n + 1)) sp_eoc_rec.add_data_point(qbx.h_max, rel_err(sp_sigma, sp_eigval*ymn)) # }}} # {{{ D' dp_sigma_op = bind(qbx, sym.Dp(lap_knl, sym.var("sigma"))) dp_sigma = dp_sigma_op(queue=queue, sigma=ymn) dp_eigval = -(mode_n*(mode_n+1))/(2*mode_n + 1) dp_eoc_rec.add_data_point(qbx.h_max, rel_err(dp_sigma, dp_eigval*ymn)) # }}} print("Errors for S:") print(s_eoc_rec) required_order = qbx_order + 1 assert s_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D:") print(d_eoc_rec) required_order = qbx_order assert d_eoc_rec.order_estimate() > required_order - 0.5 print("Errors for S':") print(sp_eoc_rec) required_order = qbx_order assert sp_eoc_rec.order_estimate() > required_order - 1.5 print("Errors for D':") print(dp_eoc_rec) required_order = qbx_order assert dp_eoc_rec.order_estimate() > required_order - 1.5
def test_proxy_generator(ctx_factory, ndim, factor, visualize=False): ctx = ctx_factory() queue = cl.CommandQueue(ctx) qbx = _build_qbx_discr(queue, ndim=ndim) srcindices = _build_block_index(qbx.density_discr, method='nodes', factor=factor) from pytential.linalg.proxy import ProxyGenerator generator = ProxyGenerator(qbx, ratio=1.1) proxies, pxyranges, pxycenters, pxyradii = generator(queue, srcindices) proxies = np.vstack([p.get() for p in proxies]) pxyranges = pxyranges.get() pxycenters = np.vstack([c.get() for c in pxycenters]) pxyradii = pxyradii.get() for i in range(srcindices.nblocks): ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]] r = la.norm(proxies[:, ipxy] - pxycenters[:, i].reshape(-1, 1), axis=0) assert np.allclose(r - pxyradii[i], 0.0, atol=1.0e-14) srcindices = srcindices.get(queue) if visualize: if qbx.ambient_dim == 2: import matplotlib.pyplot as pt from pytential.qbx.utils import get_centers_on_side density_nodes = qbx.density_discr.nodes().get(queue) ci = get_centers_on_side(qbx, -1) ci = np.vstack([c.get(queue) for c in ci]) ce = get_centers_on_side(qbx, +1) ce = np.vstack([c.get(queue) for c in ce]) r = qbx._expansion_radii("nsources").get(queue) for i in range(srcindices.nblocks): isrc = srcindices.block_indices(i) ipxy = np.s_[pxyranges[i]:pxyranges[i + 1]] pt.figure(figsize=(10, 8)) axis = pt.gca() for j in isrc: c = pt.Circle(ci[:, j], r[j], color='k', alpha=0.1) axis.add_artist(c) c = pt.Circle(ce[:, j], r[j], color='k', alpha=0.1) axis.add_artist(c) pt.plot(density_nodes[0], density_nodes[1], 'ko', ms=2.0, alpha=0.5) pt.plot(density_nodes[0, srcindices.indices], density_nodes[1, srcindices.indices], 'o', ms=2.0) pt.plot(density_nodes[0, isrc], density_nodes[1, isrc], 'o', ms=2.0) pt.plot(proxies[0, ipxy], proxies[1, ipxy], 'o', ms=2.0) pt.xlim([-1.5, 1.5]) pt.ylim([-1.5, 1.5]) filename = "test_proxy_generator_{}d_{:04}.png".format(ndim, i) pt.savefig(filename, dpi=300) pt.clf() else: from meshmode.discretization.visualization import make_visualizer from meshmode.mesh.processing import ( # noqa affine_map, merge_disjoint_meshes) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from meshmode.mesh.generation import generate_icosphere ref_mesh = generate_icosphere(1, generator.nproxy) # NOTE: this does not plot the actual proxy points for i in range(srcindices.nblocks): mesh = affine_map(ref_mesh, A=(pxyradii[i] * np.eye(ndim)), b=pxycenters[:, i].reshape(-1)) mesh = merge_disjoint_meshes([mesh, qbx.density_discr.mesh]) discr = Discretization(ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(10)) vis = make_visualizer(queue, discr, 10) filename = "test_proxy_generator_{}d_{:04}.vtu".format(ndim, i) if os.path.isfile(filename): os.remove(filename) vis.write_vtk_file(filename, [])
def main(ctx_factory, dim=2, order=4, use_quad=False, visualize=False): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext( queue, allocator=cl_tools.MemoryPool(cl_tools.ImmediateAllocator(queue)), force_device_scalars=True, ) # {{{ parameters # sphere radius radius = 1.0 # sphere resolution resolution = 64 if dim == 2 else 1 # final time final_time = np.pi # flux flux_type = "lf" # }}} # {{{ discretization if dim == 2: from meshmode.mesh.generation import make_curve_mesh, ellipse mesh = make_curve_mesh( lambda t: radius * ellipse(1.0, t), np.linspace(0.0, 1.0, resolution + 1), order) elif dim == 3: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(radius, order=4 * order, uniform_refinement_rounds=resolution) else: raise ValueError("unsupported dimension") discr_tag_to_group_factory = {} if use_quad: qtag = dof_desc.DISCR_TAG_QUAD else: qtag = None from meshmode.discretization.poly_element import \ default_simplex_group_factory, \ QuadratureSimplexGroupFactory discr_tag_to_group_factory[dof_desc.DISCR_TAG_BASE] = \ default_simplex_group_factory(base_dim=dim-1, order=order) if use_quad: discr_tag_to_group_factory[qtag] = \ QuadratureSimplexGroupFactory(order=4*order) from grudge import DiscretizationCollection dcoll = DiscretizationCollection( actx, mesh, discr_tag_to_group_factory=discr_tag_to_group_factory ) volume_discr = dcoll.discr_from_dd(dof_desc.DD_VOLUME) logger.info("ndofs: %d", volume_discr.ndofs) logger.info("nelements: %d", volume_discr.mesh.nelements) # }}} # {{{ Surface advection operator # velocity field x = thaw(dcoll.nodes(), actx) c = make_obj_array([-x[1], x[0], 0.0])[:dim] def f_initial_condition(x): return x[0] from grudge.models.advection import SurfaceAdvectionOperator adv_operator = SurfaceAdvectionOperator( dcoll, c, flux_type=flux_type, quad_tag=qtag ) u0 = f_initial_condition(x) def rhs(t, u): return adv_operator.operator(t, u) # check velocity is tangential from grudge.geometry import normal surf_normal = normal(actx, dcoll, dd=dof_desc.DD_VOLUME) error = op.norm(dcoll, c.dot(surf_normal), 2) logger.info("u_dot_n: %.5e", error) # }}} # {{{ time stepping # FIXME: dt estimate is not necessarily valid for surfaces dt = actx.to_numpy( 0.45 * adv_operator.estimate_rk4_timestep(actx, dcoll, fields=u0)) nsteps = int(final_time // dt) + 1 logger.info("dt: %.5e", dt) logger.info("nsteps: %d", nsteps) from grudge.shortcuts import set_up_rk4 dt_stepper = set_up_rk4("u", dt, u0, rhs) plot = Plotter(actx, dcoll, order, visualize=visualize) norm_u = actx.to_numpy(op.norm(dcoll, u0, 2)) step = 0 event = dt_stepper.StateComputed(0.0, 0, 0, u0) plot(event, "fld-surface-%04d" % 0) if visualize and dim == 3: from grudge.shortcuts import make_visualizer vis = make_visualizer(dcoll) vis.write_vtk_file( "fld-surface-velocity.vtu", [ ("u", c), ("n", surf_normal) ], overwrite=True ) df = dof_desc.DOFDesc(FACE_RESTR_INTERIOR) face_discr = dcoll.discr_from_dd(df) face_normal = thaw(dcoll.normal(dd=df), actx) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, face_discr) vis.write_vtk_file("fld-surface-face-normals.vtu", [ ("n", face_normal) ], overwrite=True) for event in dt_stepper.run(t_end=final_time, max_steps=nsteps + 1): if not isinstance(event, dt_stepper.StateComputed): continue step += 1 if step % 10 == 0: norm_u = actx.to_numpy(op.norm(dcoll, event.state_component, 2)) plot(event, "fld-surface-%04d" % step) logger.info("[%04d] t = %.5f |u| = %.5e", step, event.t, norm_u) # NOTE: These are here to ensure the solution is bounded for the # time interval specified assert norm_u < 3
def main(): # cl.array.to_device(queue, numpy_array) from meshmode.mesh.io import generate_gmsh, FileSource from meshmode.mesh.generation import generate_icosphere from meshmode.mesh.refinement import Refiner mesh = generate_icosphere(1,target_order) refinement_increment = 1 refiner = Refiner(mesh) for i in range(refinement_increment): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) print("%d elements" % mesh.nelements) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5*(bbox_min+bbox_max) bbox_size = max(bbox_max-bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4*target_order, qbx_order, fmm_order=False, fmm_backend="fmmlib") from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator pde_op = MuellerAugmentedMFIEOperator( omega=1.0, epss=[1.0, 1.0], mus=[1.0, 1.0], ) from pytential import bind, sym unk = pde_op.make_unknown("sigma") sym_operator = pde_op.operator(unk) sym_rhs = pde_op.rhs( sym.make_sym_vector("Einc", 3), sym.make_sym_vector("Hinc", 3)) sym_repr = pde_op.representation(1, unk) if 1: expr = sym_repr print(sym.pretty(expr)) print("#"*80) from pytential.target import PointsTarget tgt_points=np.zeros((3,1)) tgt_points[0,0] = 100 tgt_points[1,0] = -200 tgt_points[2,0] = 300 bound_op = bind((qbx, PointsTarget(tgt_points)), expr) print(bound_op.code) if 1: def green3e(x,y,z,source,strength,k): # electric field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # E = (I + Hess)(exp(ikr)/r) dot (strength) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout = np.exp(1j*k*rr)/rr evec = fout*strength qmat = np.zeros((3,3),dtype=np.complex128) qmat[0,0]=(2*dx**2-dy**2-dz**2)*(1-1j*k*rr) qmat[1,1]=(2*dy**2-dz**2-dx**2)*(1-1j*k*rr) qmat[2,2]=(2*dz**2-dx**2-dy**2)*(1-1j*k*rr) qmat[0,0]=qmat[0,0]+(-k**2*dx**2*rr**2) qmat[1,1]=qmat[1,1]+(-k**2*dy**2*rr**2) qmat[2,2]=qmat[2,2]+(-k**2*dz**2*rr**2) qmat[0,1]=(3-k**2*rr**2-3*1j*k*rr)*(dx*dy) qmat[1,2]=(3-k**2*rr**2-3*1j*k*rr)*(dy*dz) qmat[2,0]=(3-k**2*rr**2-3*1j*k*rr)*(dz*dx) qmat[1,0]=qmat[0,1] qmat[2,1]=qmat[1,2] qmat[0,2]=qmat[2,0] fout=np.exp(1j*k*rr)/rr**5/k**2 fvec = fout*np.dot(qmat,strength) evec = evec + fvec return evec def green3m(x,y,z,source,strength,k): # magnetic field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # H = curl((I + Hess)(exp(ikr)/r) dot (strength)) = # strength \cross \grad (exp(ikr)/r) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout=(1-1j*k*rr)*np.exp(1j*k*rr)/rr**3 fvec = np.zeros(3,dtype=np.complex128) fvec[0] = fout*dx fvec[1] = fout*dy fvec[2] = fout*dz hvec = np.cross(strength,fvec) return hvec def dipole3e(x,y,z,source,strength,k): # # evalaute electric and magnetic field due # to monochromatic electric dipole located at "source" # with intensity "strength" evec = green3e(x,y,z,source,strength,k) evec = evec*1j*k hvec = green3m(x,y,z,source,strength,k) # print(hvec) # print(strength) return evec,hvec def dipole3m(x,y,z,source,strength,k): # # evalaute electric and magnetic field due # to monochromatic magnetic dipole located at "source" # with intensity "strength" evec = green3m(x,y,z,source,strength,k) hvec = green3e(x,y,z,source,strength,k) hvec = -hvec*1j*k return evec,hvec def dipole3eall(x,y,z,sources,strengths,k): ns = len(strengths) evec = np.zeros(3,dtype=np.complex128) hvec = np.zeros(3,dtype=np.complex128) for i in range(ns): evect,hvect = dipole3e(x,y,z,sources[i],strengths[i],k) evec = evec + evect hvec = hvec + hvect nodes = density_discr.nodes().with_queue(queue).get() source = [0.01,-0.03,0.02] # source = cl.array.to_device(queue,np.zeros(3)) # source[0] = 0.01 # source[1] =-0.03 # source[2] = 0.02 strength = np.ones(3) # evec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) # hvec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) evec = np.zeros((3,len(nodes[0])),dtype=np.complex128) hvec = np.zeros((3,len(nodes[0])),dtype=np.complex128) for i in range(len(nodes[0])): evec[:,i],hvec[:,i] = dipole3e(nodes[0][i],nodes[1][i],nodes[2][i],source,strength,k) print(np.shape(hvec)) print(type(evec)) print(type(hvec)) evec = cl.array.to_device(queue,evec) hvec = cl.array.to_device(queue,hvec) bvp_rhs = bind(qbx, sym_rhs)(queue,Einc=evec,Hinc=hvec) print(np.shape(bvp_rhs)) print(type(bvp_rhs)) # print(bvp_rhs) 1/-1 bound_op = bind(qbx, sym_operator) from pytential.solve import gmres if 1: gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) sigma = gmres_result.solution fld_at_tgt = bind((qbx, PointsTarget(tgt_points)), sym_repr)(queue, sigma=sigma,k=k) fld_at_tgt = np.array([ fi.get() for fi in fld_at_tgt ]) print(fld_at_tgt) fld_exact_e,fld_exact_h = dipole3e(tgt_points[0,0],tgt_points[1,0],tgt_points[2,0],source,strength,k) print(fld_exact_e) print(fld_exact_h) 1/0 # }}} #mlab.figure(bgcolor=(1, 1, 1)) if 1: from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, target_order) bdry_normals = bind(density_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("source.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ]) fplot = FieldPlotter(bbox_center, extent=2*bbox_size, npoints=(150, 150, 1)) qbx_stick_out = qbx.copy(target_stick_out_factor=0.1) from pytential.target import PointsTarget from pytential.qbx import QBXTargetAssociationFailedException rho_sym = sym.var("rho") try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(fplot.points)), sym.make_obj_array([ sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None), sym.d_dx(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dy(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dz(3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), ]) )(queue, jt=jt, rho=rho, k=k) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed_targets", e.failed_target_flags.get(queue)) ]) raise fld_in_vol = sym.make_obj_array( [fiv.get() for fiv in fld_in_vol]) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("potential", fld_in_vol[0]), ("grad", fld_in_vol[1:]), ] )
def run_exterior_stokes( ctx_factory, *, ambient_dim, target_order, qbx_order, resolution, fmm_order=False, # FIXME: FMM is slower than direct evaluation source_ovsmp=None, radius=1.5, mu=1.0, visualize=False, _target_association_tolerance=0.05, _expansions_in_tree_have_extent=True): cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ geometry if source_ovsmp is None: source_ovsmp = 4 if ambient_dim == 2 else 8 places = {} if ambient_dim == 2: from meshmode.mesh.generation import make_curve_mesh, ellipse mesh = make_curve_mesh(lambda t: radius * ellipse(1.0, t), np.linspace(0.0, 1.0, resolution + 1), target_order) elif ambient_dim == 3: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(radius, target_order + 1, uniform_refinement_rounds=resolution) else: raise ValueError(f"unsupported dimension: {ambient_dim}") pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( pre_density_discr, fine_order=source_ovsmp * target_order, qbx_order=qbx_order, fmm_order=fmm_order, target_association_tolerance=_target_association_tolerance, _expansions_in_tree_have_extent=_expansions_in_tree_have_extent) places["source"] = qbx from extra_int_eq_data import make_source_and_target_points point_source, point_target = make_source_and_target_points( side=+1, inner_radius=0.5 * radius, outer_radius=2.0 * radius, ambient_dim=ambient_dim, ) places["point_source"] = point_source places["point_target"] = point_target if visualize: from sumpy.visualization import make_field_plotter_from_bbox from meshmode.mesh.processing import find_bounding_box fplot = make_field_plotter_from_bbox(find_bounding_box(mesh), h=0.1, extend_factor=1.0) mask = np.linalg.norm(fplot.points, ord=2, axis=0) > (radius + 0.25) from pytential.target import PointsTarget plot_target = PointsTarget(fplot.points[:, mask].copy()) places["plot_target"] = plot_target del mask places = GeometryCollection(places, auto_where="source") density_discr = places.get_discretization("source") logger.info("ndofs: %d", density_discr.ndofs) logger.info("nelements: %d", density_discr.mesh.nelements) # }}} # {{{ symbolic sym_normal = sym.make_sym_vector("normal", ambient_dim) sym_mu = sym.var("mu") if ambient_dim == 2: from pytential.symbolic.stokes import HsiaoKressExteriorStokesOperator sym_omega = sym.make_sym_vector("omega", ambient_dim) op = HsiaoKressExteriorStokesOperator(omega=sym_omega) elif ambient_dim == 3: from pytential.symbolic.stokes import HebekerExteriorStokesOperator op = HebekerExteriorStokesOperator() else: assert False sym_sigma = op.get_density_var("sigma") sym_bc = op.get_density_var("bc") sym_op = op.operator(sym_sigma, normal=sym_normal, mu=sym_mu) sym_rhs = op.prepare_rhs(sym_bc, mu=mu) sym_velocity = op.velocity(sym_sigma, normal=sym_normal, mu=sym_mu) sym_source_pot = op.stokeslet.apply(sym_sigma, sym_mu, qbx_forced_limit=None) # }}} # {{{ boundary conditions normal = bind(places, sym.normal(ambient_dim).as_vector())(actx) np.random.seed(42) charges = make_obj_array([ actx.from_numpy(np.random.randn(point_source.ndofs)) for _ in range(ambient_dim) ]) if ambient_dim == 2: total_charge = make_obj_array([actx.np.sum(c) for c in charges]) omega = bind(places, total_charge * sym.Ones())(actx) if ambient_dim == 2: bc_context = {"mu": mu, "omega": omega} op_context = {"mu": mu, "omega": omega, "normal": normal} else: bc_context = {} op_context = {"mu": mu, "normal": normal} bc = bind(places, sym_source_pot, auto_where=("point_source", "source"))(actx, sigma=charges, mu=mu) rhs = bind(places, sym_rhs)(actx, bc=bc, **bc_context) bound_op = bind(places, sym_op) # }}} # {{{ solve from pytential.solve import gmres gmres_tol = 1.0e-9 result = gmres(bound_op.scipy_op(actx, "sigma", np.float64, **op_context), rhs, x0=rhs, tol=gmres_tol, progress=visualize, stall_iterations=0, hard_failure=True) sigma = result.solution # }}} # {{{ check velocity at "point_target" def rnorm2(x, y): y_norm = actx.np.linalg.norm(y.dot(y), ord=2) if y_norm < 1.0e-14: y_norm = 1.0 d = x - y return actx.np.linalg.norm(d.dot(d), ord=2) / y_norm ps_velocity = bind(places, sym_velocity, auto_where=("source", "point_target"))(actx, sigma=sigma, **op_context) ex_velocity = bind(places, sym_source_pot, auto_where=("point_source", "point_target"))(actx, sigma=charges, mu=mu) v_error = rnorm2(ps_velocity, ex_velocity) h_max = bind(places, sym.h_max(ambient_dim))(actx) logger.info("resolution %4d h_max %.5e error %.5e", resolution, h_max, v_error) # }}}} # {{{ visualize if not visualize: return h_max, v_error from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, density_discr, target_order) filename = "stokes_solution_{}d_{}_ovsmp_{}.vtu".format( ambient_dim, resolution, source_ovsmp) vis.write_vtk_file(filename, [ ("density", sigma), ("bc", bc), ("rhs", rhs), ], overwrite=True) # }}} return h_max, v_error
def test_target_specific_qbx(ctx_factory, op, helmholtz_k, qbx_order): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) target_order = 4 fmm_tol = 1e-3 from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder qbx = QBXLayerPotentialSource( pre_density_discr, 4*target_order, qbx_order=qbx_order, fmm_level_to_order=SimpleExpansionOrderFinder(fmm_tol), fmm_backend="fmmlib", _expansions_in_tree_have_extent=True, _expansion_stick_out_factor=0.9, _use_target_specific_qbx=False, ) kernel_length_scale = 5 / abs(helmholtz_k) if helmholtz_k else None places = { "qbx": qbx, "qbx_target_specific": qbx.copy(_use_target_specific_qbx=True) } from pytential.qbx.refinement import refine_geometry_collection places = GeometryCollection(places, auto_where="qbx") places = refine_geometry_collection(places, kernel_length_scale=kernel_length_scale) density_discr = places.get_discretization("qbx") from meshmode.dof_array import thaw nodes = thaw(actx, density_discr.nodes()) u_dev = actx.np.sin(nodes[0]) if helmholtz_k == 0: kernel = LaplaceKernel(3) kernel_kwargs = {} else: kernel = HelmholtzKernel(3, allow_evanescent=True) kernel_kwargs = {"k": sym.var("k")} u_sym = sym.var("u") if op == "S": op = sym.S elif op == "D": op = sym.D elif op == "Sp": op = sym.Sp else: raise ValueError("unknown operator: '%s'" % op) expr = op(kernel, u_sym, qbx_forced_limit=-1, **kernel_kwargs) from meshmode.dof_array import flatten bound_op = bind(places, expr) pot_ref = actx.to_numpy(flatten(bound_op(actx, u=u_dev, k=helmholtz_k))) bound_op = bind(places, expr, auto_where="qbx_target_specific") pot_tsqbx = actx.to_numpy(flatten(bound_op(actx, u=u_dev, k=helmholtz_k))) assert np.allclose(pot_tsqbx, pot_ref, atol=1e-13, rtol=1e-13)
def test_target_specific_qbx(ctx_getter, op, helmholtz_k, qbx_order): logging.basicConfig(level=logging.INFO) cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) target_order = 4 fmm_tol = 1e-3 from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(1, target_order) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from pytential.qbx import QBXLayerPotentialSource pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder refiner_extra_kwargs = {} if helmholtz_k != 0: refiner_extra_kwargs["kernel_length_scale"] = 5 / abs(helmholtz_k) qbx, _ = QBXLayerPotentialSource( pre_density_discr, 4 * target_order, qbx_order=qbx_order, fmm_level_to_order=SimpleExpansionOrderFinder(fmm_tol), fmm_backend="fmmlib", _expansions_in_tree_have_extent=True, _expansion_stick_out_factor=0.9, _use_target_specific_qbx=False, ).with_refinement(**refiner_extra_kwargs) density_discr = qbx.density_discr nodes = density_discr.nodes().with_queue(queue) u_dev = clmath.sin(nodes[0]) if helmholtz_k == 0: kernel = LaplaceKernel(3) kernel_kwargs = {} else: kernel = HelmholtzKernel(3, allow_evanescent=True) kernel_kwargs = {"k": sym.var("k")} u_sym = sym.var("u") if op == "S": op = sym.S elif op == "D": op = sym.D elif op == "Sp": op = sym.Sp else: raise ValueError("unknown operator: '%s'" % op) expr = op(kernel, u_sym, qbx_forced_limit=-1, **kernel_kwargs) bound_op = bind(qbx, expr) pot_ref = bound_op(queue, u=u_dev, k=helmholtz_k).get() qbx = qbx.copy(_use_target_specific_qbx=True) bound_op = bind(qbx, expr) pot_tsqbx = bound_op(queue, u=u_dev, k=helmholtz_k).get() assert np.allclose(pot_tsqbx, pot_ref, atol=1e-13, rtol=1e-13)
def main(ctx_factory, dim=2, order=4, product_tag=None, visualize=False): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ parameters # sphere radius radius = 1.0 # sphere resolution resolution = 64 if dim == 2 else 1 # cfl dt_factor = 2.0 # final time final_time = np.pi # velocity field sym_x = sym.nodes(dim) c = make_obj_array([-sym_x[1], sym_x[0], 0.0])[:dim] # flux flux_type = "lf" # }}} # {{{ discretization if dim == 2: from meshmode.mesh.generation import make_curve_mesh, ellipse mesh = make_curve_mesh(lambda t: radius * ellipse(1.0, t), np.linspace(0.0, 1.0, resolution + 1), order) elif dim == 3: from meshmode.mesh.generation import generate_icosphere mesh = generate_icosphere(radius, order=4 * order, uniform_refinement_rounds=resolution) else: raise ValueError("unsupported dimension") discr_tag_to_group_factory = {} if product_tag == "none": product_tag = None else: product_tag = dof_desc.DISCR_TAG_QUAD from meshmode.discretization.poly_element import \ PolynomialWarpAndBlendGroupFactory, \ QuadratureSimplexGroupFactory discr_tag_to_group_factory[dof_desc.DISCR_TAG_BASE] = \ PolynomialWarpAndBlendGroupFactory(order) if product_tag: discr_tag_to_group_factory[product_tag] = \ QuadratureSimplexGroupFactory(order=4*order) from grudge import DiscretizationCollection discr = DiscretizationCollection( actx, mesh, discr_tag_to_group_factory=discr_tag_to_group_factory) volume_discr = discr.discr_from_dd(dof_desc.DD_VOLUME) logger.info("ndofs: %d", volume_discr.ndofs) logger.info("nelements: %d", volume_discr.mesh.nelements) # }}} # {{{ symbolic operators def f_initial_condition(x): return x[0] from grudge.models.advection import SurfaceAdvectionOperator op = SurfaceAdvectionOperator(c, flux_type=flux_type, quad_tag=product_tag) bound_op = bind(discr, op.sym_operator()) u0 = bind(discr, f_initial_condition(sym_x))(actx, t=0) def rhs(t, u): return bound_op(actx, t=t, u=u) # check velocity is tangential sym_normal = sym.surface_normal(dim, dim=dim - 1, dd=dof_desc.DD_VOLUME).as_vector() error = bind(discr, sym.norm(2, c.dot(sym_normal)))(actx) logger.info("u_dot_n: %.5e", error) # }}} # {{{ time stepping # compute time step h_min = bind(discr, sym.h_max_from_volume(discr.ambient_dim, dim=discr.dim))(actx) dt = dt_factor * h_min / order**2 nsteps = int(final_time // dt) + 1 dt = final_time / nsteps + 1.0e-15 logger.info("dt: %.5e", dt) logger.info("nsteps: %d", nsteps) from grudge.shortcuts import set_up_rk4 dt_stepper = set_up_rk4("u", dt, u0, rhs) plot = Plotter(actx, discr, order, visualize=visualize) norm = bind(discr, sym.norm(2, sym.var("u"))) norm_u = norm(actx, u=u0) step = 0 event = dt_stepper.StateComputed(0.0, 0, 0, u0) plot(event, "fld-surface-%04d" % 0) if visualize and dim == 3: from grudge.shortcuts import make_visualizer vis = make_visualizer(discr) vis.write_vtk_file("fld-surface-velocity.vtu", [("u", bind(discr, c)(actx)), ("n", bind(discr, sym_normal)(actx))], overwrite=True) df = dof_desc.DOFDesc(FACE_RESTR_INTERIOR) face_discr = discr.connection_from_dds(dof_desc.DD_VOLUME, df).to_discr face_normal = bind( discr, sym.normal(df, face_discr.ambient_dim, dim=face_discr.dim))(actx) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, face_discr) vis.write_vtk_file("fld-surface-face-normals.vtu", [("n", face_normal)], overwrite=True) for event in dt_stepper.run(t_end=final_time, max_steps=nsteps + 1): if not isinstance(event, dt_stepper.StateComputed): continue step += 1 if step % 10 == 0: norm_u = norm(actx, u=event.state_component) plot(event, "fld-surface-%04d" % step) logger.info("[%04d] t = %.5f |u| = %.5e", step, event.t, norm_u) plot(event, "fld-surface-%04d" % step)
def main(): # cl.array.to_device(queue, numpy_array) from meshmode.mesh.io import generate_gmsh, FileSource from meshmode.mesh.generation import generate_icosphere from meshmode.mesh.refinement import Refiner mesh = generate_icosphere(1, target_order) refinement_increment = 1 refiner = Refiner(mesh) for i in range(refinement_increment): flags = np.ones(mesh.nelements, dtype=bool) refiner.refine(flags) mesh = refiner.get_current_mesh() from meshmode.mesh.processing import perform_flips # Flip elements--gmsh generates inside-out geometry. mesh = perform_flips(mesh, np.ones(mesh.nelements)) print("%d elements" % mesh.nelements) from meshmode.mesh.processing import find_bounding_box bbox_min, bbox_max = find_bounding_box(mesh) bbox_center = 0.5 * (bbox_min + bbox_max) bbox_size = max(bbox_max - bbox_min) / 2 logger.info("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) qbx = QBXLayerPotentialSource(density_discr, 4 * target_order, qbx_order, fmm_order=False, fmm_backend="fmmlib") from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator pde_op = MuellerAugmentedMFIEOperator( omega=1.0, epss=[1.0, 1.0], mus=[1.0, 1.0], ) from pytential import bind, sym unk = pde_op.make_unknown("sigma") sym_operator = pde_op.operator(unk) sym_rhs = pde_op.rhs(sym.make_sym_vector("Einc", 3), sym.make_sym_vector("Hinc", 3)) sym_repr = pde_op.representation(1, unk) if 1: expr = sym_repr print(sym.pretty(expr)) print("#" * 80) from pytential.target import PointsTarget tgt_points = np.zeros((3, 1)) tgt_points[0, 0] = 100 tgt_points[1, 0] = -200 tgt_points[2, 0] = 300 bound_op = bind((qbx, PointsTarget(tgt_points)), expr) print(bound_op.code) if 1: def green3e(x, y, z, source, strength, k): # electric field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # E = (I + Hess)(exp(ikr)/r) dot (strength) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout = np.exp(1j * k * rr) / rr evec = fout * strength qmat = np.zeros((3, 3), dtype=np.complex128) qmat[0, 0] = (2 * dx**2 - dy**2 - dz**2) * (1 - 1j * k * rr) qmat[1, 1] = (2 * dy**2 - dz**2 - dx**2) * (1 - 1j * k * rr) qmat[2, 2] = (2 * dz**2 - dx**2 - dy**2) * (1 - 1j * k * rr) qmat[0, 0] = qmat[0, 0] + (-k**2 * dx**2 * rr**2) qmat[1, 1] = qmat[1, 1] + (-k**2 * dy**2 * rr**2) qmat[2, 2] = qmat[2, 2] + (-k**2 * dz**2 * rr**2) qmat[0, 1] = (3 - k**2 * rr**2 - 3 * 1j * k * rr) * (dx * dy) qmat[1, 2] = (3 - k**2 * rr**2 - 3 * 1j * k * rr) * (dy * dz) qmat[2, 0] = (3 - k**2 * rr**2 - 3 * 1j * k * rr) * (dz * dx) qmat[1, 0] = qmat[0, 1] qmat[2, 1] = qmat[1, 2] qmat[0, 2] = qmat[2, 0] fout = np.exp(1j * k * rr) / rr**5 / k**2 fvec = fout * np.dot(qmat, strength) evec = evec + fvec return evec def green3m(x, y, z, source, strength, k): # magnetic field corresponding to dyadic green's function # due to monochromatic electric dipole located at "source". # "strength" is the the intensity of the dipole. # H = curl((I + Hess)(exp(ikr)/r) dot (strength)) = # strength \cross \grad (exp(ikr)/r) # dx = x - source[0] dy = y - source[1] dz = z - source[2] rr = np.sqrt(dx**2 + dy**2 + dz**2) fout = (1 - 1j * k * rr) * np.exp(1j * k * rr) / rr**3 fvec = np.zeros(3, dtype=np.complex128) fvec[0] = fout * dx fvec[1] = fout * dy fvec[2] = fout * dz hvec = np.cross(strength, fvec) return hvec def dipole3e(x, y, z, source, strength, k): # # evalaute electric and magnetic field due # to monochromatic electric dipole located at "source" # with intensity "strength" evec = green3e(x, y, z, source, strength, k) evec = evec * 1j * k hvec = green3m(x, y, z, source, strength, k) # print(hvec) # print(strength) return evec, hvec def dipole3m(x, y, z, source, strength, k): # # evalaute electric and magnetic field due # to monochromatic magnetic dipole located at "source" # with intensity "strength" evec = green3m(x, y, z, source, strength, k) hvec = green3e(x, y, z, source, strength, k) hvec = -hvec * 1j * k return evec, hvec def dipole3eall(x, y, z, sources, strengths, k): ns = len(strengths) evec = np.zeros(3, dtype=np.complex128) hvec = np.zeros(3, dtype=np.complex128) for i in range(ns): evect, hvect = dipole3e(x, y, z, sources[i], strengths[i], k) evec = evec + evect hvec = hvec + hvect nodes = density_discr.nodes().with_queue(queue).get() source = [0.01, -0.03, 0.02] # source = cl.array.to_device(queue,np.zeros(3)) # source[0] = 0.01 # source[1] =-0.03 # source[2] = 0.02 strength = np.ones(3) # evec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) # hvec = cl.array.to_device(queue,np.zeros((3,len(nodes[0])),dtype=np.complex128)) evec = np.zeros((3, len(nodes[0])), dtype=np.complex128) hvec = np.zeros((3, len(nodes[0])), dtype=np.complex128) for i in range(len(nodes[0])): evec[:, i], hvec[:, i] = dipole3e(nodes[0][i], nodes[1][i], nodes[2][i], source, strength, k) print(np.shape(hvec)) print(type(evec)) print(type(hvec)) evec = cl.array.to_device(queue, evec) hvec = cl.array.to_device(queue, hvec) bvp_rhs = bind(qbx, sym_rhs)(queue, Einc=evec, Hinc=hvec) print(np.shape(bvp_rhs)) print(type(bvp_rhs)) # print(bvp_rhs) 1 / -1 bound_op = bind(qbx, sym_operator) from pytential.solve import gmres if 1: gmres_result = gmres(bound_op.scipy_op(queue, "sigma", dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) sigma = gmres_result.solution fld_at_tgt = bind((qbx, PointsTarget(tgt_points)), sym_repr)(queue, sigma=sigma, k=k) fld_at_tgt = np.array([fi.get() for fi in fld_at_tgt]) print(fld_at_tgt) fld_exact_e, fld_exact_h = dipole3e(tgt_points[0, 0], tgt_points[1, 0], tgt_points[2, 0], source, strength, k) print(fld_exact_e) print(fld_exact_h) 1 / 0 # }}} #mlab.figure(bgcolor=(1, 1, 1)) if 1: from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, target_order) bdry_normals = bind(density_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("source.vtu", [ ("sigma", sigma), ("bdry_normals", bdry_normals), ]) fplot = FieldPlotter(bbox_center, extent=2 * bbox_size, npoints=(150, 150, 1)) qbx_stick_out = qbx.copy(target_stick_out_factor=0.1) from pytential.target import PointsTarget from pytential.qbx import QBXTargetAssociationFailedException rho_sym = sym.var("rho") try: fld_in_vol = bind((qbx_stick_out, PointsTarget(fplot.points)), sym.make_obj_array([ sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None), sym.d_dx( 3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dy( 3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), sym.d_dz( 3, sym.S(pde_op.kernel, rho_sym, k=sym.var("k"), qbx_forced_limit=None)), ]))(queue, jt=jt, rho=rho, k=k) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [("failed_targets", e.failed_target_flags.get(queue))]) raise fld_in_vol = sym.make_obj_array([fiv.get() for fiv in fld_in_vol]) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("potential.vts", [ ("potential", fld_in_vol[0]), ("grad", fld_in_vol[1:]), ])