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 check_sufficient_source_quadrature_resolution( self, lpot_source, tree, peer_lists, refine_flags, debug, wait_for=None): # 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: npanels_to_refine_prev = cl.array.sum(refine_flags).get() found_panel_to_refine = cl.array.zeros(self.queue, 1, np.int32) found_panel_to_refine.finish() from pytential import bind, sym source_danger_zone_radii_by_panel = bind(lpot_source, sym._source_danger_zone_radii( lpot_source.ambient_dim, dofdesc=sym.GRANULARITY_ELEMENT))(self.queue) 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_panel_to_source_starts, tree.qbx_user_source_slice.start, tree.qbx_user_center_slice.start, tree.sorted_target_ids, source_danger_zone_radii_by_panel, tree.nqbxpanels, refine_flags, found_panel_to_refine, *tree.sources), range=slice(tree.nqbxsources), queue=self.queue, wait_for=wait_for) cl.wait_for_events([evt]) if debug: npanels_to_refine = cl.array.sum(refine_flags).get() if npanels_to_refine > npanels_to_refine_prev: logger.debug("refiner: found {} panel(s) to refine".format( npanels_to_refine - npanels_to_refine_prev)) return found_panel_to_refine.get()[0] == 1
def run_source_refinement_test(ctx_factory, mesh, order, helmholtz_k=None, visualize=False): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) # {{{ initial geometry from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) discr = Discretization(actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(order)) lpot_source = QBXLayerPotentialSource( discr, qbx_order=order, # not used in refinement fine_order=order) places = GeometryCollection(lpot_source) # }}} # {{{ refined geometry kernel_length_scale = 5 / helmholtz_k if helmholtz_k else None expansion_disturbance_tolerance = 0.025 from pytential.qbx.refinement import refine_geometry_collection places = refine_geometry_collection( places, kernel_length_scale=kernel_length_scale, expansion_disturbance_tolerance=expansion_disturbance_tolerance, visualize=visualize) # }}} dd = places.auto_source stage1_density_discr = places.get_discretization(dd.geometry) from meshmode.dof_array import thaw stage1_density_nodes = dof_array_to_numpy( actx, thaw(actx, stage1_density_discr.nodes())) quad_stage2_density_discr = places.get_discretization( dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2) quad_stage2_density_nodes = dof_array_to_numpy( actx, thaw(actx, quad_stage2_density_discr.nodes())) int_centers = dof_array_to_numpy( actx, bind(places, sym.expansion_centers(lpot_source.ambient_dim, -1))(actx)) ext_centers = dof_array_to_numpy( actx, bind(places, sym.expansion_centers(lpot_source.ambient_dim, +1))(actx)) expansion_radii = dof_array_to_numpy( actx, bind(places, sym.expansion_radii(lpot_source.ambient_dim))(actx)) dd = dd.copy(granularity=sym.GRANULARITY_ELEMENT) source_danger_zone_radii = dof_array_to_numpy( actx, bind( places, sym._source_danger_zone_radii(lpot_source.ambient_dim, dofdesc=dd.to_stage2()))(actx)) quad_res = dof_array_to_numpy( actx, bind(places, sym._quad_resolution(lpot_source.ambient_dim, dofdesc=dd))(actx)) # {{{ check if satisfying criteria def check_disk_undisturbed_by_sources(centers_panel, sources_panel): if centers_panel.element_nr == sources_panel.element_nr: # Same panel return my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = stage1_density_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # A center cannot be closer to another panel than to its originating # panel. rad = expansion_radii[centers_panel.discr_slice] assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \ (dist, rad, centers_panel.element_nr, sources_panel.element_nr) def check_sufficient_quadrature_resolution(centers_panel, sources_panel): dz_radius = source_danger_zone_radii[sources_panel.element_nr] my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = quad_stage2_density_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # The quadrature contribution from each panel is as accurate # as from the center's own source panel. assert dist >= dz_radius, \ (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr) def check_quad_res_to_helmholtz_k_ratio(panel): # Check wavenumber to panel size ratio. assert quad_res[panel.element_nr] * helmholtz_k <= 5 for i, panel_1 in enumerate(iter_elements(stage1_density_discr)): for panel_2 in iter_elements(stage1_density_discr): check_disk_undisturbed_by_sources(panel_1, panel_2) for panel_2 in iter_elements(quad_stage2_density_discr): check_sufficient_quadrature_resolution(panel_1, panel_2) if helmholtz_k is not None: check_quad_res_to_helmholtz_k_ratio(panel_1)
def run_source_refinement_test(ctx_factory, mesh, order, helmholtz_k=None): cl_ctx = ctx_factory() queue = cl.CommandQueue(cl_ctx) from meshmode.discretization import Discretization from meshmode.discretization.poly_element import ( InterpolatoryQuadratureSimplexGroupFactory) factory = InterpolatoryQuadratureSimplexGroupFactory(order) discr = Discretization(cl_ctx, mesh, factory) from pytential.qbx.refinement import (RefinerCodeContainer, refine_for_global_qbx) from pytential.qbx.utils import TreeCodeContainer lpot_source = QBXLayerPotentialSource( discr, qbx_order=order, # not used in refinement fine_order=order) del discr expansion_disturbance_tolerance = 0.025 refiner_extra_kwargs = { "expansion_disturbance_tolerance": expansion_disturbance_tolerance, } if helmholtz_k is not None: refiner_extra_kwargs["kernel_length_scale"] = 5 / helmholtz_k lpot_source, conn = refine_for_global_qbx( lpot_source, RefinerCodeContainer(cl_ctx, TreeCodeContainer(cl_ctx)).get_wrangler(queue), factory, **refiner_extra_kwargs) discr_nodes = lpot_source.density_discr.nodes().get(queue) fine_discr_nodes = \ lpot_source.quad_stage2_density_discr.nodes().get(queue) int_centers = bind(lpot_source, sym.expansion_centers(lpot_source.ambient_dim, -1))(queue) int_centers = np.array([axis.get(queue) for axis in int_centers]) ext_centers = bind(lpot_source, sym.expansion_centers(lpot_source.ambient_dim, +1))(queue) ext_centers = np.array([axis.get(queue) for axis in ext_centers]) expansion_radii = bind(lpot_source, sym.expansion_radii( lpot_source.ambient_dim))(queue).get() source_danger_zone_radii = bind( lpot_source, sym._source_danger_zone_radii( lpot_source.ambient_dim, dofdesc=sym.GRANULARITY_ELEMENT))(queue).get() quad_res = bind( lpot_source, sym._quad_resolution(lpot_source.ambient_dim, dofdesc=sym.GRANULARITY_ELEMENT))(queue) # {{{ check if satisfying criteria def check_disk_undisturbed_by_sources(centers_panel, sources_panel): if centers_panel.element_nr == sources_panel.element_nr: # Same panel return my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = discr_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # A center cannot be closer to another panel than to its originating # panel. rad = expansion_radii[centers_panel.discr_slice] assert (dist >= rad * (1-expansion_disturbance_tolerance)).all(), \ (dist, rad, centers_panel.element_nr, sources_panel.element_nr) def check_sufficient_quadrature_resolution(centers_panel, sources_panel): dz_radius = source_danger_zone_radii[sources_panel.element_nr] my_int_centers = int_centers[:, centers_panel.discr_slice] my_ext_centers = ext_centers[:, centers_panel.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = fine_discr_nodes[:, sources_panel.discr_slice] # =distance(centers of panel 1, panel 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # The quadrature contribution from each panel is as accurate # as from the center's own source panel. assert dist >= dz_radius, \ (dist, dz_radius, centers_panel.element_nr, sources_panel.element_nr) def check_quad_res_to_helmholtz_k_ratio(panel): # Check wavenumber to panel size ratio. assert quad_res[panel.element_nr] * helmholtz_k <= 5 for i, panel_1 in enumerate(iter_elements(lpot_source.density_discr)): for panel_2 in iter_elements(lpot_source.density_discr): check_disk_undisturbed_by_sources(panel_1, panel_2) for panel_2 in iter_elements(lpot_source.quad_stage2_density_discr): check_sufficient_quadrature_resolution(panel_1, panel_2) if helmholtz_k is not None: check_quad_res_to_helmholtz_k_ratio(panel_1)
def run_source_refinement_test(actx_factory, mesh, order, helmholtz_k=None, surface_name="surface", visualize=False): actx = actx_factory() # {{{ initial geometry from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureGroupFactory discr = Discretization(actx, mesh, InterpolatoryQuadratureGroupFactory(order)) lpot_source = QBXLayerPotentialSource( discr, qbx_order=order, # not used in refinement fine_order=order) places = GeometryCollection(lpot_source) logger.info("nelements: %d", discr.mesh.nelements) logger.info("ndofs: %d", discr.ndofs) # }}} # {{{ refined geometry def _visualize_quad_resolution(_places, dd, suffix): if dd.discr_stage is None: vis_discr = lpot_source.density_discr else: vis_discr = _places.get_discretization(dd.geometry, dd.discr_stage) stretch = bind(_places, sym._simplex_mapping_max_stretch_factor( _places.ambient_dim, with_elementwise_max=False), auto_where=dd)(actx) from meshmode.discretization.visualization import make_visualizer vis = make_visualizer(actx, vis_discr, order, force_equidistant=True) vis.write_vtk_file( f"global-qbx-source-refinement-{surface_name}-{order}-{suffix}.vtu", [("stretch", stretch)], overwrite=True, use_high_order=True) kernel_length_scale = 5 / helmholtz_k if helmholtz_k else None expansion_disturbance_tolerance = 0.025 from pytential.qbx.refinement import refine_geometry_collection places = refine_geometry_collection( places, kernel_length_scale=kernel_length_scale, expansion_disturbance_tolerance=expansion_disturbance_tolerance, visualize=False) if visualize: dd = places.auto_source _visualize_quad_resolution(places, dd.copy(discr_stage=None), "original") _visualize_quad_resolution(places, dd.to_stage1(), "stage1") _visualize_quad_resolution(places, dd.to_stage2(), "stage2") # }}} dd = places.auto_source ambient_dim = places.ambient_dim stage1_density_discr = places.get_discretization(dd.geometry) stage1_density_nodes = actx.to_numpy( flatten(stage1_density_discr.nodes(), actx)).reshape(ambient_dim, -1) quad_stage2_density_discr = places.get_discretization( dd.geometry, sym.QBX_SOURCE_QUAD_STAGE2) quad_stage2_density_nodes = actx.to_numpy( flatten(quad_stage2_density_discr.nodes(), actx)).reshape(ambient_dim, -1) int_centers = actx.to_numpy( flatten( bind(places, sym.expansion_centers(ambient_dim, -1))(actx), actx)).reshape(ambient_dim, -1) ext_centers = actx.to_numpy( flatten( bind(places, sym.expansion_centers(ambient_dim, +1))(actx), actx)).reshape(ambient_dim, -1) expansion_radii = actx.to_numpy( flatten(bind(places, sym.expansion_radii(ambient_dim))(actx), actx)) dd = dd.copy(granularity=sym.GRANULARITY_ELEMENT) source_danger_zone_radii = actx.to_numpy( flatten( bind( places, sym._source_danger_zone_radii(ambient_dim, dofdesc=dd.to_stage2()))(actx), actx)) quad_res = actx.to_numpy( flatten( bind(places, sym._quad_resolution(ambient_dim, dofdesc=dd))(actx), actx)) # {{{ check if satisfying criteria def check_disk_undisturbed_by_sources(centers_element, sources_element): if centers_element.index == sources_element.index: # Same element return my_int_centers = int_centers[:, centers_element.discr_slice] my_ext_centers = ext_centers[:, centers_element.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = stage1_density_nodes[:, sources_element.discr_slice] # =distance(centers of element 1, element 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # A center cannot be closer to another element than to its originating # element. rad = expansion_radii[centers_element.discr_slice] assert np.all( dist >= rad * (1 - expansion_disturbance_tolerance)), (dist, rad, centers_element.index, sources_element.index) def check_sufficient_quadrature_resolution(centers_element, sources_element): dz_radius = source_danger_zone_radii[sources_element.index] my_int_centers = int_centers[:, centers_element.discr_slice] my_ext_centers = ext_centers[:, centers_element.discr_slice] all_centers = np.append(my_int_centers, my_ext_centers, axis=-1) nodes = quad_stage2_density_nodes[:, sources_element.discr_slice] # =distance(centers of element 1, element 2) dist = (la.norm( (all_centers[..., np.newaxis] - nodes[:, np.newaxis, ...]).T, axis=-1).min()) # Criterion: # The quadrature contribution from each element is as accurate # as from the center's own source element. assert dist >= dz_radius, \ (dist, dz_radius, centers_element.index, sources_element.index) def check_quad_res_to_helmholtz_k_ratio(element): # Check wavenumber to element size ratio. assert quad_res[element.index] * helmholtz_k <= 5 for element_1 in iter_elements(stage1_density_discr): for element_2 in iter_elements(stage1_density_discr): check_disk_undisturbed_by_sources(element_1, element_2) for element_2 in iter_elements(quad_stage2_density_discr): check_sufficient_quadrature_resolution(element_1, element_2) if helmholtz_k is not None: check_quad_res_to_helmholtz_k_ratio(element_1)