def warp_and_refine_until_resolved(unwarped_mesh_or_refiner, warp_callable, est_rel_interp_tolerance): """Given an original ("unwarped") :class:`meshmode.mesh.Mesh` and a warping function *warp_callable* that takes and returns a mesh and a tolerance to which the mesh should be resolved by the mapping polynomials, this function will iteratively refine the *unwarped_mesh* until relative interpolation error estimates on the warped version are smaller than *est_rel_interp_tolerance* on each element. :returns: The refined, unwarped mesh. .. versionadded:: 2018.1 """ from modepy.modes import simplex_onb from modepy.matrices import vandermonde from modepy.modal_decay import simplex_interp_error_coefficient_estimator_matrix from meshmode.mesh.refinement import Refiner, RefinerWithoutAdjacency if isinstance(unwarped_mesh_or_refiner, (Refiner, RefinerWithoutAdjacency)): refiner = unwarped_mesh_or_refiner unwarped_mesh = refiner.get_current_mesh() else: unwarped_mesh = unwarped_mesh_or_refiner refiner = Refiner(unwarped_mesh) iteration = 0 while True: refine_flags = np.zeros(unwarped_mesh.nelements, dtype=bool) warped_mesh = warp_callable(unwarped_mesh) # test whether there are invalid values in warped mesh if not np.isfinite(warped_mesh.vertices).all(): raise FloatingPointError( "Warped mesh contains non-finite vertices " "(NaN or Inf)") for group in warped_mesh.groups: if not np.isfinite(group.nodes).all(): raise FloatingPointError( "Warped mesh contains non-finite nodes " "(NaN or Inf)") for egrp in warped_mesh.groups: dim, nunit_nodes = egrp.unit_nodes.shape interp_err_est_mat = simplex_interp_error_coefficient_estimator_matrix( egrp.unit_nodes, egrp.order, n_tail_orders=1 if warped_mesh.dim > 1 else 2) vdm_inv = la.inv( vandermonde(simplex_onb(dim, egrp.order), egrp.unit_nodes)) mapping_coeffs = np.einsum("ij,dej->dei", vdm_inv, egrp.nodes) mapping_norm_2 = np.sqrt(np.sum(mapping_coeffs**2, axis=-1)) interp_error_coeffs = np.einsum("ij,dej->dei", interp_err_est_mat, egrp.nodes) interp_error_norm_2 = np.sqrt( np.sum(interp_error_coeffs**2, axis=-1)) # max over dimensions est_rel_interp_error = np.max(interp_error_norm_2 / mapping_norm_2, axis=0) refine_flags[ egrp.element_nr_base: egrp.element_nr_base+egrp.nelements] = \ est_rel_interp_error > est_rel_interp_tolerance nrefined_elements = np.sum(refine_flags.astype(np.int32)) if nrefined_elements == 0: break logger.info( "warp_and_refine_until_resolved: " "iteration %d -> splitting %d/%d elements", iteration, nrefined_elements, unwarped_mesh.nelements) unwarped_mesh = refiner.refine(refine_flags) iteration += 1 return unwarped_mesh
def warp_and_refine_until_resolved( unwarped_mesh_or_refiner, warp_callable, est_rel_interp_tolerance): """Given an original ("un-warped") :class:`meshmode.mesh.Mesh` and a warping function *warp_callable* that takes and returns a mesh and a tolerance to which the mesh should be resolved by the mapping polynomials, this function will iteratively refine the *unwarped_mesh* until relative interpolation error estimates on the warped version are smaller than *est_rel_interp_tolerance* on each element. :returns: The refined, un-warped mesh. .. versionadded:: 2018.1 """ from modepy.modes import simplex_onb from modepy.matrices import vandermonde from modepy.modal_decay import simplex_interp_error_coefficient_estimator_matrix from meshmode.mesh.refinement import Refiner, RefinerWithoutAdjacency if isinstance(unwarped_mesh_or_refiner, (Refiner, RefinerWithoutAdjacency)): refiner = unwarped_mesh_or_refiner unwarped_mesh = refiner.get_current_mesh() else: unwarped_mesh = unwarped_mesh_or_refiner refiner = Refiner(unwarped_mesh) iteration = 0 while True: refine_flags = np.zeros(unwarped_mesh.nelements, dtype=np.bool) warped_mesh = warp_callable(unwarped_mesh) # test whether there are invalid values in warped mesh if not np.isfinite(warped_mesh.vertices).all(): raise FloatingPointError("Warped mesh contains non-finite vertices " "(NaN or Inf)") for group in warped_mesh.groups: if not np.isfinite(group.nodes).all(): raise FloatingPointError("Warped mesh contains non-finite nodes " "(NaN or Inf)") for egrp in warped_mesh.groups: dim, nunit_nodes = egrp.unit_nodes.shape interp_err_est_mat = simplex_interp_error_coefficient_estimator_matrix( egrp.unit_nodes, egrp.order, n_tail_orders=1 if warped_mesh.dim > 1 else 2) vdm_inv = la.inv( vandermonde(simplex_onb(dim, egrp.order), egrp.unit_nodes)) mapping_coeffs = np.einsum("ij,dej->dei", vdm_inv, egrp.nodes) mapping_norm_2 = np.sqrt(np.sum(mapping_coeffs**2, axis=-1)) interp_error_coeffs = np.einsum( "ij,dej->dei", interp_err_est_mat, egrp.nodes) interp_error_norm_2 = np.sqrt(np.sum(interp_error_coeffs**2, axis=-1)) # max over dimensions est_rel_interp_error = np.max(interp_error_norm_2/mapping_norm_2, axis=0) refine_flags[ egrp.element_nr_base: egrp.element_nr_base+egrp.nelements] = \ est_rel_interp_error > est_rel_interp_tolerance nrefined_elements = np.sum(refine_flags.astype(np.int32)) if nrefined_elements == 0: break logger.info("warp_and_refine_until_resolved: " "iteration %d -> splitting %d/%d elements", iteration, nrefined_elements, unwarped_mesh.nelements) unwarped_mesh = refiner.refine(refine_flags) iteration += 1 return unwarped_mesh