def muller_solve_func(ne): from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "u", np.complex128, ne=ne, **base_context), y_vec, tol=1e-12, progress=True, stall_iterations=0, hard_failure=False) minv_y = gmres_result.solution print("gmres state:", gmres_result.state) z = 1/x_vec.dot(minv_y) print("muller func value:", repr(z)) return z
def test_gmres(): n = 200 A = ( # noqa n * (np.eye(n) + 2j * np.eye(n)) + np.random.randn(n, n) + 1j * np.random.randn(n, n)) true_sol = np.random.randn(n) + 1j * np.random.randn(n) b = np.dot(A, true_sol) A_func = lambda x: np.dot(A, x) # noqa A_func.shape = A.shape A_func.dtype = A.dtype from pytential.solve import gmres, ResidualPrinter tol = 1e-6 sol = gmres(A_func, b, callback=ResidualPrinter(), maxiter=5 * n, tol=tol).solution assert la.norm(true_sol - sol) / la.norm(sol) < tol
def test_gmres(): n = 200 A = ( n * (np.eye(n) + 2j * np.eye(n)) + np.random.randn(n, n) + 1j * np.random.randn(n, n)) true_sol = np.random.randn(n) + 1j * np.random.randn(n) b = np.dot(A, true_sol) A_func = lambda x: np.dot(A, x) A_func.shape = A.shape A_func.dtype = A.dtype from pytential.solve import gmres, ResidualPrinter tol = 1e-6 sol = gmres(A_func, b, callback=ResidualPrinter(), maxiter=5*n, tol=tol).solution assert la.norm(true_sol - sol) / la.norm(sol) < tol
def map_inverse(self, expr): bound_op_cache = self.bound_expr.get_cache("bound_op") try: bound_op = bound_op_cache[expr] except KeyError: bound_op = bind( expr.expression, self.bound_expr.places[expr.where], self.bound_expr.iprec) bound_op_cache[expr] = bound_op scipy_op = bound_op.scipy_op(expr.variable_name, expr.where, **dict((var_name, self.rec(var_expr)) for var_name, var_expr in six.iteritems(expr.extra_vars))) from pytential.solve import gmres rhs = self.rec(expr.rhs) result = gmres(scipy_op, rhs, debug=False) return result
def map_inverse(self, expr): bound_op_cache = self.bound_expr.places._get_cache("bound_op") try: bound_op = bound_op_cache[expr] except KeyError: bound_op = bind(expr.expression, self.places.get_geometry(expr.dofdesc.geometry), self.bound_expr.iprec) bound_op_cache[expr] = bound_op scipy_op = bound_op.scipy_op( expr.variable_name, expr.dofdesc, **dict((var_name, self.rec(var_expr)) for var_name, var_expr in six.iteritems(expr.extra_vars))) from pytential.solve import gmres rhs = self.rec(expr.rhs) result = gmres(scipy_op, rhs) return result
def map_inverse(self, expr): bound_op_cache = self.bound_expr.places._get_cache( EvaluationMapperBoundOpCacheKey) try: bound_op = bound_op_cache[expr] except KeyError: bound_op = bind(expr.expression, self.places.get_geometry(expr.dofdesc.geometry), self.bound_expr.iprec) bound_op_cache[expr] = bound_op scipy_op = bound_op.scipy_op( expr.variable_name, expr.dofdesc, **{ var_name: self.rec(var_expr) for var_name, var_expr in expr.extra_vars.items() }) from pytential.solve import gmres rhs = self.rec(expr.rhs) result = gmres(scipy_op, rhs) return result
dofdesc=sym.DEFAULT_TARGET))( queue, charges=source_charges_dev, **concrete_knl_kwargs) # }}} # {{{ solve bound_op = bind(qbx, op_u) rhs = bind(density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bc) try: from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "u", dtype, **concrete_knl_kwargs), rhs, tol=case.gmres_tol, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) except QBXTargetAssociationFailedException as e: bdry_vis = make_visualizer(queue, density_discr, case.target_order + 3) bdry_vis.write_vtk_file("failed-targets-%s.vtu" % resolution, [ ("failed_targets", e.failed_target_flags), ]) raise print("gmres state:", gmres_result.state) weighted_u = gmres_result.solution
def main(nelements): import logging logging.basicConfig(level=logging.INFO) def get_obj_array(obj_array): from pytools.obj_array import make_obj_array return make_obj_array([ary.get() for ary in obj_array]) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ( # noqa make_curve_mesh, starfish, ellipse, drop) mesh = make_curve_mesh(lambda t: starfish(t), np.linspace(0, 1, nelements + 1), target_order) coarse_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource target_association_tolerance = 0.05 qbx, _ = QBXLayerPotentialSource( coarse_density_discr, fine_order=ovsmp_target_order, qbx_order=qbx_order, fmm_order=fmm_order, target_association_tolerance=target_association_tolerance, ).with_refinement() density_discr = qbx.density_discr nodes = density_discr.nodes().with_queue(queue) # Get normal vectors for the density discretization -- used in integration with stresslet mv_normal = bind(density_discr, sym.normal(2))(queue) normal = mv_normal.as_vector(np.object) # {{{ describe bvp from sumpy.kernel import LaplaceKernel from pytential.symbolic.stokes import StressletWrapper from pytools.obj_array import make_obj_array dim = 2 cse = sym.cse nvec_sym = sym.make_sym_vector("normal", dim) sigma_sym = sym.make_sym_vector("sigma", dim) mu_sym = sym.var("mu") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym / sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = -1 # Create stresslet object stresslet_obj = StressletWrapper(dim=2) # Describe boundary operator bdry_op_sym = loc_sign * 0.5 * sigma_sym + sqrt_w * stresslet_obj.apply( inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit='avg') # Bind to the qbx discretization bound_op = bind(qbx, bdry_op_sym) # }}} # {{{ fix rhs and solve def fund_soln(x, y, loc): #with direction (1,0) for point source r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = 1. / (4 * np.pi * mu) xcomp = (-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling ycomp = ((x - loc[0]) * (y - loc[1]) / r**2) * scaling return [xcomp, ycomp] def couette_soln(x, y, dp, h): scaling = 1. / (2 * mu) xcomp = scaling * dp * ((y + (h / 2.))**2 - h * (y + (h / 2.))) ycomp = scaling * 0 * y return [xcomp, ycomp] if soln_type == 'fundamental': pt_loc = np.array([2.0, 0.0]) bc = fund_soln(nodes[0], nodes[1], pt_loc) else: dp = -10. h = 2.5 bc = couette_soln(nodes[0], nodes[1], dp, h) # Get rhs vector bvp_rhs = bind(qbx, sqrt_w * sym.make_sym_vector("bc", dim))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", np.float64, mu=mu, normal=normal), bvp_rhs, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution # Describe representation of solution for evaluation in domain representation_sym = stresslet_obj.apply(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) from sumpy.visualization import FieldPlotter nsamp = 10 eval_points_1d = np.linspace(-1., 1., nsamp) eval_points = np.zeros((2, len(eval_points_1d)**2)) eval_points[0, :] = np.tile(eval_points_1d, len(eval_points_1d)) eval_points[1, :] = np.repeat(eval_points_1d, len(eval_points_1d)) gamma_sym = sym.var("gamma") inv_sqrt_w_gamma = cse(gamma_sym / sqrt_w) constant_laplace_rep = sym.D(LaplaceKernel(dim=2), inv_sqrt_w_gamma, qbx_forced_limit=None) sqrt_w_vec = bind(qbx, sqrt_w)(queue) def general_mask(test_points): const_density = bind((qbx, PointsTarget(test_points)), constant_laplace_rep)(queue, gamma=sqrt_w_vec).get() return (abs(const_density) > 0.1) def inside_domain(test_points): mask = general_mask(test_points) return np.array([row[mask] for row in test_points]) def stride_hack(arr): from numpy.lib.stride_tricks import as_strided return np.array(as_strided(arr, strides=(8 * len(arr[0]), 8))) eval_points = inside_domain(eval_points) eval_points_dev = cl.array.to_device(queue, eval_points) # Evaluate the solution at the evaluation points vel = bind((qbx, PointsTarget(eval_points_dev)), representation_sym)(queue, sigma=sigma, mu=mu, normal=normal) print("@@@@@@@@") vel = get_obj_array(vel) if soln_type == 'fundamental': exact_soln = fund_soln(eval_points_dev[0], eval_points_dev[1], pt_loc) else: exact_soln = couette_soln(eval_points_dev[0], eval_points_dev[1], dp, h) err = vel - get_obj_array(exact_soln) print("@@@@@@@@") print( "L2 error estimate: ", np.sqrt((2. / (nsamp - 1))**2 * np.sum(err[0] * err[0]) + (2. / (nsamp - 1))**2 * np.sum(err[1] * err[1]))) max_error_loc = [abs(err[0]).argmax(), abs(err[1]).argmax()] print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1]))) print("exact velocity at max error points: x -> ", err[0][max_error_loc[0]], ", y -> ", err[1][max_error_loc[1]]) from pytential.symbolic.mappers import DerivativeTaker rep_pressure = stresslet_obj.apply_pressure(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) pressure = bind((qbx, PointsTarget(eval_points_dev)), rep_pressure)(queue, sigma=sigma, mu=mu, normal=normal) pressure = pressure.get() print "pressure = ", pressure x_dir_vecs = np.zeros((2, len(eval_points[0]))) x_dir_vecs[0, :] = 1.0 y_dir_vecs = np.zeros((2, len(eval_points[0]))) y_dir_vecs[1, :] = 1.0 x_dir_vecs = cl.array.to_device(queue, x_dir_vecs) y_dir_vecs = cl.array.to_device(queue, y_dir_vecs) dir_vec_sym = sym.make_sym_vector("force_direction", dim) rep_stress = stresslet_obj.apply_stress(inv_sqrt_w_sigma, nvec_sym, dir_vec_sym, mu_sym, qbx_forced_limit=-2) applied_stress_x = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=x_dir_vecs, mu=mu) applied_stress_x = get_obj_array(applied_stress_x) applied_stress_y = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=y_dir_vecs, mu=mu) applied_stress_y = get_obj_array(applied_stress_y) print "stress applied to x direction: ", applied_stress_x print "stress applied to y direction: ", applied_stress_y import matplotlib.pyplot as plt plt.quiver(eval_points[0], eval_points[1], vel[0], vel[1], linewidth=0.1) file_name = "field-n%s.pdf" % (nelements) plt.savefig(file_name) return (max(abs(err[0])), max(abs(err[1])))
def main(): # cl.array.to_device(queue, numpy_array) from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource("ellipsoid.step"), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h]) 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=qbx_order + 10, fmm_backend="fmmlib") from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator pde_op = MuellerAugmentedMFIEOperator( omega=0.4, epss=[1.4, 1.0], mus=[1.2, 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(0, 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) 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 0: 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=bvp_rhs,k=k) fld_at_tgt = np.array([ fi.get() for fi in fld_at_tgt ]) print(fld_at_tgt) 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_tgt_tol = qbx.copy(target_association_tolerance=0.1) from pytential.target import PointsTarget from pytential.qbx import QBXTargetAssociationFailedException rho_sym = sym.var("rho") try: fld_in_vol = bind( (qbx_tgt_tol, 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 main(): logging.basicConfig(level=logging.INFO) nelements = 60 qbx_order = 3 k_fac = 4 k0 = 3 * k_fac k1 = 2.9 * k_fac mesh_order = 10 bdry_quad_order = mesh_order bdry_ovsmp_quad_order = bdry_quad_order * 4 fmm_order = qbx_order * 2 cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh(partial(ellipse, 3), np.linspace(0, 1, nelements + 1), mesh_order) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) logger.info("%d elements" % mesh.nelements) # from meshmode.discretization.visualization import make_visualizer # bdry_vis = make_visualizer(queue, density_discr, 20) # {{{ solve bvp from sumpy.kernel import HelmholtzKernel kernel = HelmholtzKernel(2) beta = 2.5 * k_fac K0 = np.sqrt(k0**2 - beta**2) K1 = np.sqrt(k1**2 - beta**2) from pytential.symbolic.pde.scalar import DielectricSDRep2DBoundaryOperator pde_op = DielectricSDRep2DBoundaryOperator( mode='tm', k_vacuum=1, interfaces=((0, 1, sym.DEFAULT_SOURCE), ), domain_k_exprs=(k0, k1), beta=beta) op_unknown_sym = pde_op.make_unknown("unknown") representation0_sym = pde_op.representation(op_unknown_sym, 0) representation1_sym = pde_op.representation(op_unknown_sym, 1) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource(density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order) bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym)) # in inner domain sources_1 = make_obj_array(list(np.array([[-1.5, 0.5]]).T.copy())) strengths_1 = np.array([1]) from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False) _, (Einc, ) = pot_p2p(queue, density_discr.nodes(), sources_1, [strengths_1], out_host=False, k=K0) sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue) bvp_rhs = np.zeros(len(pde_op.bcs), dtype=object) for i_bc, terms in enumerate(pde_op.bcs): for term in terms: assert term.i_interface == 0 assert term.field_kind == pde_op.field_kind_e if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += (term.coeff_outer * (-Einc)) elif term.direction == pde_op.dir_normal: # no jump in normal derivative bvp_rhs[i_bc] += 0 * Einc else: raise NotImplementedError("direction spec in RHS") bvp_rhs[i_bc] *= sqrt_w from pytential.solve import gmres gmres_result = gmres(bound_pde_op.scipy_op(queue, "unknown", dtype=np.complex128, domains=[sym.DEFAULT_TARGET] * 2, K0=K0, K1=K1), bvp_rhs, tol=1e-6, progress=True, hard_failure=True, stall_iterations=0) # }}} unknown = gmres_result.solution # {{{ visualize from pytential.qbx import QBXLayerPotentialSource lap_qbx = QBXLayerPotentialSource(density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=qbx_order) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300) from pytential.target import PointsTarget fld0 = bind((qbx, PointsTarget(fplot.points)), representation0_sym)(queue, unknown=unknown, K0=K0).get() fld1 = bind((qbx, PointsTarget(fplot.points)), representation1_sym)(queue, unknown=unknown, K1=K1).get() ones = cl.array.empty(queue, density_discr.nnodes, np.float64) dom1_indicator = -bind( (lap_qbx, PointsTarget(fplot.points)), sym.D(0, sym.var("sigma")))( queue, sigma=ones.fill(1)).get() _, (fld_inc_vol, ) = pot_p2p(queue, fplot.points, sources_1, [strengths_1], out_host=True, k=K0) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("potential.vts", [ ("fld0", fld0), ("fld1", fld1), ("fld_inc_vol", fld_inc_vol), ("fld_total", ((fld_inc_vol + fld0) * (1 - dom1_indicator) + fld1 * dom1_indicator)), ("dom1_indicator", dom1_indicator), ])
def run_exterior_stokes_2d(ctx_factory, nelements, mesh_order=4, target_order=4, qbx_order=4, fmm_order=10, mu=1, circle_rad=1.5, do_plot=False): # This program tests an exterior Stokes flow in 2D using the # compound representation given in Hsiao & Kress, # ``On an integral equation for the two-dimensional exterior Stokes problem,'' # Applied Numerical Mathematics 1 (1985). logging.basicConfig(level=logging.INFO) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) ovsmp_target_order = 4 * target_order from meshmode.mesh.generation import ( # noqa make_curve_mesh, starfish, ellipse, drop) mesh = make_curve_mesh(lambda t: circle_rad * ellipse(1, t), np.linspace(0, 1, nelements + 1), target_order) coarse_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource target_association_tolerance = 0.05 qbx, _ = QBXLayerPotentialSource( coarse_density_discr, fine_order=ovsmp_target_order, qbx_order=qbx_order, fmm_order=fmm_order, target_association_tolerance=target_association_tolerance, _expansions_in_tree_have_extent=True, ).with_refinement() density_discr = qbx.density_discr normal = bind(density_discr, sym.normal(2).as_vector())(queue) path_length = bind(density_discr, sym.integral(2, 1, 1))(queue) # {{{ describe bvp from pytential.symbolic.stokes import StressletWrapper, StokesletWrapper dim = 2 cse = sym.cse sigma_sym = sym.make_sym_vector("sigma", dim) meanless_sigma_sym = cse(sigma_sym - sym.mean(2, 1, sigma_sym)) int_sigma = sym.Ones() * sym.integral(2, 1, sigma_sym) nvec_sym = sym.make_sym_vector("normal", dim) mu_sym = sym.var("mu") # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = 1 stresslet_obj = StressletWrapper(dim=2) stokeslet_obj = StokesletWrapper(dim=2) bdry_op_sym = (-loc_sign * 0.5 * sigma_sym - stresslet_obj.apply( sigma_sym, nvec_sym, mu_sym, qbx_forced_limit='avg') + stokeslet_obj.apply( meanless_sigma_sym, mu_sym, qbx_forced_limit='avg') - (0.5 / np.pi) * int_sigma) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve def fund_soln(x, y, loc, strength): #with direction (1,0) for point source r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = strength / (4 * np.pi * mu) xcomp = (-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling ycomp = ((x - loc[0]) * (y - loc[1]) / r**2) * scaling return [xcomp, ycomp] def rotlet_soln(x, y, loc): r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2) xcomp = -(y - loc[1]) / r**2 ycomp = (x - loc[0]) / r**2 return [xcomp, ycomp] def fund_and_rot_soln(x, y, loc, strength): #with direction (1,0) for point source r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = strength / (4 * np.pi * mu) xcomp = ((-cl.clmath.log(r) + (x - loc[0])**2 / r**2) * scaling - (y - loc[1]) * strength * 0.125 / r**2 + 3.3) ycomp = (((x - loc[0]) * (y - loc[1]) / r**2) * scaling + (x - loc[0]) * strength * 0.125 / r**2 + 1.5) return [xcomp, ycomp] nodes = density_discr.nodes().with_queue(queue) fund_soln_loc = np.array([0.5, -0.2]) strength = 100. bc = fund_and_rot_soln(nodes[0], nodes[1], fund_soln_loc, strength) omega_sym = sym.make_sym_vector("omega", dim) u_A_sym_bdry = stokeslet_obj.apply( # noqa: N806 omega_sym, mu_sym, qbx_forced_limit=1) omega = [ cl.array.to_device(queue, (strength / path_length) * np.ones(len(nodes[0]))), cl.array.to_device(queue, np.zeros(len(nodes[0]))) ] bvp_rhs = bind(qbx, sym.make_sym_vector("bc", dim) + u_A_sym_bdry)(queue, bc=bc, mu=mu, omega=omega) gmres_result = gmres(bound_op.scipy_op(queue, "sigma", np.float64, mu=mu, normal=normal), bvp_rhs, x0=bvp_rhs, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution sigma_int_val_sym = sym.make_sym_vector("sigma_int_val", 2) int_val = bind(qbx, sym.integral(2, 1, sigma_sym))(queue, sigma=sigma) int_val = -int_val / (2 * np.pi) print("int_val = ", int_val) u_A_sym_vol = stokeslet_obj.apply( # noqa: N806 omega_sym, mu_sym, qbx_forced_limit=2) representation_sym = ( -stresslet_obj.apply(sigma_sym, nvec_sym, mu_sym, qbx_forced_limit=2) + stokeslet_obj.apply(meanless_sigma_sym, mu_sym, qbx_forced_limit=2) - u_A_sym_vol + sigma_int_val_sym) nsamp = 30 eval_points_1d = np.linspace(-3., 3., nsamp) eval_points = np.zeros((2, len(eval_points_1d)**2)) eval_points[0, :] = np.tile(eval_points_1d, len(eval_points_1d)) eval_points[1, :] = np.repeat(eval_points_1d, len(eval_points_1d)) def circle_mask(test_points, radius): return (test_points[0, :]**2 + test_points[1, :]**2 > radius**2) def outside_circle(test_points, radius): mask = circle_mask(test_points, radius) return np.array([row[mask] for row in test_points]) eval_points = outside_circle(eval_points, radius=circle_rad) from pytential.target import PointsTarget vel = bind((qbx, PointsTarget(eval_points)), representation_sym)(queue, sigma=sigma, mu=mu, normal=normal, sigma_int_val=int_val, omega=omega) print("@@@@@@@@") fplot = FieldPlotter(np.zeros(2), extent=6, npoints=100) plot_pts = outside_circle(fplot.points, radius=circle_rad) plot_vel = bind((qbx, PointsTarget(plot_pts)), representation_sym)(queue, sigma=sigma, mu=mu, normal=normal, sigma_int_val=int_val, omega=omega) def get_obj_array(obj_array): return make_obj_array([ary.get() for ary in obj_array]) exact_soln = fund_and_rot_soln(cl.array.to_device(queue, eval_points[0]), cl.array.to_device(queue, eval_points[1]), fund_soln_loc, strength) vel = get_obj_array(vel) err = vel - get_obj_array(exact_soln) # FIXME: Pointwise relative errors don't make sense! rel_err = err / (get_obj_array(exact_soln)) if 0: print("@@@@@@@@") print("vel[0], err[0], rel_err[0] ***** vel[1], err[1], rel_err[1]: ") for i in range(len(vel[0])): print("%15.8e, %15.8e, %15.8e ***** %15.8e, %15.8e, %15.8e\n" % (vel[0][i], err[0][i], rel_err[0][i], vel[1][i], err[1][i], rel_err[1][i])) print("@@@@@@@@") l2_err = np.sqrt((6. / (nsamp - 1))**2 * np.sum(err[0] * err[0]) + (6. / (nsamp - 1))**2 * np.sum(err[1] * err[1])) l2_rel_err = np.sqrt((6. / (nsamp - 1))**2 * np.sum(rel_err[0] * rel_err[0]) + (6. / (nsamp - 1))**2 * np.sum(rel_err[1] * rel_err[1])) print("L2 error estimate: ", l2_err) print("L2 rel error estimate: ", l2_rel_err) print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1]))) print("max rel error at sampled points: ", max(abs(rel_err[0])), max(abs(rel_err[1]))) if do_plot: import matplotlib matplotlib.use("Agg") import matplotlib.pyplot as plt full_pot = np.zeros_like(fplot.points) * float("nan") mask = circle_mask(fplot.points, radius=circle_rad) for i, vel in enumerate(plot_vel): full_pot[i, mask] = vel.get() plt.quiver(fplot.points[0], fplot.points[1], full_pot[0], full_pot[1], linewidth=0.1) plt.savefig("exterior-2d-field.pdf") # }}} h_max = bind(qbx, sym.h_max(qbx.ambient_dim))(queue) return h_max, l2_err
def main(): logging.basicConfig(level=logging.INFO) nelements = 60 qbx_order = 3 k_fac = 4 k0 = 3*k_fac k1 = 2.9*k_fac mesh_order = 10 bdry_quad_order = mesh_order bdry_ovsmp_quad_order = bdry_quad_order * 4 fmm_order = qbx_order * 2 cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh( partial(ellipse, 3), np.linspace(0, 1, nelements+1), mesh_order) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) logger.info("%d elements" % mesh.nelements) # from meshmode.discretization.visualization import make_visualizer # bdry_vis = make_visualizer(queue, density_discr, 20) # {{{ solve bvp from sumpy.kernel import HelmholtzKernel kernel = HelmholtzKernel(2) beta = 2.5*k_fac K0 = np.sqrt(k0**2-beta**2) K1 = np.sqrt(k1**2-beta**2) from pytential.symbolic.pde.scalar import DielectricSDRep2DBoundaryOperator pde_op = DielectricSDRep2DBoundaryOperator( mode='tm', k_vacuum=1, interfaces=((0, 1, sym.DEFAULT_SOURCE),), domain_k_exprs=(k0, k1), beta=beta) op_unknown_sym = pde_op.make_unknown("unknown") representation0_sym = pde_op.representation(op_unknown_sym, 0) representation1_sym = pde_op.representation(op_unknown_sym, 1) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ) bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym)) # in inner domain sources_1 = make_obj_array(list(np.array([ [-1.5, 0.5] ]).T.copy())) strengths_1 = np.array([1]) from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False) _, (Einc,) = pot_p2p(queue, density_discr.nodes(), sources_1, [strengths_1], out_host=False, k=K0) sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue) bvp_rhs = np.zeros(len(pde_op.bcs), dtype=np.object) for i_bc, terms in enumerate(pde_op.bcs): for term in terms: assert term.i_interface == 0 assert term.field_kind == pde_op.field_kind_e if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += ( term.coeff_outer * (-Einc) ) elif term.direction == pde_op.dir_normal: # no jump in normal derivative bvp_rhs[i_bc] += 0*Einc else: raise NotImplementedError("direction spec in RHS") bvp_rhs[i_bc] *= sqrt_w from pytential.solve import gmres gmres_result = gmres( bound_pde_op.scipy_op(queue, "unknown", dtype=np.complex128, domains=[sym.DEFAULT_TARGET]*2, K0=K0, K1=K1), bvp_rhs, tol=1e-6, progress=True, hard_failure=True, stall_iterations=0) # }}} unknown = gmres_result.solution # {{{ visualize from pytential.qbx import QBXLayerPotentialSource lap_qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=qbx_order ) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300) from pytential.target import PointsTarget fld0 = bind( (qbx, PointsTarget(fplot.points)), representation0_sym)(queue, unknown=unknown, K0=K0).get() fld1 = bind( (qbx, PointsTarget(fplot.points)), representation1_sym)(queue, unknown=unknown, K1=K1).get() ones = cl.array.empty(queue, density_discr.nnodes, np.float64) dom1_indicator = -bind( (lap_qbx, PointsTarget(fplot.points)), sym.D(0, sym.var("sigma")))( queue, sigma=ones.fill(1)).get() _, (fld_inc_vol,) = pot_p2p(queue, fplot.points, sources_1, [strengths_1], out_host=True, k=K0) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("fld0", fld0), ("fld1", fld1), ("fld_inc_vol", fld_inc_vol), ("fld_total", ( (fld_inc_vol + fld0)*(1-dom1_indicator) + fld1*dom1_indicator )), ("dom1_indicator", dom1_indicator), ] )
def compute_biharmonic_extension(queue, target_discr, qbx, density_discr, f, fx, fy, target_association_tolerance=0.05): """Biharmoc extension. Currently only support interior domains in 2D (i.e., extension is on the exterior). """ # pylint: disable=invalid-unary-operand-type dim = 2 queue = setup_command_queue(queue=queue) qbx_forced_limit = 1 normal = get_normal_vectors(queue, density_discr, loc_sign=1) bdry_op_sym = get_extension_bie_symbolic_operator(loc_sign=1) bound_op = bind(qbx, bdry_op_sym) bc = [fy, -fx] bvp_rhs = bind(qbx, sym.make_sym_vector("bc", dim))(queue, bc=bc) gmres_result = gmres(bound_op.scipy_op(queue, "sigma", np.float64, mu=1., normal=normal), bvp_rhs, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) mu = gmres_result.solution arclength_parametrization_derivatives_sym = sym.make_sym_vector( "arclength_parametrization_derivatives", dim) density_mu_sym = sym.make_sym_vector("mu", dim) dxids_sym = arclength_parametrization_derivatives_sym[0] + \ 1j * arclength_parametrization_derivatives_sym[1] dxids_conj_sym = arclength_parametrization_derivatives_sym[0] - \ 1j * arclength_parametrization_derivatives_sym[1] density_rho_sym = density_mu_sym[1] - 1j * density_mu_sym[0] density_conj_rho_sym = density_mu_sym[1] + 1j * density_mu_sym[0] # convolutions GS1 = sym.IntG( # noqa: N806 ComplexLinearLogKernel(dim), density_rho_sym, qbx_forced_limit=None) GS2 = sym.IntG( # noqa: N806 ComplexLinearKernel(dim), density_conj_rho_sym, qbx_forced_limit=None) GD1 = sym.IntG( # noqa: N806 ComplexFractionalKernel(dim), density_rho_sym * dxids_sym, qbx_forced_limit=None) GD2 = [ sym.IntG( # noqa: N806 AxisTargetDerivative(iaxis, ComplexLogKernel(dim)), density_conj_rho_sym * dxids_sym + density_rho_sym * dxids_conj_sym, qbx_forced_limit=qbx_forced_limit) for iaxis in range(dim) ] GS1_bdry = sym.IntG( # noqa: N806 ComplexLinearLogKernel(dim), density_rho_sym, qbx_forced_limit=qbx_forced_limit) GS2_bdry = sym.IntG( # noqa: N806 ComplexLinearKernel(dim), density_conj_rho_sym, qbx_forced_limit=qbx_forced_limit) GD1_bdry = sym.IntG( # noqa: N806 ComplexFractionalKernel(dim), density_rho_sym * dxids_sym, qbx_forced_limit=qbx_forced_limit) xp, yp = get_arclength_parametrization_derivative(queue, density_discr) xp = -xp yp = -yp tangent = get_tangent_vectors(queue, density_discr, loc_sign=qbx_forced_limit) # check and fix the direction of parametrization # logger.info("Fix all negative signs in:" + # str(xp * tangent[0] + yp * tangent[1])) grad_v2 = [ bind(qbx, GD2[iaxis])(queue, mu=mu, arclength_parametrization_derivatives=make_obj_array( [xp, yp])).real for iaxis in range(dim) ] v2_tangent_der = sum(tangent[iaxis] * grad_v2[iaxis] for iaxis in range(dim)) from pytential.symbolic.pde.scalar import NeumannOperator from sumpy.kernel import LaplaceKernel operator_v1 = NeumannOperator(LaplaceKernel(dim), loc_sign=qbx_forced_limit) bound_op_v1 = bind(qbx, operator_v1.operator(var("sigma"))) # FIXME: the positive sign works here rhs_v1 = operator_v1.prepare_rhs(1 * v2_tangent_der) gmres_result = gmres(bound_op_v1.scipy_op(queue, "sigma", dtype=np.float64), rhs_v1, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) sigma = gmres_result.solution qbx_stick_out = qbx.copy( target_association_tolerance=target_association_tolerance) v1 = bind((qbx_stick_out, target_discr), operator_v1.representation(var("sigma"), qbx_forced_limit=None))(queue, sigma=sigma) grad_v1 = bind( (qbx_stick_out, target_discr), operator_v1.representation( var("sigma"), qbx_forced_limit=None, map_potentials=lambda pot: sym.grad(dim, pot)))(queue, sigma=sigma) v1_bdry = bind( qbx, operator_v1.representation(var("sigma"), qbx_forced_limit=qbx_forced_limit))( queue, sigma=sigma) z_conj = target_discr.nodes()[0] - 1j * target_discr.nodes()[1] z_conj_bdry = density_discr.nodes().with_queue(queue)[0] \ - 1j * density_discr.nodes().with_queue(queue)[1] int_rho = 1 / (8 * np.pi) * bind( qbx, sym.integral(dim, dim - 1, density_rho_sym))(queue, mu=mu) omega_S1 = bind( # noqa: N806 (qbx_stick_out, target_discr), GS1)(queue, mu=mu).real omega_S2 = -1 * bind( # noqa: N806 (qbx_stick_out, target_discr), GS2)(queue, mu=mu).real omega_S3 = (z_conj * int_rho).real # noqa: N806 omega_S = -(omega_S1 + omega_S2 + omega_S3) # noqa: N806 grad_omega_S1 = bind( # noqa: N806 (qbx_stick_out, target_discr), sym.grad(dim, GS1))(queue, mu=mu).real grad_omega_S2 = -1 * bind( # noqa: N806 (qbx_stick_out, target_discr), sym.grad(dim, GS2))(queue, mu=mu).real grad_omega_S3 = (int_rho * make_obj_array([1., -1.])).real # noqa: N806 grad_omega_S = -(grad_omega_S1 + grad_omega_S2 + grad_omega_S3 ) # noqa: N806 omega_S1_bdry = bind(qbx, GS1_bdry)(queue, mu=mu).real # noqa: N806 omega_S2_bdry = -1 * bind(qbx, GS2_bdry)(queue, mu=mu).real # noqa: N806 omega_S3_bdry = (z_conj_bdry * int_rho).real # noqa: N806 omega_S_bdry = -(omega_S1_bdry + omega_S2_bdry + omega_S3_bdry ) # noqa: N806 omega_D1 = bind( # noqa: N806 (qbx_stick_out, target_discr), GD1)(queue, mu=mu, arclength_parametrization_derivatives=make_obj_array([xp, yp])).real omega_D = (omega_D1 + v1) # noqa: N806 grad_omega_D1 = bind( # noqa: N806 (qbx_stick_out, target_discr), sym.grad(dim, GD1))( queue, mu=mu, arclength_parametrization_derivatives=make_obj_array([xp, yp])).real grad_omega_D = grad_omega_D1 + grad_v1 # noqa: N806 omega_D1_bdry = bind( # noqa: N806 qbx, GD1_bdry)(queue, mu=mu, arclength_parametrization_derivatives=make_obj_array( [xp, yp])).real omega_D_bdry = (omega_D1_bdry + v1_bdry) # noqa: N806 int_bdry_mu = bind( qbx, sym.integral(dim, dim - 1, sym.make_sym_vector("mu", dim)))(queue, mu=mu) omega_W = ( # noqa: N806 int_bdry_mu[0] * target_discr.nodes()[1] - int_bdry_mu[1] * target_discr.nodes()[0]) grad_omega_W = make_obj_array( # noqa: N806 [-int_bdry_mu[1], int_bdry_mu[0]]) omega_W_bdry = ( # noqa: N806 int_bdry_mu[0] * density_discr.nodes().with_queue(queue)[1] - int_bdry_mu[1] * density_discr.nodes().with_queue(queue)[0]) int_bdry = bind(qbx, sym.integral(dim, dim - 1, var("integrand")))( queue, integrand=omega_S_bdry + omega_D_bdry + omega_W_bdry) debugging_info = {} debugging_info['omega_S'] = omega_S debugging_info['omega_D'] = omega_D debugging_info['omega_W'] = omega_W debugging_info['omega_v1'] = v1 debugging_info['omega_D1'] = omega_D1 int_interior_func_bdry = bind(qbx, sym.integral(2, 1, var("integrand")))(queue, integrand=f) path_length = get_path_length(queue, density_discr) ext_f = omega_S + omega_D + omega_W + (int_interior_func_bdry - int_bdry) / path_length grad_f = grad_omega_S + grad_omega_D + grad_omega_W return ext_f, grad_f[0], grad_f[1], debugging_info
def compute_harmonic_extension(queue, target_discr, qbx, density_discr, f, loc_sign=1, target_association_tolerance=0.05, gmres_tolerance=1e-14): """Harmonic extension. :param: loc_sign indicates the domain for extension, which equals to the negation of the loc_sign for the original problem. """ dim = qbx.ambient_dim queue = setup_command_queue(queue=queue) # {{{ describe bvp from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(dim) cse = sym.cse sigma_sym = sym.var("sigma") #sqrt_w = sym.sqrt_jac_q_weight(3) sqrt_w = 1 inv_sqrt_w_sigma = cse(sigma_sym / sqrt_w) bdry_op_sym = ( loc_sign * 0.5 * sigma_sym + sqrt_w * (sym.S(kernel, inv_sqrt_w_sigma) + sym.D(kernel, inv_sqrt_w_sigma))) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve bvp_rhs = bind(qbx, sqrt_w * sym.var("bc"))(queue, bc=f) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", dtype=np.float64), bvp_rhs, tol=gmres_tolerance, progress=True, stall_iterations=0, hard_failure=True) sigma = bind(qbx, sym.var("sigma") / sqrt_w)(queue, sigma=gmres_result.solution) # }}} debugging_info = {} debugging_info['gmres_result'] = gmres_result # {{{ postprocess repr_kwargs = dict(qbx_forced_limit=None) representation_sym = (sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) + sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) qbx_stick_out = qbx.copy( target_association_tolerance=target_association_tolerance) debugging_info['qbx'] = qbx_stick_out debugging_info['representation'] = representation_sym debugging_info['density'] = sigma ext_f = bind((qbx_stick_out, target_discr), representation_sym)(queue, sigma=sigma).real # }}} # NOTE: matching is needed if using # pytential.symbolic.pde.scalar.DirichletOperator # but here we are using a representation that does not have null # space for exterior Dirichlet problem if loc_sign == 1 and False: bdry_measure = bind(density_discr, sym.integral(dim, dim - 1, 1))(queue) int_func_bdry = bind(qbx, sym.integral(dim, dim - 1, var("integrand")))(queue, integrand=f) solu_bdry = bind((qbx, density_discr), representation_sym)(queue, sigma=sigma).real int_solu_bdry = bind(qbx, sym.integral( dim, dim - 1, var("integrand")))(queue, integrand=solu_bdry) matching_const = (int_func_bdry - int_solu_bdry) / bdry_measure else: matching_const = 0. ext_f = ext_f + matching_const def eval_ext_f(target_discr): return bind((qbx_stick_out, target_discr), representation_sym)( queue, sigma=sigma).real + matching_const debugging_info['eval_ext_f'] = eval_ext_f return ext_f, debugging_info
def main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial if 0: mesh = make_curve_mesh( partial(ellipse, 1), np.linspace(0, 1, nelements+1), mesh_order) else: base_mesh = make_curve_mesh( partial(ellipse, 1), np.linspace(0, 1, nelements+1), mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes nx = 2 ny = 2 dx = 2 / nx meshes = [ affine_map( base_mesh, A=np.diag([dx*0.25, dx*0.25]), b=np.array([dx*(ix-nx/2), dx*(iy-ny/2)])) for ix in range(nx) for iy in range(ny)] mesh = merge_disjoint_meshes(meshes, single_group=True) if 0: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) 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 # {{{ describe bvp from sumpy.kernel import LaplaceKernel, HelmholtzKernel kernel = HelmholtzKernel(2) cse = sym.cse sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (-loc_sign*0.5*sigma_sym + sqrt_w*( alpha*sym.S(kernel, inv_sqrt_w_sigma, k=sym.var("k"), qbx_forced_limit=+1) - sym.D(kernel, inv_sqrt_w_sigma, k=sym.var("k"), qbx_forced_limit="avg") )) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) k_vec = np.array([2, 1]) k_vec = k * k_vec / la.norm(k_vec, 2) def u_incoming_func(x): return cl.clmath.exp( 1j * (x[0] * k_vec[0] + x[1] * k_vec[1])) bc = -u_incoming_func(nodes) bvp_rhs = bind(qbx, sqrt_w*sym.var("bc"))(queue, bc=bc) from pytential.solve import gmres 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) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution repr_kwargs = dict(k=sym.var("k"), qbx_forced_limit=None) representation_sym = ( alpha*sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) - sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = cl.array.to_device(queue, fplot.points) u_incoming = u_incoming_func(targets) qbx_stick_out = qbx.copy(target_association_tolerance=0.05) ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (qbx_stick_out, PointsTarget(targets)), sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None))( queue, sigma=ones_density).get() try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), representation_sym)(queue, sigma=sigma, k=k).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)) ] ) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-helm.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ("u_incoming", u_incoming.get()), ] )
def main(nelements): import logging logging.basicConfig(level=logging.INFO) def get_obj_array(obj_array): from pytools.obj_array import make_obj_array return make_obj_array([ ary.get() for ary in obj_array ]) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ( # noqa make_curve_mesh, starfish, ellipse, drop) mesh = make_curve_mesh( lambda t: starfish(t), np.linspace(0, 1, nelements+1), target_order) coarse_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(target_order)) from pytential.qbx import QBXLayerPotentialSource target_association_tolerance = 0.05 qbx, _ = QBXLayerPotentialSource( coarse_density_discr, fine_order=ovsmp_target_order, qbx_order=qbx_order, fmm_order=fmm_order, target_association_tolerance=target_association_tolerance, ).with_refinement() density_discr = qbx.density_discr nodes = density_discr.nodes().with_queue(queue) # Get normal vectors for the density discretization -- used in integration with stresslet mv_normal = bind(density_discr, sym.normal(2))(queue) normal = mv_normal.as_vector(np.object) # {{{ describe bvp from sumpy.kernel import LaplaceKernel from pytential.symbolic.stokes import StressletWrapper from pytools.obj_array import make_obj_array dim=2 cse = sym.cse nvec_sym = sym.make_sym_vector("normal", dim) sigma_sym = sym.make_sym_vector("sigma", dim) mu_sym = sym.var("mu") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = -1 # Create stresslet object stresslet_obj = StressletWrapper(dim=2) # Describe boundary operator bdry_op_sym = loc_sign * 0.5 * sigma_sym + sqrt_w * stresslet_obj.apply(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit='avg') # Bind to the qbx discretization bound_op = bind(qbx, bdry_op_sym) # }}} # {{{ fix rhs and solve def fund_soln(x, y, loc): #with direction (1,0) for point source r = cl.clmath.sqrt((x - loc[0])**2 + (y - loc[1])**2) scaling = 1./(4*np.pi*mu) xcomp = (-cl.clmath.log(r) + (x - loc[0])**2/r**2) * scaling ycomp = ((x - loc[0])*(y - loc[1])/r**2) * scaling return [ xcomp, ycomp ] def couette_soln(x, y, dp, h): scaling = 1./(2*mu) xcomp = scaling * dp * ((y+(h/2.))**2 - h * (y+(h/2.))) ycomp = scaling * 0*y return [xcomp, ycomp] if soln_type == 'fundamental': pt_loc = np.array([2.0, 0.0]) bc = fund_soln(nodes[0], nodes[1], pt_loc) else: dp = -10. h = 2.5 bc = couette_soln(nodes[0], nodes[1], dp, h) # Get rhs vector bvp_rhs = bind(qbx, sqrt_w*sym.make_sym_vector("bc",dim))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma", np.float64, mu=mu, normal=normal), bvp_rhs, tol=1e-9, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution # Describe representation of solution for evaluation in domain representation_sym = stresslet_obj.apply(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) from sumpy.visualization import FieldPlotter nsamp = 10 eval_points_1d = np.linspace(-1., 1., nsamp) eval_points = np.zeros((2, len(eval_points_1d)**2)) eval_points[0,:] = np.tile(eval_points_1d, len(eval_points_1d)) eval_points[1,:] = np.repeat(eval_points_1d, len(eval_points_1d)) gamma_sym = sym.var("gamma") inv_sqrt_w_gamma = cse(gamma_sym/sqrt_w) constant_laplace_rep = sym.D(LaplaceKernel(dim=2), inv_sqrt_w_gamma, qbx_forced_limit=None) sqrt_w_vec = bind(qbx, sqrt_w)(queue) def general_mask(test_points): const_density = bind((qbx, PointsTarget(test_points)), constant_laplace_rep)(queue, gamma=sqrt_w_vec).get() return (abs(const_density) > 0.1) def inside_domain(test_points): mask = general_mask(test_points) return np.array([ row[mask] for row in test_points]) def stride_hack(arr): from numpy.lib.stride_tricks import as_strided return np.array(as_strided(arr, strides=(8 * len(arr[0]), 8))) eval_points = inside_domain(eval_points) eval_points_dev = cl.array.to_device(queue, eval_points) # Evaluate the solution at the evaluation points vel = bind( (qbx, PointsTarget(eval_points_dev)), representation_sym)(queue, sigma=sigma, mu=mu, normal=normal) print("@@@@@@@@") vel = get_obj_array(vel) if soln_type == 'fundamental': exact_soln = fund_soln(eval_points_dev[0], eval_points_dev[1], pt_loc) else: exact_soln = couette_soln(eval_points_dev[0], eval_points_dev[1], dp, h) err = vel - get_obj_array(exact_soln) print("@@@@@@@@") print("L2 error estimate: ", np.sqrt((2./(nsamp-1))**2*np.sum(err[0]*err[0]) + (2./(nsamp-1))**2*np.sum(err[1]*err[1]))) max_error_loc = [abs(err[0]).argmax(), abs(err[1]).argmax()] print("max error at sampled points: ", max(abs(err[0])), max(abs(err[1]))) print("exact velocity at max error points: x -> ", err[0][max_error_loc[0]], ", y -> ", err[1][max_error_loc[1]]) from pytential.symbolic.mappers import DerivativeTaker rep_pressure = stresslet_obj.apply_pressure(inv_sqrt_w_sigma, nvec_sym, mu_sym, qbx_forced_limit=-2) pressure = bind((qbx, PointsTarget(eval_points_dev)), rep_pressure)(queue, sigma=sigma, mu=mu, normal=normal) pressure = pressure.get() print "pressure = ", pressure x_dir_vecs = np.zeros((2,len(eval_points[0]))) x_dir_vecs[0,:] = 1.0 y_dir_vecs = np.zeros((2, len(eval_points[0]))) y_dir_vecs[1,:] = 1.0 x_dir_vecs = cl.array.to_device(queue, x_dir_vecs) y_dir_vecs = cl.array.to_device(queue, y_dir_vecs) dir_vec_sym = sym.make_sym_vector("force_direction", dim) rep_stress = stresslet_obj.apply_stress(inv_sqrt_w_sigma, nvec_sym, dir_vec_sym, mu_sym, qbx_forced_limit=-2) applied_stress_x = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=x_dir_vecs, mu=mu) applied_stress_x = get_obj_array(applied_stress_x) applied_stress_y = bind((qbx, PointsTarget(eval_points_dev)), rep_stress)(queue, sigma=sigma, normal=normal, force_direction=y_dir_vecs, mu=mu) applied_stress_y = get_obj_array(applied_stress_y) print "stress applied to x direction: ", applied_stress_x print "stress applied to y direction: ", applied_stress_y import matplotlib.pyplot as plt plt.quiver(eval_points[0], eval_points[1], vel[0], vel[1], linewidth=0.1) file_name = "field-n%s.pdf"%(nelements) plt.savefig(file_name) return (max(abs(err[0])), max(abs(err[1])))
def main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial if 0: mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) else: base_mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes nx = 2 ny = 2 dx = 2 / nx meshes = [ affine_map(base_mesh, A=np.diag([dx * 0.25, dx * 0.25]), b=np.array([dx * (ix - nx / 2), dx * (iy - ny / 2)])) for ix in range(nx) for iy in range(ny) ] mesh = merge_disjoint_meshes(meshes, single_group=True) if 0: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import (QBXLayerPotentialSource, QBXTargetAssociationFailedException) 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 # {{{ describe bvp from sumpy.kernel import LaplaceKernel, HelmholtzKernel kernel = HelmholtzKernel(2) cse = sym.cse sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = cse(sigma_sym / sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (-loc_sign * 0.5 * sigma_sym + sqrt_w * (alpha * sym.S( kernel, inv_sqrt_w_sigma, k=sym.var("k"), qbx_forced_limit=+1) - sym.D( kernel, inv_sqrt_w_sigma, k=sym.var("k"), qbx_forced_limit="avg"))) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) k_vec = np.array([2, 1]) k_vec = k * k_vec / la.norm(k_vec, 2) def u_incoming_func(x): return cl.clmath.exp(1j * (x[0] * k_vec[0] + x[1] * k_vec[1])) bc = -u_incoming_func(nodes) bvp_rhs = bind(qbx, sqrt_w * sym.var("bc"))(queue, bc=bc) from pytential.solve import gmres 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) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution repr_kwargs = dict(k=sym.var("k"), qbx_forced_limit=None) representation_sym = ( alpha * sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) - sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = cl.array.to_device(queue, fplot.points) u_incoming = u_incoming_func(targets) qbx_stick_out = qbx.copy(target_association_tolerance=0.05) ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind((qbx_stick_out, PointsTarget(targets)), sym.D(LaplaceKernel(2), sym.var("sigma"), qbx_forced_limit=None))(queue, sigma=ones_density).get() try: fld_in_vol = bind((qbx_stick_out, PointsTarget(targets)), representation_sym)(queue, sigma=sigma, k=k).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("failed-targets.vts", [("failed", e.failed_target_flags.get(queue))]) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("potential-helm.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ("u_incoming", u_incoming.get()), ])
def main(): # cl.array.to_device(queue, numpy_array) from meshmode.mesh.io import generate_gmsh, FileSource mesh = generate_gmsh( FileSource("ellipsoid.step"), 2, order=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h]) 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=qbx_order + 10, fmm_backend="fmmlib") from pytential.symbolic.pde.maxwell import MuellerAugmentedMFIEOperator pde_op = MuellerAugmentedMFIEOperator( omega=0.4, epss=[1.4, 1.0], mus=[1.2, 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(0, 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) 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 0: 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=bvp_rhs, k=k) fld_at_tgt = np.array([fi.get() for fi in fld_at_tgt]) print(fld_at_tgt) 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_tgt_tol = qbx.copy(target_association_tolerance=0.1) from pytential.target import PointsTarget from pytential.qbx import QBXTargetAssociationFailedException rho_sym = sym.var("rho") try: fld_in_vol = bind((qbx_tgt_tol, 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 main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import generate_torus rout = 10 rin = 1 if 1: base_mesh = generate_torus(rout, rin, 40, 4, mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes # nx = 1 # ny = 1 nz = 1 dz = 0 meshes = [ affine_map(base_mesh, A=np.diag([1, 1, 1]), b=np.array([0, 0, iz * dz])) for iz in range(nz) ] mesh = merge_disjoint_meshes(meshes, single_group=True) if 0: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import (QBXLayerPotentialSource, QBXTargetAssociationFailedException) 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 # {{{ describe bvp from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(3) cse = sym.cse sigma_sym = sym.var("sigma") #sqrt_w = sym.sqrt_jac_q_weight(3) sqrt_w = 1 inv_sqrt_w_sigma = cse(sigma_sym / sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = ( loc_sign * 0.5 * sigma_sym + sqrt_w * (sym.S(kernel, inv_sqrt_w_sigma) + sym.D(kernel, inv_sqrt_w_sigma))) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) source = np.array([rout, 0, 0]) def u_incoming_func(x): # return 1/cl.clmath.sqrt( (x[0] - source[0])**2 # +(x[1] - source[1])**2 # +(x[2] - source[2])**2 ) return 1.0 / la.norm(x.get() - source[:, None], axis=0) bc = cl.array.to_device(queue, u_incoming_func(nodes)) bvp_rhs = bind(qbx, sqrt_w * sym.var("bc"))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", dtype=np.float64), bvp_rhs, tol=1e-14, progress=True, stall_iterations=0, hard_failure=True) sigma = bind(qbx, sym.var("sigma") / sqrt_w)(queue, sigma=gmres_result.solution) # }}} from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, 20) bdry_vis.write_vtk_file("laplace.vtu", [ ("sigma", sigma), ]) # {{{ postprocess/visualize repr_kwargs = dict(qbx_forced_limit=None) representation_sym = (sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) + sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(3), extent=20, npoints=50) targets = cl.array.to_device(queue, fplot.points) qbx_stick_out = qbx.copy(target_stick_out_factor=0.2) try: fld_in_vol = bind((qbx_stick_out, PointsTarget(targets)), representation_sym)(queue, sigma=sigma).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("failed-targets.vts", [("failed", e.failed_target_flags.get(queue))]) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("potential-laplace-3d.vts", [ ("potential", fld_in_vol), ])
def main(): import logging logging.basicConfig(level=logging.INFO) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh( partial(ellipse, 2), np.linspace(0, 1, nelements+1), mesh_order) pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order, expansion_disks_in_tree_have_extent=True, ).with_refinement() density_discr = qbx.density_discr from pytential.symbolic.pde.cahn_hilliard import CahnHilliardOperator chop = CahnHilliardOperator( # FIXME: Constants? lambda1=1.5, lambda2=1.25, c=1) unk = chop.make_unknown("sigma") bound_op = bind(qbx, chop.operator(unk)) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) def g(xvec): x, y = xvec return cl.clmath.atan2(y, x) bc = sym.make_obj_array([ # FIXME: Realistic BC g(nodes), -g(nodes), ]) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.complex128), bc, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = cl.array.to_device(queue, fplot.points) qbx_stick_out = qbx.copy(target_association_tolerance=0.05) indicator_qbx = qbx_stick_out.copy(qbx_order=2) from sumpy.kernel import LaplaceKernel ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (indicator_qbx, PointsTarget(targets)), sym.D(LaplaceKernel(2), sym.var("sigma")))( queue, sigma=ones_density).get() try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), chop.representation(unk))(queue, sigma=sigma).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)) ] ) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ] )
def run_dielectric_test(cl_ctx, queue, nelements, qbx_order, op_class, mode, k0=3, k1=2.9, mesh_order=10, bdry_quad_order=None, bdry_ovsmp_quad_order=None, use_l2_weighting=False, fmm_order=None, visualize=False): if fmm_order is None: fmm_order = qbx_order * 2 if bdry_quad_order is None: bdry_quad_order = mesh_order if bdry_ovsmp_quad_order is None: bdry_ovsmp_quad_order = 4*bdry_quad_order from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh( partial(ellipse, 3), np.linspace(0, 1, nelements+1), mesh_order) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) logger.info("%d elements" % mesh.nelements) # from meshmode.discretization.visualization import make_visualizer # bdry_vis = make_visualizer(queue, density_discr, 20) # {{{ solve bvp from sumpy.kernel import HelmholtzKernel, AxisTargetDerivative kernel = HelmholtzKernel(2) beta = 2.5 K0 = np.sqrt(k0**2-beta**2) # noqa K1 = np.sqrt(k1**2-beta**2) # noqa pde_op = op_class( mode, k_vacuum=1, interfaces=((0, 1, sym.DEFAULT_SOURCE),), domain_k_exprs=(k0, k1), beta=beta, use_l2_weighting=use_l2_weighting) op_unknown_sym = pde_op.make_unknown("unknown") representation0_sym = pde_op.representation(op_unknown_sym, 0) representation1_sym = pde_op.representation(op_unknown_sym, 1) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ).with_refinement() #print(sym.pretty(pde_op.operator(op_unknown_sym))) #1/0 bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym)) e_factor = float(pde_op.ez_enabled) h_factor = float(pde_op.hz_enabled) e_sources_0 = make_obj_array(list(np.array([ [0.1, 0.2] ]).T.copy())) e_strengths_0 = np.array([1*e_factor]) e_sources_1 = make_obj_array(list(np.array([ [4, 4] ]).T.copy())) e_strengths_1 = np.array([1*e_factor]) h_sources_0 = make_obj_array(list(np.array([ [0.2, 0.1] ]).T.copy())) h_strengths_0 = np.array([1*h_factor]) h_sources_1 = make_obj_array(list(np.array([ [4, 5] ]).T.copy())) h_strengths_1 = np.array([1*h_factor]) kernel_grad = [ AxisTargetDerivative(i, kernel) for i in range(density_discr.ambient_dim)] from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False) pot_p2p_grad = P2P(cl_ctx, kernel_grad, exclude_self=False) normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) tangent = bind( density_discr, sym.pseudoscalar()/sym.area_element())(queue).as_vector(np.object) _, (E0,) = pot_p2p(queue, density_discr.nodes(), e_sources_0, [e_strengths_0], out_host=False, k=K0) _, (E1,) = pot_p2p(queue, density_discr.nodes(), e_sources_1, [e_strengths_1], out_host=False, k=K1) _, (grad0_E0, grad1_E0) = pot_p2p_grad( queue, density_discr.nodes(), e_sources_0, [e_strengths_0], out_host=False, k=K0) _, (grad0_E1, grad1_E1) = pot_p2p_grad( queue, density_discr.nodes(), e_sources_1, [e_strengths_1], out_host=False, k=K1) _, (H0,) = pot_p2p(queue, density_discr.nodes(), h_sources_0, [h_strengths_0], out_host=False, k=K0) _, (H1,) = pot_p2p(queue, density_discr.nodes(), h_sources_1, [h_strengths_1], out_host=False, k=K1) _, (grad0_H0, grad1_H0) = pot_p2p_grad( queue, density_discr.nodes(), h_sources_0, [h_strengths_0], out_host=False, k=K0) _, (grad0_H1, grad1_H1) = pot_p2p_grad( queue, density_discr.nodes(), h_sources_1, [h_strengths_1], out_host=False, k=K1) E0_dntarget = (grad0_E0*normal[0] + grad1_E0*normal[1]) # noqa E1_dntarget = (grad0_E1*normal[0] + grad1_E1*normal[1]) # noqa H0_dntarget = (grad0_H0*normal[0] + grad1_H0*normal[1]) # noqa H1_dntarget = (grad0_H1*normal[0] + grad1_H1*normal[1]) # noqa E0_dttarget = (grad0_E0*tangent[0] + grad1_E0*tangent[1]) # noqa E1_dttarget = (grad0_E1*tangent[0] + grad1_E1*tangent[1]) # noqa H0_dttarget = (grad0_H0*tangent[0] + grad1_H0*tangent[1]) # noqa H1_dttarget = (grad0_H1*tangent[0] + grad1_H1*tangent[1]) # noqa sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue) bvp_rhs = np.zeros(len(pde_op.bcs), dtype=np.object) for i_bc, terms in enumerate(pde_op.bcs): for term in terms: assert term.i_interface == 0 if term.field_kind == pde_op.field_kind_e: if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += ( term.coeff_outer * E0 + term.coeff_inner * E1) elif term.direction == pde_op.dir_normal: bvp_rhs[i_bc] += ( term.coeff_outer * E0_dntarget + term.coeff_inner * E1_dntarget) elif term.direction == pde_op.dir_tangential: bvp_rhs[i_bc] += ( term.coeff_outer * E0_dttarget + term.coeff_inner * E1_dttarget) else: raise NotImplementedError("direction spec in RHS") elif term.field_kind == pde_op.field_kind_h: if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += ( term.coeff_outer * H0 + term.coeff_inner * H1) elif term.direction == pde_op.dir_normal: bvp_rhs[i_bc] += ( term.coeff_outer * H0_dntarget + term.coeff_inner * H1_dntarget) elif term.direction == pde_op.dir_tangential: bvp_rhs[i_bc] += ( term.coeff_outer * H0_dttarget + term.coeff_inner * H1_dttarget) else: raise NotImplementedError("direction spec in RHS") if use_l2_weighting: bvp_rhs[i_bc] *= sqrt_w scipy_op = bound_pde_op.scipy_op(queue, "unknown", domains=[sym.DEFAULT_TARGET]*len(pde_op.bcs), K0=K0, K1=K1, dtype=np.complex128) if mode == "tem" or op_class is SRep: from sumpy.tools import vector_from_device, vector_to_device from pytential.solve import lu unknown = lu(scipy_op, vector_from_device(queue, bvp_rhs)) unknown = vector_to_device(queue, unknown) else: from pytential.solve import gmres gmres_result = gmres(scipy_op, bvp_rhs, tol=1e-14, progress=True, hard_failure=True, stall_iterations=0) unknown = gmres_result.solution # }}} targets_0 = make_obj_array(list(np.array([ [3.2 + t, -4] for t in [0, 0.5, 1] ]).T.copy())) targets_1 = make_obj_array(list(np.array([ [t*-0.3, t*-0.2] for t in [0, 0.5, 1] ]).T.copy())) from pytential.target import PointsTarget from sumpy.tools import vector_from_device F0_tgt = vector_from_device(queue, bind( # noqa (qbx, PointsTarget(targets_0)), representation0_sym)(queue, unknown=unknown, K0=K0, K1=K1)) F1_tgt = vector_from_device(queue, bind( # noqa (qbx, PointsTarget(targets_1)), representation1_sym)(queue, unknown=unknown, K0=K0, K1=K1)) _, (E0_tgt_true,) = pot_p2p(queue, targets_0, e_sources_0, [e_strengths_0], out_host=True, k=K0) _, (E1_tgt_true,) = pot_p2p(queue, targets_1, e_sources_1, [e_strengths_1], out_host=True, k=K1) _, (H0_tgt_true,) = pot_p2p(queue, targets_0, h_sources_0, [h_strengths_0], out_host=True, k=K0) _, (H1_tgt_true,) = pot_p2p(queue, targets_1, h_sources_1, [h_strengths_1], out_host=True, k=K1) err_F0_total = 0 # noqa err_F1_total = 0 # noqa i_field = 0 def vec_norm(ary): return la.norm(ary.reshape(-1)) def field_kind_to_string(field_kind): return {pde_op.field_kind_e: "E", pde_op.field_kind_h: "H"}[field_kind] for field_kind in pde_op.field_kinds: if not pde_op.is_field_present(field_kind): continue if field_kind == pde_op.field_kind_e: F0_tgt_true = E0_tgt_true # noqa F1_tgt_true = E1_tgt_true # noqa elif field_kind == pde_op.field_kind_h: F0_tgt_true = H0_tgt_true # noqa F1_tgt_true = H1_tgt_true # noqa else: assert False abs_err_F0 = vec_norm(F0_tgt[i_field] - F0_tgt_true) # noqa abs_err_F1 = vec_norm(F1_tgt[i_field] - F1_tgt_true) # noqa rel_err_F0 = abs_err_F0/vec_norm(F0_tgt_true) # noqa rel_err_F1 = abs_err_F1/vec_norm(F1_tgt_true) # noqa err_F0_total = max(rel_err_F0, err_F0_total) # noqa err_F1_total = max(rel_err_F1, err_F1_total) # noqa print("Abs Err %s0" % field_kind_to_string(field_kind), abs_err_F0) print("Abs Err %s1" % field_kind_to_string(field_kind), abs_err_F1) print("Rel Err %s0" % field_kind_to_string(field_kind), rel_err_F0) print("Rel Err %s1" % field_kind_to_string(field_kind), rel_err_F1) i_field += 1 if visualize: from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300) from pytential.target import PointsTarget fld0 = bind( (qbx, PointsTarget(fplot.points)), representation0_sym)(queue, unknown=unknown, K0=K0) fld1 = bind( (qbx, PointsTarget(fplot.points)), representation1_sym)(queue, unknown=unknown, K1=K1) comp_fields = [] i_field = 0 for field_kind in pde_op.field_kinds: if not pde_op.is_field_present(field_kind): continue fld_str = field_kind_to_string(field_kind) comp_fields.extend([ ("%s_fld0" % fld_str, fld0[i_field].get()), ("%s_fld1" % fld_str, fld1[i_field].get()), ]) i_field += 0 low_order_qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=2, fmm_order=3).with_refinement() from sumpy.kernel import LaplaceKernel from pytential.target import PointsTarget ones = (cl.array.empty(queue, (density_discr.nnodes,), dtype=np.float64) .fill(1)) ind_func = - bind((low_order_qbx, PointsTarget(fplot.points)), sym.D(LaplaceKernel(2), sym.var("u")))( queue, u=ones).get() _, (e_fld0_true,) = pot_p2p( queue, fplot.points, e_sources_0, [e_strengths_0], out_host=True, k=K0) _, (e_fld1_true,) = pot_p2p( queue, fplot.points, e_sources_1, [e_strengths_1], out_host=True, k=K1) _, (h_fld0_true,) = pot_p2p( queue, fplot.points, h_sources_0, [h_strengths_0], out_host=True, k=K0) _, (h_fld1_true,) = pot_p2p( queue, fplot.points, h_sources_1, [h_strengths_1], out_host=True, k=K1) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-n%d.vts" % nelements, [ ("e_fld0_true", e_fld0_true), ("e_fld1_true", e_fld1_true), ("h_fld0_true", h_fld0_true), ("h_fld1_true", h_fld1_true), ("ind", ind_func), ] + comp_fields ) return err_F0_total, err_F1_total
def main(): import logging logging.basicConfig(level=logging.INFO) cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh( partial(ellipse, 3), np.linspace(0, 1, nelements+1), mesh_order) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ) # {{{ describe bvp from sumpy.kernel import HelmholtzKernel kernel = HelmholtzKernel(2) cse = sym.cse sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight() inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = -1 bdry_op_sym = (-loc_sign*0.5*sigma_sym + sqrt_w*( alpha*sym.S(kernel, inv_sqrt_w_sigma, k=sym.var("k")) - sym.D(kernel, inv_sqrt_w_sigma, k=sym.var("k")) )) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve mode_nr = 3 nodes = density_discr.nodes().with_queue(queue) angle = cl.clmath.atan2(nodes[1], nodes[0]) bc = cl.clmath.cos(mode_nr*angle) bvp_rhs = bind(qbx, sqrt_w*sym.var("bc"))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma", k=k), bvp_rhs, tol=1e-14, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize sigma = gmres_result.solution representation_sym = ( alpha*sym.S(kernel, inv_sqrt_w_sigma, k=sym.var("k")) - sym.D(kernel, inv_sqrt_w_sigma, k=sym.var("k"))) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=1500) from pytential.target import PointsTarget fld_in_vol = bind( (qbx, PointsTarget(fplot.points)), representation_sym)(queue, sigma=sigma, k=k).get() #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential.vts", [ ("potential", fld_in_vol) ] )
def main(): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) from meshmode.mesh.generation import generate_torus rout = 10 rin = 1 if 1: base_mesh = generate_torus( rout, rin, 40, 4, mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes # nx = 1 # ny = 1 nz = 1 dz = 0 meshes = [ affine_map( base_mesh, A=np.diag([1, 1, 1]), b=np.array([0, 0, iz*dz])) for iz in range(nz)] mesh = merge_disjoint_meshes(meshes, single_group=True) if 0: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) 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 # {{{ describe bvp from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(3) cse = sym.cse sigma_sym = sym.var("sigma") #sqrt_w = sym.sqrt_jac_q_weight(3) sqrt_w = 1 inv_sqrt_w_sigma = cse(sigma_sym/sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (loc_sign*0.5*sigma_sym + sqrt_w*( sym.S(kernel, inv_sqrt_w_sigma) + sym.D(kernel, inv_sqrt_w_sigma) )) # }}} bound_op = bind(qbx, bdry_op_sym) # {{{ fix rhs and solve nodes = density_discr.nodes().with_queue(queue) source = np.array([rout, 0, 0]) def u_incoming_func(x): # return 1/cl.clmath.sqrt( (x[0] - source[0])**2 # +(x[1] - source[1])**2 # +(x[2] - source[2])**2 ) return 1.0/la.norm(x.get()-source[:, None], axis=0) bc = cl.array.to_device(queue, u_incoming_func(nodes)) bvp_rhs = bind(qbx, sqrt_w*sym.var("bc"))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma", dtype=np.float64), bvp_rhs, tol=1e-14, progress=True, stall_iterations=0, hard_failure=True) sigma = bind(qbx, sym.var("sigma")/sqrt_w)(queue, sigma=gmres_result.solution) # }}} from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, density_discr, 20) bdry_vis.write_vtk_file("laplace.vtu", [ ("sigma", sigma), ]) # {{{ postprocess/visualize repr_kwargs = dict(qbx_forced_limit=None) representation_sym = ( sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) + sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(3), extent=20, npoints=50) targets = cl.array.to_device(queue, fplot.points) qbx_stick_out = qbx.copy(target_stick_out_factor=0.2) try: fld_in_vol = bind( (qbx_stick_out, PointsTarget(targets)), representation_sym)(queue, sigma=sigma).get() except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)) ] ) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file( "potential-laplace-3d.vts", [ ("potential", fld_in_vol), ] )
def main(mesh_name="torus", visualize=False): import logging logging.basicConfig(level=logging.WARNING) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) if mesh_name == "torus": rout = 10 rin = 1 from meshmode.mesh.generation import generate_torus base_mesh = generate_torus( rout, rin, 40, 4, mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes # nx = 1 # ny = 1 nz = 1 dz = 0 meshes = [ affine_map( base_mesh, A=np.diag([1, 1, 1]), b=np.array([0, 0, iz*dz])) for iz in range(nz)] mesh = merge_disjoint_meshes(meshes, single_group=True) if visualize: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() else: raise ValueError(f"unknown mesh name: {mesh_name}") pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import ( QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx = QBXLayerPotentialSource( pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order, ) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(3), extent=20, npoints=50) targets = actx.from_numpy(fplot.points) from pytential import GeometryCollection places = GeometryCollection({ "qbx": qbx, "qbx_target_assoc": qbx.copy(target_association_tolerance=0.2), "targets": PointsTarget(targets) }, auto_where="qbx") density_discr = places.get_discretization("qbx") # {{{ describe bvp from sumpy.kernel import LaplaceKernel kernel = LaplaceKernel(3) sigma_sym = sym.var("sigma") #sqrt_w = sym.sqrt_jac_q_weight(3) sqrt_w = 1 inv_sqrt_w_sigma = sym.cse(sigma_sym/sqrt_w) # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 bdry_op_sym = (loc_sign*0.5*sigma_sym + sqrt_w*( sym.S(kernel, inv_sqrt_w_sigma, qbx_forced_limit=+1) + sym.D(kernel, inv_sqrt_w_sigma, qbx_forced_limit="avg") )) # }}} bound_op = bind(places, bdry_op_sym) # {{{ fix rhs and solve from meshmode.dof_array import thaw, flatten, unflatten nodes = thaw(actx, density_discr.nodes()) source = np.array([rout, 0, 0]) def u_incoming_func(x): from pytools.obj_array import obj_array_vectorize x = obj_array_vectorize(actx.to_numpy, flatten(x)) x = np.array(list(x)) # return 1/cl.clmath.sqrt( (x[0] - source[0])**2 # +(x[1] - source[1])**2 # +(x[2] - source[2])**2 ) return 1.0/la.norm(x - source[:, None], axis=0) bc = unflatten(actx, density_discr, actx.from_numpy(u_incoming_func(nodes))) bvp_rhs = bind(places, sqrt_w*sym.var("bc"))(actx, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(actx, "sigma", dtype=np.float64), bvp_rhs, tol=1e-14, progress=True, stall_iterations=0, hard_failure=True) sigma = bind(places, sym.var("sigma")/sqrt_w)( actx, sigma=gmres_result.solution) # }}} from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(actx, density_discr, 20) bdry_vis.write_vtk_file("laplace.vtu", [ ("sigma", sigma), ]) # {{{ postprocess/visualize repr_kwargs = dict( source="qbx_target_assoc", target="targets", qbx_forced_limit=None) representation_sym = ( sym.S(kernel, inv_sqrt_w_sigma, **repr_kwargs) + sym.D(kernel, inv_sqrt_w_sigma, **repr_kwargs)) try: fld_in_vol = actx.to_numpy( bind(places, representation_sym)(actx, sigma=sigma)) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("laplace-dirichlet-3d-failed-targets.vts", [ ("failed", e.failed_target_flags.get(queue)), ]) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("laplace-dirichlet-3d-potential.vts", [ ("potential", fld_in_vol), ])
# }}} # {{{ solve scipy_op = bind(places, sym_op).scipy_op( actx, "sigma", operator.dtype, **solution.context) rhs = bind(places, sym_rhs)( actx, b=solution.source(actx, density_discr), **solution.context) from pytential.solve import gmres result = gmres( scipy_op, rhs, x0=rhs, tol=1.0e-7, progress=visualize, stall_iterations=0, hard_failure=True) result = bind(places, sym.real(sym_result))( actx, sigma=actx.np.real(result.solution), **solution.context) ref_result = solution.exact(actx, density_discr) # }}} from pytential import norm h_max = actx.to_numpy( bind(places, sym.h_max(places.ambient_dim))(actx) )
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 run_test(cl_ctx, queue): q_order = 5 qbx_order = q_order fmm_backend = "sumpy" mesh = get_ellipse_mesh(20, 40, mesh_order=5) a = 1 b = 1 / 40 if 0: from meshmode.mesh.visualization import draw_curve import matplotlib.pyplot as plt draw_curve(mesh) plt.axes().set_aspect('equal') plt.show() from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(q_order)) refiner_extra_kwargs = { # "_expansion_disturbance_tolerance": 0.05, "_scaled_max_curvature_threshold": 1, "maxiter": 10, } qbx, _ = QBXLayerPotentialSource( pre_density_discr, fine_order=4 * q_order, qbx_order=qbx_order, fmm_backend=fmm_backend, fmm_order=qbx_order + 5, ).with_refinement(**refiner_extra_kwargs) if 1: print("%d stage-1 elements after refinement" % qbx.density_discr.mesh.nelements) print("%d stage-2 elements after refinement" % qbx.stage2_density_discr.mesh.nelements) print("quad stage-2 elements have %d nodes" % qbx.quad_stage2_density_discr.groups[0].nunit_nodes) def reference_solu(rvec): # a harmonic function x, y = rvec return 2.1 * x * y + (x**2 - y**2) * 0.5 + x bvals = reference_solu(qbx.density_discr.nodes().with_queue(queue)) from pytential.symbolic.pde.scalar import DirichletOperator from sumpy.kernel import LaplaceKernel from pytential import sym, bind op = DirichletOperator(LaplaceKernel(2), -1) bound_op = bind(qbx.copy(target_association_tolerance=0.5), op.operator(sym.var('sigma'))) rhs = bind(qbx.density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bvals) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", dtype=np.float64), rhs, tol=1e-12, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) from sumpy.visualization import FieldPlotter from pytential.target import PointsTarget pltsize = b * 1.5 fplot = FieldPlotter(np.array([-1 + pltsize * 0.5, 0]), extent=pltsize * 1.05, npoints=500) plt_targets = cl.array.to_device(queue, fplot.points) interior_pts = (fplot.points[0]**2 / a**2 + fplot.points[1]**2 / b**2) < 0.99 exact_vals = reference_solu(fplot.points) out_errs = [] for assotol in [0.05]: qbx_stick_out = qbx.copy(target_association_tolerance=0.05) vol_solution = bind((qbx_stick_out, PointsTarget(plt_targets)), op.representation(sym.var('sigma')))( queue, sigma=gmres_result.solution).get() interior_error_linf = ( np.linalg.norm(np.abs(vol_solution - exact_vals)[interior_pts], ord=np.inf) / np.linalg.norm(exact_vals[interior_pts], ord=np.inf)) interior_error_l2 = (np.linalg.norm( np.abs(vol_solution - exact_vals)[interior_pts], ord=2) / np.linalg.norm(exact_vals[interior_pts], ord=2)) print("\nassotol = %f" % assotol) print("L_inf Error = %e " % interior_error_linf) print("L_2 Error = %e " % interior_error_l2) out_errs.append( ("error-%f" % assotol, np.abs(vol_solution - exact_vals))) if 1: fplot.write_vtk_file("results.vts", out_errs)
def get_bvp_error(lpot_source, fmm_order, qbx_order, k=0): # This returns a tuple (err_l2, err_linf, nit). queue = cl.CommandQueue(lpot_source.cl_context) lpot_source = lpot_source.copy( qbx_order=qbx_order, fmm_level_to_order=(False if fmm_order is False else lambda *args: fmm_order)) d = lpot_source.ambient_dim assert k == 0 # Helmholtz would require a different representation from sumpy.kernel import LaplaceKernel, HelmholtzKernel lap_k_sym = LaplaceKernel(d) if k == 0: k_sym = lap_k_sym knl_kwargs = {} else: k_sym = HelmholtzKernel(d) knl_kwargs = {"k": sym.var("k")} density_discr = lpot_source.density_discr # {{{ find source and target points source_angles = (np.pi / 2 + np.linspace(0, 2 * np.pi * BVP_EXPERIMENT_N_ARMS, BVP_EXPERIMENT_N_ARMS, endpoint=False)) / BVP_EXPERIMENT_N_ARMS source_points = 0.75 * np.array([ np.cos(source_angles), np.sin(source_angles), ]) target_angles = (np.pi + np.pi / 2 + np.linspace(0, 2 * np.pi * BVP_EXPERIMENT_N_ARMS, BVP_EXPERIMENT_N_ARMS, endpoint=False)) / BVP_EXPERIMENT_N_ARMS target_points = 1.5 * np.array([ np.cos(target_angles), np.sin(target_angles), ]) np.random.seed(17) source_charges = np.random.randn(BVP_EXPERIMENT_N_ARMS) source_points_dev = cl.array.to_device(queue, source_points) target_points_dev = cl.array.to_device(queue, target_points) source_charges_dev = cl.array.to_device(queue, source_charges) from pytential.source import PointPotentialSource from pytential.target import PointsTarget point_source = PointPotentialSource(lpot_source.cl_context, source_points_dev) pot_src = sym.IntG( # FIXME: qbx_forced_limit--really? k_sym, sym.var("charges"), qbx_forced_limit=None, **knl_kwargs) ref_direct = bind((point_source, PointsTarget(target_points_dev)), pot_src)(queue, charges=source_charges_dev, **knl_kwargs).get() sym_sqrt_j = sym.sqrt_jac_q_weight(density_discr.ambient_dim) bc = bind((point_source, density_discr), sym.normal_derivative(density_discr.ambient_dim, pot_src, where=sym.DEFAULT_TARGET))( queue, charges=source_charges_dev, **knl_kwargs) rhs = bind(density_discr, sym.var("bc") * sym_sqrt_j)(queue, bc=bc) # }}} # {{{ solve bound_op = bind( lpot_source, -0.5 * sym.var("u") + sym_sqrt_j * sym.Sp(k_sym, sym.var("u") / sym_sqrt_j, qbx_forced_limit="avg", **knl_kwargs)) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "u", np.float64, **knl_kwargs), rhs, tol=1e-10, stall_iterations=100, progress=True, hard_failure=True) u = gmres_result.solution # }}} points_target = PointsTarget(target_points_dev) bound_tgt_op = bind((lpot_source, points_target), sym.S(k_sym, sym.var("u") / sym_sqrt_j, qbx_forced_limit=None)) test_via_bdry = bound_tgt_op(queue, u=u).get() err = ref_direct - test_via_bdry err_l2 = la.norm(err, 2) / la.norm(ref_direct, 2) err_linf = la.norm(err, np.inf) / la.norm(ref_direct, np.inf) return err_l2, err_linf, gmres_result.iteration_count
def main(): import logging logging.basicConfig(level=logging.INFO) ctx = cl.create_some_context() queue = cl.CommandQueue(ctx) mesh = generate_gmsh( FileSource("circle.step"), 2, order=mesh_order, force_ambient_dim=2, other_options=["-string", "Mesh.CharacteristicLengthMax = %g;" % h] ) logger.info("%d elements" % mesh.nelements) # {{{ discretizations and connections vol_discr = Discretization(ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(vol_quad_order)) ovsmp_vol_discr = Discretization(ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(vol_ovsmp_quad_order)) from meshmode.discretization.connection import ( make_boundary_restriction, make_same_mesh_connection) bdry_mesh, bdry_discr, bdry_connection = make_boundary_restriction( queue, vol_discr, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) vol_to_ovsmp_vol = make_same_mesh_connection( queue, ovsmp_vol_discr, vol_discr) # }}} # {{{ visualizers vol_vis = make_visualizer(queue, vol_discr, 20) bdry_vis = make_visualizer(queue, bdry_discr, 20) # }}} vol_x = vol_discr.nodes().with_queue(queue) ovsmp_vol_x = ovsmp_vol_discr.nodes().with_queue(queue) rhs = rhs_func(vol_x[0], vol_x[1]) poisson_true_sol = sol_func(vol_x[0], vol_x[1]) vol_vis.write_vtk_file("volume.vtu", [("f", rhs)]) bdry_normals = bind(bdry_discr, p.normal())(queue).as_vector(dtype=object) bdry_vis.write_vtk_file("boundary.vtu", [ ("normals", bdry_normals) ]) bdry_nodes = bdry_discr.nodes().with_queue(queue) bdry_f = rhs_func(bdry_nodes[0], bdry_nodes[1]) bdry_f_2 = bdry_connection(queue, rhs) bdry_vis.write_vtk_file("y.vtu", [("f", bdry_f_2)]) if 0: vol_vis.show_scalar_in_mayavi(rhs, do_show=False) bdry_vis.show_scalar_in_mayavi(bdry_f - bdry_f_2, line_width=10, do_show=False) import mayavi.mlab as mlab mlab.colorbar() mlab.show() # {{{ compute volume potential from sumpy.qbx import LayerPotential from sumpy.expansion.local import LineTaylorLocalExpansion def get_kernel(): from sumpy.symbolic import pymbolic_real_norm_2 from pymbolic.primitives import (make_sym_vector, Variable as var) r = pymbolic_real_norm_2(make_sym_vector("d", 3)) expr = var("log")(r) scaling = 1/(2*var("pi")) from sumpy.kernel import ExpressionKernel return ExpressionKernel( dim=3, expression=expr, scaling=scaling, is_complex_valued=False) laplace_2d_in_3d_kernel = get_kernel() layer_pot = LayerPotential(ctx, [ LineTaylorLocalExpansion(laplace_2d_in_3d_kernel, order=vol_qbx_order)]) targets = cl.array.zeros(queue, (3,) + vol_x.shape[1:], vol_x.dtype) targets[:2] = vol_x center_dist = np.min( cl.clmath.sqrt( bind(vol_discr, p.area_element())(queue)).get()) centers = make_obj_array([ci.copy().reshape(vol_discr.nnodes) for ci in targets]) centers[2][:] = center_dist sources = cl.array.zeros(queue, (3,) + ovsmp_vol_x.shape[1:], ovsmp_vol_x.dtype) sources[:2] = ovsmp_vol_x ovsmp_rhs = vol_to_ovsmp_vol(queue, rhs) ovsmp_vol_weights = bind(ovsmp_vol_discr, p.area_element() * p.QWeight())(queue) evt, (vol_pot,) = layer_pot( queue, targets=targets.reshape(3, vol_discr.nnodes), centers=centers, sources=sources.reshape(3, ovsmp_vol_discr.nnodes), strengths=( (ovsmp_vol_weights*ovsmp_rhs).reshape(ovsmp_vol_discr.nnodes),) ) vol_pot_bdry = bdry_connection(queue, vol_pot) # }}} # {{{ solve bvp from sumpy.kernel import LaplaceKernel from pytential.symbolic.pde.scalar import DirichletOperator op = DirichletOperator(LaplaceKernel(2), -1, use_l2_weighting=True) sym_sigma = sym.var("sigma") op_sigma = op.operator(sym_sigma) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( bdry_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order ) bound_op = bind(qbx, op_sigma) poisson_bc = poisson_bc_func(bdry_nodes[0], bdry_nodes[1]) bvp_bc = poisson_bc - vol_pot_bdry bdry_f = rhs_func(bdry_nodes[0], bdry_nodes[1]) bvp_rhs = bind(bdry_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bvp_bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "sigma"), bvp_rhs, tol=1e-14, progress=True, hard_failure=False) sigma = gmres_result.solution print("gmres state:", gmres_result.state) # }}} bvp_sol = bind( (qbx, vol_discr), op.representation(sym_sigma))(queue, sigma=sigma) poisson_sol = bvp_sol + vol_pot poisson_err = poisson_sol-poisson_true_sol rel_err = ( norm(vol_discr, queue, poisson_err) / norm(vol_discr, queue, poisson_true_sol)) bdry_vis.write_vtk_file("poisson-boundary.vtu", [ ("vol_pot_bdry", vol_pot_bdry), ("sigma", sigma), ]) vol_vis.write_vtk_file("poisson-volume.vtu", [ ("bvp_sol", bvp_sol), ("poisson_sol", poisson_sol), ("poisson_true_sol", poisson_true_sol), ("poisson_err", poisson_err), ("vol_pot", vol_pot), ("rhs", rhs), ]) print("h = %s" % h) print("mesh_order = %s" % mesh_order) print("vol_quad_order = %s" % vol_quad_order) print("vol_ovsmp_quad_order = %s" % vol_ovsmp_quad_order) print("bdry_quad_order = %s" % bdry_quad_order) print("bdry_ovsmp_quad_order = %s" % bdry_ovsmp_quad_order) print("qbx_order = %s" % qbx_order) print("vol_qbx_order = %s" % vol_qbx_order) print("fmm_order = %s" % fmm_order) print() print("rel err: %g" % rel_err)
def run_int_eq_test( cl_ctx, queue, curve_f, nelements, qbx_order, bc_type, loc_sign, k, target_order, source_order): mesh = make_curve_mesh(curve_f, np.linspace(0, 1, nelements+1), target_order) if 0: from pytential.visualization import show_mesh show_mesh(mesh) pt.gca().set_aspect("equal") pt.show() 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)) if source_order is None: source_order = 4*target_order qbx = QBXLayerPotentialSource( density_discr, fine_order=source_order, qbx_order=qbx_order, # Don't use FMM for now fmm_order=False) # {{{ set up operator from pytential.symbolic.pde.scalar import ( DirichletOperator, NeumannOperator) from sumpy.kernel import LaplaceKernel, HelmholtzKernel, AxisTargetDerivative if k: knl = HelmholtzKernel(2) knl_kwargs = {"k": k} else: knl = LaplaceKernel(2) knl_kwargs = {} if knl.is_complex_valued: dtype = np.complex128 else: dtype = np.float64 if bc_type == "dirichlet": op = DirichletOperator((knl, knl_kwargs), loc_sign, use_l2_weighting=True) elif bc_type == "neumann": op = NeumannOperator((knl, knl_kwargs), loc_sign, use_l2_weighting=True, use_improved_operator=False) else: assert False op_u = op.operator(sym.var("u")) # }}} # {{{ set up test data inner_radius = 0.1 outer_radius = 2 if loc_sign < 0: test_src_geo_radius = outer_radius test_tgt_geo_radius = inner_radius else: test_src_geo_radius = inner_radius test_tgt_geo_radius = outer_radius point_sources = make_circular_point_group(10, test_src_geo_radius, func=lambda x: x**1.5) test_targets = make_circular_point_group(20, test_tgt_geo_radius) np.random.seed(22) source_charges = np.random.randn(point_sources.shape[1]) source_charges[-1] = -np.sum(source_charges[:-1]) source_charges = source_charges.astype(dtype) assert np.sum(source_charges) < 1e-15 # }}} if 0: # show geometry, centers, normals nodes_h = density_discr.nodes().get(queue=queue) pt.plot(nodes_h[0], nodes_h[1], "x-") normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) pt.quiver(nodes_h[0], nodes_h[1], normal[0].get(queue), normal[1].get(queue)) pt.gca().set_aspect("equal") pt.show() # {{{ establish BCs from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [knl], exclude_self=False, value_dtypes=dtype) evt, (test_direct,) = pot_p2p( queue, test_targets, point_sources, [source_charges], out_host=False, **knl_kwargs) nodes = density_discr.nodes() evt, (src_pot,) = pot_p2p( queue, nodes, point_sources, [source_charges], **knl_kwargs) grad_p2p = P2P(cl_ctx, [AxisTargetDerivative(0, knl), AxisTargetDerivative(1, knl)], exclude_self=False, value_dtypes=dtype) evt, (src_grad0, src_grad1) = grad_p2p( queue, nodes, point_sources, [source_charges], **knl_kwargs) if bc_type == "dirichlet": bc = src_pot elif bc_type == "neumann": normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) bc = (src_grad0*normal[0] + src_grad1*normal[1]) # }}} # {{{ solve bound_op = bind(qbx, op_u) rhs = bind(density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bc) from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "u", k=k), rhs, tol=1e-14, progress=True, hard_failure=False) u = gmres_result.solution print("gmres state:", gmres_result.state) if 0: # {{{ build matrix for spectrum check from sumpy.tools import build_matrix mat = build_matrix(bound_op.scipy_op("u")) w, v = la.eig(mat) if 0: pt.imshow(np.log10(1e-20+np.abs(mat))) pt.colorbar() pt.show() #assert abs(s[-1]) < 1e-13, "h #assert abs(s[-2]) > 1e-7 #from pudb import set_trace; set_trace() # }}} # }}} # {{{ error check from pytential.target import PointsTarget bound_tgt_op = bind((qbx, PointsTarget(test_targets)), op.representation(sym.var("u"))) test_via_bdry = bound_tgt_op(queue, u=u, k=k) err = test_direct-test_via_bdry err = err.get() test_direct = test_direct.get() test_via_bdry = test_via_bdry.get() # {{{ remove effect of net source charge if k == 0 and bc_type == "neumann" and loc_sign == -1: # remove constant offset in interior Laplace Neumann error tgt_ones = np.ones_like(test_direct) tgt_ones = tgt_ones/la.norm(tgt_ones) err = err - np.vdot(tgt_ones, err)*tgt_ones # }}} rel_err_2 = la.norm(err)/la.norm(test_direct) rel_err_inf = la.norm(err, np.inf)/la.norm(test_direct, np.inf) # }}} print("rel_err_2: %g rel_err_inf: %g" % (rel_err_2, rel_err_inf)) # {{{ test tangential derivative bound_t_deriv_op = bind(qbx, op.representation( sym.var("u"), map_potentials=sym.tangential_derivative, qbx_forced_limit=loc_sign)) #print(bound_t_deriv_op.code) tang_deriv_from_src = bound_t_deriv_op(queue, u=u).as_scalar().get() tangent = bind( density_discr, sym.pseudoscalar()/sym.area_element())(queue).as_vector(np.object) tang_deriv_ref = (src_grad0 * tangent[0] + src_grad1 * tangent[1]).get() if 0: pt.plot(tang_deriv_ref.real) pt.plot(tang_deriv_from_src.real) pt.show() td_err = tang_deriv_from_src - tang_deriv_ref rel_td_err_inf = la.norm(td_err, np.inf)/la.norm(tang_deriv_ref, np.inf) print("rel_td_err_inf: %g" % rel_td_err_inf) # }}} # {{{ plotting if 0: fplot = FieldPlotter(np.zeros(2), extent=1.25*2*max(test_src_geo_radius, test_tgt_geo_radius), npoints=200) #pt.plot(u) #pt.show() evt, (fld_from_src,) = pot_p2p( queue, fplot.points, point_sources, [source_charges], **knl_kwargs) fld_from_bdry = bind( (qbx, PointsTarget(fplot.points)), op.representation(sym.var("u")) )(queue, u=u, k=k) fld_from_src = fld_from_src.get() fld_from_bdry = fld_from_bdry.get() nodes = density_discr.nodes().get(queue=queue) def prep(): pt.plot(point_sources[0], point_sources[1], "o", label="Monopole 'Point Charges'") pt.plot(test_targets[0], test_targets[1], "v", label="Observation Points") pt.plot(nodes[0], nodes[1], "k-", label=r"$\Gamma$") from matplotlib.cm import get_cmap cmap = get_cmap() cmap._init() if 0: cmap._lut[(cmap.N*99)//100:, -1] = 0 # make last percent transparent? prep() if 1: pt.subplot(131) pt.title("Field error (loc_sign=%s)" % loc_sign) log_err = np.log10(1e-20+np.abs(fld_from_src-fld_from_bdry)) log_err = np.minimum(-3, log_err) fplot.show_scalar_in_matplotlib(log_err, cmap=cmap) #from matplotlib.colors import Normalize #im.set_norm(Normalize(vmin=-6, vmax=1)) cb = pt.colorbar(shrink=0.9) cb.set_label(r"$\log_{10}(\mathdefault{Error})$") if 1: pt.subplot(132) prep() pt.title("Source Field") fplot.show_scalar_in_matplotlib( fld_from_src.real, max_val=3) pt.colorbar(shrink=0.9) if 1: pt.subplot(133) prep() pt.title("Solved Field") fplot.show_scalar_in_matplotlib( fld_from_bdry.real, max_val=3) pt.colorbar(shrink=0.9) # total field #fplot.show_scalar_in_matplotlib( #fld_from_src.real+fld_from_bdry.real, max_val=0.1) #pt.colorbar() pt.legend(loc="best", prop=dict(size=15)) from matplotlib.ticker import NullFormatter pt.gca().xaxis.set_major_formatter(NullFormatter()) pt.gca().yaxis.set_major_formatter(NullFormatter()) pt.gca().set_aspect("equal") if 0: border_factor_top = 0.9 border_factor = 0.3 xl, xh = pt.xlim() xhsize = 0.5*(xh-xl) pt.xlim(xl-border_factor*xhsize, xh+border_factor*xhsize) yl, yh = pt.ylim() yhsize = 0.5*(yh-yl) pt.ylim(yl-border_factor_top*yhsize, yh+border_factor*yhsize) #pt.savefig("helmholtz.pdf", dpi=600) pt.show() # }}} class Result(Record): pass return Result( rel_err_2=rel_err_2, rel_err_inf=rel_err_inf, rel_td_err_inf=rel_td_err_inf, gmres_result=gmres_result)
def main(mesh_name="ellipse", visualize=False): import logging logging.basicConfig(level=logging.INFO) # INFO for more progress info cl_ctx = cl.create_some_context() queue = cl.CommandQueue(cl_ctx) actx = PyOpenCLArrayContext(queue) from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial if mesh_name == "ellipse": mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) elif mesh_name == "ellipse_array": base_mesh = make_curve_mesh(partial(ellipse, 1), np.linspace(0, 1, nelements + 1), mesh_order) from meshmode.mesh.processing import affine_map, merge_disjoint_meshes nx = 2 ny = 2 dx = 2 / nx meshes = [ affine_map(base_mesh, A=np.diag([dx * 0.25, dx * 0.25]), b=np.array([dx * (ix - nx / 2), dx * (iy - ny / 2)])) for ix in range(nx) for iy in range(ny) ] mesh = merge_disjoint_meshes(meshes, single_group=True) if visualize: from meshmode.mesh.visualization import draw_curve draw_curve(mesh) import matplotlib.pyplot as plt plt.show() else: raise ValueError(f"unknown mesh name: {mesh_name}") pre_density_discr = Discretization( actx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) from pytential.qbx import (QBXLayerPotentialSource, QBXTargetAssociationFailedException) qbx = QBXLayerPotentialSource(pre_density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order) from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=500) targets = actx.from_numpy(fplot.points) from pytential import GeometryCollection places = GeometryCollection( { "qbx": qbx, "qbx_high_target_assoc_tol": qbx.copy(target_association_tolerance=0.05), "targets": PointsTarget(targets) }, auto_where="qbx") density_discr = places.get_discretization("qbx") # {{{ describe bvp from sumpy.kernel import LaplaceKernel, HelmholtzKernel kernel = HelmholtzKernel(2) sigma_sym = sym.var("sigma") sqrt_w = sym.sqrt_jac_q_weight(2) inv_sqrt_w_sigma = sym.cse(sigma_sym / sqrt_w) # Brakhage-Werner parameter alpha = 1j # -1 for interior Dirichlet # +1 for exterior Dirichlet loc_sign = +1 k_sym = sym.var("k") bdry_op_sym = ( -loc_sign * 0.5 * sigma_sym + sqrt_w * (alpha * sym.S(kernel, inv_sqrt_w_sigma, k=k_sym, qbx_forced_limit=+1) - sym.D(kernel, inv_sqrt_w_sigma, k=k_sym, qbx_forced_limit="avg"))) # }}} bound_op = bind(places, bdry_op_sym) # {{{ fix rhs and solve from meshmode.dof_array import thaw nodes = thaw(actx, density_discr.nodes()) k_vec = np.array([2, 1]) k_vec = k * k_vec / la.norm(k_vec, 2) def u_incoming_func(x): return actx.np.exp(1j * (x[0] * k_vec[0] + x[1] * k_vec[1])) bc = -u_incoming_func(nodes) bvp_rhs = bind(places, sqrt_w * sym.var("bc"))(actx, bc=bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(actx, sigma_sym.name, dtype=np.complex128, k=k), bvp_rhs, tol=1e-8, progress=True, stall_iterations=0, hard_failure=True) # }}} # {{{ postprocess/visualize repr_kwargs = dict(source="qbx_high_target_assoc_tol", target="targets", qbx_forced_limit=None) representation_sym = ( alpha * sym.S(kernel, inv_sqrt_w_sigma, k=k_sym, **repr_kwargs) - sym.D(kernel, inv_sqrt_w_sigma, k=k_sym, **repr_kwargs)) u_incoming = u_incoming_func(targets) ones_density = density_discr.zeros(actx) for elem in ones_density: elem.fill(1) indicator = actx.to_numpy( bind(places, sym.D(LaplaceKernel(2), sigma_sym, **repr_kwargs))(actx, sigma=ones_density)) try: fld_in_vol = actx.to_numpy( bind(places, representation_sym)(actx, sigma=gmres_result.solution, k=k)) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file("helmholtz-dirichlet-failed-targets.vts", [("failed", e.failed_target_flags.get(queue))]) raise #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("helmholtz-dirichlet-potential.vts", [ ("potential", fld_in_vol), ("indicator", indicator), ("u_incoming", actx.to_numpy(u_incoming)), ])
def run_dielectric_test(cl_ctx, queue, nelements, qbx_order, op_class, mode, k0=3, k1=2.9, mesh_order=10, bdry_quad_order=None, bdry_ovsmp_quad_order=None, use_l2_weighting=False, fmm_order=None, visualize=False): if fmm_order is None: fmm_order = qbx_order * 2 if bdry_quad_order is None: bdry_quad_order = mesh_order if bdry_ovsmp_quad_order is None: bdry_ovsmp_quad_order = 4 * bdry_quad_order from meshmode.mesh.generation import ellipse, make_curve_mesh from functools import partial mesh = make_curve_mesh(partial(ellipse, 3), np.linspace(0, 1, nelements + 1), mesh_order) density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order)) logger.info("%d elements" % mesh.nelements) # from meshmode.discretization.visualization import make_visualizer # bdry_vis = make_visualizer(queue, density_discr, 20) # {{{ solve bvp from sumpy.kernel import HelmholtzKernel, AxisTargetDerivative kernel = HelmholtzKernel(2) beta = 2.5 K0 = np.sqrt(k0**2 - beta**2) # noqa K1 = np.sqrt(k1**2 - beta**2) # noqa pde_op = op_class(mode, k_vacuum=1, interfaces=((0, 1, sym.DEFAULT_SOURCE), ), domain_k_exprs=(k0, k1), beta=beta, use_l2_weighting=use_l2_weighting) op_unknown_sym = pde_op.make_unknown("unknown") representation0_sym = pde_op.representation(op_unknown_sym, 0) representation1_sym = pde_op.representation(op_unknown_sym, 1) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource(density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order).with_refinement() #print(sym.pretty(pde_op.operator(op_unknown_sym))) #1/0 bound_pde_op = bind(qbx, pde_op.operator(op_unknown_sym)) e_factor = float(pde_op.ez_enabled) h_factor = float(pde_op.hz_enabled) e_sources_0 = make_obj_array(list(np.array([[0.1, 0.2]]).T.copy())) e_strengths_0 = np.array([1 * e_factor]) e_sources_1 = make_obj_array(list(np.array([[4, 4]]).T.copy())) e_strengths_1 = np.array([1 * e_factor]) h_sources_0 = make_obj_array(list(np.array([[0.2, 0.1]]).T.copy())) h_strengths_0 = np.array([1 * h_factor]) h_sources_1 = make_obj_array(list(np.array([[4, 5]]).T.copy())) h_strengths_1 = np.array([1 * h_factor]) kernel_grad = [ AxisTargetDerivative(i, kernel) for i in range(density_discr.ambient_dim) ] from sumpy.p2p import P2P pot_p2p = P2P(cl_ctx, [kernel], exclude_self=False) pot_p2p_grad = P2P(cl_ctx, kernel_grad, exclude_self=False) normal = bind(density_discr, sym.normal())(queue).as_vector(np.object) tangent = bind(density_discr, sym.pseudoscalar() / sym.area_element())(queue).as_vector( np.object) _, (E0, ) = pot_p2p(queue, density_discr.nodes(), e_sources_0, [e_strengths_0], out_host=False, k=K0) _, (E1, ) = pot_p2p(queue, density_discr.nodes(), e_sources_1, [e_strengths_1], out_host=False, k=K1) _, (grad0_E0, grad1_E0) = pot_p2p_grad(queue, density_discr.nodes(), e_sources_0, [e_strengths_0], out_host=False, k=K0) _, (grad0_E1, grad1_E1) = pot_p2p_grad(queue, density_discr.nodes(), e_sources_1, [e_strengths_1], out_host=False, k=K1) _, (H0, ) = pot_p2p(queue, density_discr.nodes(), h_sources_0, [h_strengths_0], out_host=False, k=K0) _, (H1, ) = pot_p2p(queue, density_discr.nodes(), h_sources_1, [h_strengths_1], out_host=False, k=K1) _, (grad0_H0, grad1_H0) = pot_p2p_grad(queue, density_discr.nodes(), h_sources_0, [h_strengths_0], out_host=False, k=K0) _, (grad0_H1, grad1_H1) = pot_p2p_grad(queue, density_discr.nodes(), h_sources_1, [h_strengths_1], out_host=False, k=K1) E0_dntarget = (grad0_E0 * normal[0] + grad1_E0 * normal[1]) # noqa E1_dntarget = (grad0_E1 * normal[0] + grad1_E1 * normal[1]) # noqa H0_dntarget = (grad0_H0 * normal[0] + grad1_H0 * normal[1]) # noqa H1_dntarget = (grad0_H1 * normal[0] + grad1_H1 * normal[1]) # noqa E0_dttarget = (grad0_E0 * tangent[0] + grad1_E0 * tangent[1]) # noqa E1_dttarget = (grad0_E1 * tangent[0] + grad1_E1 * tangent[1]) # noqa H0_dttarget = (grad0_H0 * tangent[0] + grad1_H0 * tangent[1]) # noqa H1_dttarget = (grad0_H1 * tangent[0] + grad1_H1 * tangent[1]) # noqa sqrt_w = bind(density_discr, sym.sqrt_jac_q_weight())(queue) bvp_rhs = np.zeros(len(pde_op.bcs), dtype=np.object) for i_bc, terms in enumerate(pde_op.bcs): for term in terms: assert term.i_interface == 0 if term.field_kind == pde_op.field_kind_e: if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += (term.coeff_outer * E0 + term.coeff_inner * E1) elif term.direction == pde_op.dir_normal: bvp_rhs[i_bc] += (term.coeff_outer * E0_dntarget + term.coeff_inner * E1_dntarget) elif term.direction == pde_op.dir_tangential: bvp_rhs[i_bc] += (term.coeff_outer * E0_dttarget + term.coeff_inner * E1_dttarget) else: raise NotImplementedError("direction spec in RHS") elif term.field_kind == pde_op.field_kind_h: if term.direction == pde_op.dir_none: bvp_rhs[i_bc] += (term.coeff_outer * H0 + term.coeff_inner * H1) elif term.direction == pde_op.dir_normal: bvp_rhs[i_bc] += (term.coeff_outer * H0_dntarget + term.coeff_inner * H1_dntarget) elif term.direction == pde_op.dir_tangential: bvp_rhs[i_bc] += (term.coeff_outer * H0_dttarget + term.coeff_inner * H1_dttarget) else: raise NotImplementedError("direction spec in RHS") if use_l2_weighting: bvp_rhs[i_bc] *= sqrt_w scipy_op = bound_pde_op.scipy_op(queue, "unknown", domains=[sym.DEFAULT_TARGET] * len(pde_op.bcs), K0=K0, K1=K1, dtype=np.complex128) if mode == "tem" or op_class is SRep: from sumpy.tools import vector_from_device, vector_to_device from pytential.solve import lu unknown = lu(scipy_op, vector_from_device(queue, bvp_rhs)) unknown = vector_to_device(queue, unknown) else: from pytential.solve import gmres gmres_result = gmres(scipy_op, bvp_rhs, tol=1e-14, progress=True, hard_failure=True, stall_iterations=0) unknown = gmres_result.solution # }}} targets_0 = make_obj_array( list(np.array([[3.2 + t, -4] for t in [0, 0.5, 1]]).T.copy())) targets_1 = make_obj_array( list(np.array([[t * -0.3, t * -0.2] for t in [0, 0.5, 1]]).T.copy())) from pytential.target import PointsTarget from sumpy.tools import vector_from_device F0_tgt = vector_from_device( queue, bind( # noqa (qbx, PointsTarget(targets_0)), representation0_sym)(queue, unknown=unknown, K0=K0, K1=K1)) F1_tgt = vector_from_device( queue, bind( # noqa (qbx, PointsTarget(targets_1)), representation1_sym)(queue, unknown=unknown, K0=K0, K1=K1)) _, (E0_tgt_true, ) = pot_p2p(queue, targets_0, e_sources_0, [e_strengths_0], out_host=True, k=K0) _, (E1_tgt_true, ) = pot_p2p(queue, targets_1, e_sources_1, [e_strengths_1], out_host=True, k=K1) _, (H0_tgt_true, ) = pot_p2p(queue, targets_0, h_sources_0, [h_strengths_0], out_host=True, k=K0) _, (H1_tgt_true, ) = pot_p2p(queue, targets_1, h_sources_1, [h_strengths_1], out_host=True, k=K1) err_F0_total = 0 # noqa err_F1_total = 0 # noqa i_field = 0 def vec_norm(ary): return la.norm(ary.reshape(-1)) def field_kind_to_string(field_kind): return {pde_op.field_kind_e: "E", pde_op.field_kind_h: "H"}[field_kind] for field_kind in pde_op.field_kinds: if not pde_op.is_field_present(field_kind): continue if field_kind == pde_op.field_kind_e: F0_tgt_true = E0_tgt_true # noqa F1_tgt_true = E1_tgt_true # noqa elif field_kind == pde_op.field_kind_h: F0_tgt_true = H0_tgt_true # noqa F1_tgt_true = H1_tgt_true # noqa else: assert False abs_err_F0 = vec_norm(F0_tgt[i_field] - F0_tgt_true) # noqa abs_err_F1 = vec_norm(F1_tgt[i_field] - F1_tgt_true) # noqa rel_err_F0 = abs_err_F0 / vec_norm(F0_tgt_true) # noqa rel_err_F1 = abs_err_F1 / vec_norm(F1_tgt_true) # noqa err_F0_total = max(rel_err_F0, err_F0_total) # noqa err_F1_total = max(rel_err_F1, err_F1_total) # noqa print("Abs Err %s0" % field_kind_to_string(field_kind), abs_err_F0) print("Abs Err %s1" % field_kind_to_string(field_kind), abs_err_F1) print("Rel Err %s0" % field_kind_to_string(field_kind), rel_err_F0) print("Rel Err %s1" % field_kind_to_string(field_kind), rel_err_F1) i_field += 1 if visualize: from sumpy.visualization import FieldPlotter fplot = FieldPlotter(np.zeros(2), extent=5, npoints=300) from pytential.target import PointsTarget fld0 = bind((qbx, PointsTarget(fplot.points)), representation0_sym)(queue, unknown=unknown, K0=K0) fld1 = bind((qbx, PointsTarget(fplot.points)), representation1_sym)(queue, unknown=unknown, K1=K1) comp_fields = [] i_field = 0 for field_kind in pde_op.field_kinds: if not pde_op.is_field_present(field_kind): continue fld_str = field_kind_to_string(field_kind) comp_fields.extend([ ("%s_fld0" % fld_str, fld0[i_field].get()), ("%s_fld1" % fld_str, fld1[i_field].get()), ]) i_field += 0 low_order_qbx = QBXLayerPotentialSource( density_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=2, fmm_order=3).with_refinement() from sumpy.kernel import LaplaceKernel from pytential.target import PointsTarget ones = (cl.array.empty(queue, (density_discr.nnodes, ), dtype=np.float64).fill(1)) ind_func = -bind( (low_order_qbx, PointsTarget(fplot.points)), sym.D(LaplaceKernel(2), sym.var("u")))(queue, u=ones).get() _, (e_fld0_true, ) = pot_p2p(queue, fplot.points, e_sources_0, [e_strengths_0], out_host=True, k=K0) _, (e_fld1_true, ) = pot_p2p(queue, fplot.points, e_sources_1, [e_strengths_1], out_host=True, k=K1) _, (h_fld0_true, ) = pot_p2p(queue, fplot.points, h_sources_0, [h_strengths_0], out_host=True, k=K0) _, (h_fld1_true, ) = pot_p2p(queue, fplot.points, h_sources_1, [h_strengths_1], out_host=True, k=K1) #fplot.show_scalar_in_mayavi(fld_in_vol.real, max_val=5) fplot.write_vtk_file("potential-n%d.vts" % nelements, [ ("e_fld0_true", e_fld0_true), ("e_fld1_true", e_fld1_true), ("h_fld0_true", h_fld0_true), ("h_fld1_true", h_fld1_true), ("ind", ind_func), ] + comp_fields) return err_F0_total, err_F1_total
def run_int_eq_test(cl_ctx, queue, case, resolution, visualize): mesh = case.get_mesh(resolution, case.target_order) print("%d elements" % mesh.nelements) from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory pre_density_discr = Discretization( cl_ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) source_order = 4*case.target_order refiner_extra_kwargs = {} qbx_lpot_kwargs = {} if case.fmm_backend is None: qbx_lpot_kwargs["fmm_order"] = False else: if hasattr(case, "fmm_tol"): from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder qbx_lpot_kwargs["fmm_level_to_order"] = SimpleExpansionOrderFinder( case.fmm_tol) elif hasattr(case, "fmm_order"): qbx_lpot_kwargs["fmm_order"] = case.fmm_order else: qbx_lpot_kwargs["fmm_order"] = case.qbx_order + 5 qbx = QBXLayerPotentialSource( pre_density_discr, fine_order=source_order, qbx_order=case.qbx_order, _box_extent_norm=getattr(case, "box_extent_norm", None), _from_sep_smaller_crit=getattr(case, "from_sep_smaller_crit", None), _from_sep_smaller_min_nsources_cumul=30, fmm_backend=case.fmm_backend, **qbx_lpot_kwargs) if case.use_refinement: if case.k != 0 and getattr(case, "refine_on_helmholtz_k", True): refiner_extra_kwargs["kernel_length_scale"] = 5/case.k if hasattr(case, "scaled_max_curvature_threshold"): refiner_extra_kwargs["_scaled_max_curvature_threshold"] = \ case.scaled_max_curvature_threshold if hasattr(case, "expansion_disturbance_tolerance"): refiner_extra_kwargs["_expansion_disturbance_tolerance"] = \ case.expansion_disturbance_tolerance if hasattr(case, "refinement_maxiter"): refiner_extra_kwargs["maxiter"] = case.refinement_maxiter #refiner_extra_kwargs["visualize"] = True print("%d elements before refinement" % pre_density_discr.mesh.nelements) qbx, _ = qbx.with_refinement(**refiner_extra_kwargs) print("%d stage-1 elements after refinement" % qbx.density_discr.mesh.nelements) print("%d stage-2 elements after refinement" % qbx.stage2_density_discr.mesh.nelements) print("quad stage-2 elements have %d nodes" % qbx.quad_stage2_density_discr.groups[0].nunit_nodes) density_discr = qbx.density_discr if hasattr(case, "visualize_geometry") and case.visualize_geometry: bdry_normals = bind( density_discr, sym.normal(mesh.ambient_dim) )(queue).as_vector(dtype=object) bdry_vis = make_visualizer(queue, density_discr, case.target_order) bdry_vis.write_vtk_file("geometry.vtu", [ ("normals", bdry_normals) ]) # {{{ plot geometry if 0: if mesh.ambient_dim == 2: # show geometry, centers, normals nodes_h = density_discr.nodes().get(queue=queue) pt.plot(nodes_h[0], nodes_h[1], "x-") normal = bind(density_discr, sym.normal(2))(queue).as_vector(np.object) pt.quiver(nodes_h[0], nodes_h[1], normal[0].get(queue), normal[1].get(queue)) pt.gca().set_aspect("equal") pt.show() elif mesh.ambient_dim == 3: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_normals = bind(density_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("pre-solve-source-%s.vtu" % resolution, [ ("bdry_normals", bdry_normals), ]) else: raise ValueError("invalid mesh dim") # }}} # {{{ set up operator from pytential.symbolic.pde.scalar import ( DirichletOperator, NeumannOperator) from sumpy.kernel import LaplaceKernel, HelmholtzKernel if case.k: knl = HelmholtzKernel(mesh.ambient_dim) knl_kwargs = {"k": sym.var("k")} concrete_knl_kwargs = {"k": case.k} else: knl = LaplaceKernel(mesh.ambient_dim) knl_kwargs = {} concrete_knl_kwargs = {} if knl.is_complex_valued: dtype = np.complex128 else: dtype = np.float64 loc_sign = +1 if case.prob_side in [+1, "scat"] else -1 if case.bc_type == "dirichlet": op = DirichletOperator(knl, loc_sign, use_l2_weighting=True, kernel_arguments=knl_kwargs) elif case.bc_type == "neumann": op = NeumannOperator(knl, loc_sign, use_l2_weighting=True, use_improved_operator=False, kernel_arguments=knl_kwargs) else: assert False op_u = op.operator(sym.var("u")) # }}} # {{{ set up test data if case.prob_side == -1: test_src_geo_radius = case.outer_radius test_tgt_geo_radius = case.inner_radius elif case.prob_side == +1: test_src_geo_radius = case.inner_radius test_tgt_geo_radius = case.outer_radius elif case.prob_side == "scat": test_src_geo_radius = case.outer_radius test_tgt_geo_radius = case.outer_radius else: raise ValueError("unknown problem_side") point_sources = make_circular_point_group( mesh.ambient_dim, 10, test_src_geo_radius, func=lambda x: x**1.5) test_targets = make_circular_point_group( mesh.ambient_dim, 20, test_tgt_geo_radius) np.random.seed(22) source_charges = np.random.randn(point_sources.shape[1]) source_charges[-1] = -np.sum(source_charges[:-1]) source_charges = source_charges.astype(dtype) assert np.sum(source_charges) < 1e-15 source_charges_dev = cl.array.to_device(queue, source_charges) # }}} # {{{ establish BCs from pytential.source import PointPotentialSource from pytential.target import PointsTarget point_source = PointPotentialSource(cl_ctx, point_sources) pot_src = sym.IntG( # FIXME: qbx_forced_limit--really? knl, sym.var("charges"), qbx_forced_limit=None, **knl_kwargs) test_direct = bind((point_source, PointsTarget(test_targets)), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs) if case.bc_type == "dirichlet": bc = bind((point_source, density_discr), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs) elif case.bc_type == "neumann": bc = bind( (point_source, density_discr), sym.normal_derivative( qbx.ambient_dim, pot_src, where=sym.DEFAULT_TARGET) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) # }}} # {{{ solve bound_op = bind(qbx, op_u) rhs = bind(density_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bc) try: from pytential.solve import gmres gmres_result = gmres( bound_op.scipy_op(queue, "u", dtype, **concrete_knl_kwargs), rhs, tol=case.gmres_tol, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) except QBXTargetAssociationFailedException as e: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_vis.write_vtk_file("failed-targets-%s.vtu" % resolution, [ ("failed_targets", e.failed_target_flags), ]) raise print("gmres state:", gmres_result.state) weighted_u = gmres_result.solution # }}} # {{{ build matrix for spectrum check if 0: from sumpy.tools import build_matrix mat = build_matrix( bound_op.scipy_op( queue, arg_name="u", dtype=dtype, k=case.k)) w, v = la.eig(mat) if 0: pt.imshow(np.log10(1e-20+np.abs(mat))) pt.colorbar() pt.show() #assert abs(s[-1]) < 1e-13, "h #assert abs(s[-2]) > 1e-7 #from pudb import set_trace; set_trace() # }}} if case.prob_side != "scat": # {{{ error check points_target = PointsTarget(test_targets) bound_tgt_op = bind((qbx, points_target), op.representation(sym.var("u"))) test_via_bdry = bound_tgt_op(queue, u=weighted_u, k=case.k) err = test_via_bdry - test_direct err = err.get() test_direct = test_direct.get() test_via_bdry = test_via_bdry.get() # {{{ remove effect of net source charge if case.k == 0 and case.bc_type == "neumann" and loc_sign == -1: # remove constant offset in interior Laplace Neumann error tgt_ones = np.ones_like(test_direct) tgt_ones = tgt_ones/la.norm(tgt_ones) err = err - np.vdot(tgt_ones, err)*tgt_ones # }}} rel_err_2 = la.norm(err)/la.norm(test_direct) rel_err_inf = la.norm(err, np.inf)/la.norm(test_direct, np.inf) # }}} print("rel_err_2: %g rel_err_inf: %g" % (rel_err_2, rel_err_inf)) else: rel_err_2 = None rel_err_inf = None # {{{ test gradient if case.check_gradient and case.prob_side != "scat": bound_grad_op = bind((qbx, points_target), op.representation( sym.var("u"), map_potentials=lambda pot: sym.grad(mesh.ambient_dim, pot), qbx_forced_limit=None)) #print(bound_t_deriv_op.code) grad_from_src = bound_grad_op( queue, u=weighted_u, **concrete_knl_kwargs) grad_ref = (bind( (point_source, points_target), sym.grad(mesh.ambient_dim, pot_src) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) ) grad_err = (grad_from_src - grad_ref) rel_grad_err_inf = ( la.norm(grad_err[0].get(), np.inf) / la.norm(grad_ref[0].get(), np.inf)) print("rel_grad_err_inf: %g" % rel_grad_err_inf) # }}} # {{{ test tangential derivative if case.check_tangential_deriv and case.prob_side != "scat": bound_t_deriv_op = bind(qbx, op.representation( sym.var("u"), map_potentials=lambda pot: sym.tangential_derivative(2, pot), qbx_forced_limit=loc_sign)) #print(bound_t_deriv_op.code) tang_deriv_from_src = bound_t_deriv_op( queue, u=weighted_u, **concrete_knl_kwargs).as_scalar().get() tang_deriv_ref = (bind( (point_source, density_discr), sym.tangential_derivative(2, pot_src) )(queue, charges=source_charges_dev, **concrete_knl_kwargs) .as_scalar().get()) if 0: pt.plot(tang_deriv_ref.real) pt.plot(tang_deriv_from_src.real) pt.show() td_err = (tang_deriv_from_src - tang_deriv_ref) rel_td_err_inf = la.norm(td_err, np.inf)/la.norm(tang_deriv_ref, np.inf) print("rel_td_err_inf: %g" % rel_td_err_inf) else: rel_td_err_inf = None # }}} # {{{ any-D file plotting if visualize: bdry_vis = make_visualizer(queue, density_discr, case.target_order+3) bdry_normals = bind(density_discr, sym.normal(qbx.ambient_dim))(queue)\ .as_vector(dtype=object) sym_sqrt_j = sym.sqrt_jac_q_weight(density_discr.ambient_dim) u = bind(density_discr, sym.var("u")/sym_sqrt_j)(queue, u=weighted_u) bdry_vis.write_vtk_file("source-%s.vtu" % resolution, [ ("u", u), ("bc", bc), #("bdry_normals", bdry_normals), ]) from sumpy.visualization import make_field_plotter_from_bbox # noqa from meshmode.mesh.processing import find_bounding_box vis_grid_spacing = (0.1, 0.1, 0.1)[:qbx.ambient_dim] if hasattr(case, "vis_grid_spacing"): vis_grid_spacing = case.vis_grid_spacing vis_extend_factor = 0.2 if hasattr(case, "vis_extend_factor"): vis_grid_spacing = case.vis_grid_spacing fplot = make_field_plotter_from_bbox( find_bounding_box(mesh), h=vis_grid_spacing, extend_factor=vis_extend_factor) qbx_tgt_tol = qbx.copy(target_association_tolerance=0.15) from pytential.target import PointsTarget try: solved_pot = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), op.representation(sym.var("u")) )(queue, u=weighted_u, k=case.k) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed_targets", e.failed_target_flags.get(queue)) ]) raise from sumpy.kernel import LaplaceKernel ones_density = density_discr.zeros(queue) ones_density.fill(1) indicator = bind( (qbx_tgt_tol, PointsTarget(fplot.points)), -sym.D(LaplaceKernel(density_discr.ambient_dim), sym.var("sigma"), qbx_forced_limit=None))( queue, sigma=ones_density).get() solved_pot = solved_pot.get() true_pot = bind((point_source, PointsTarget(fplot.points)), pot_src)( queue, charges=source_charges_dev, **concrete_knl_kwargs).get() #fplot.show_scalar_in_mayavi(solved_pot.real, max_val=5) if case.prob_side == "scat": fplot.write_vtk_file( "potential-%s.vts" % resolution, [ ("pot_scattered", solved_pot), ("pot_incoming", -true_pot), ("indicator", indicator), ] ) else: fplot.write_vtk_file( "potential-%s.vts" % resolution, [ ("solved_pot", solved_pot), ("true_pot", true_pot), ("indicator", indicator), ] ) # }}} class Result(Record): pass return Result( h_max=qbx.h_max, rel_err_2=rel_err_2, rel_err_inf=rel_err_inf, rel_td_err_inf=rel_td_err_inf, gmres_result=gmres_result)
def main(): import logging logging.basicConfig(level=logging.INFO) ctx = cl.create_some_context() queue = cl.CommandQueue(ctx) if 1: ext = 0.5 mesh = generate_regular_rect_mesh(a=(-ext / 2, -ext / 2), b=(ext / 2, ext / 2), n=(int(ext / h), int(ext / h))) else: mesh = generate_gmsh(FileSource("circle.step"), 2, order=mesh_order, force_ambient_dim=2, other_options=[ "-string", "Mesh.CharacteristicLengthMax = %g;" % h ]) logger.info("%d elements" % mesh.nelements) # {{{ discretizations and connections vol_discr = Discretization( ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(vol_quad_order)) ovsmp_vol_discr = Discretization( ctx, mesh, InterpolatoryQuadratureSimplexGroupFactory(vol_ovsmp_quad_order)) from meshmode.mesh import BTAG_ALL from meshmode.discretization.connection import (make_face_restriction, make_same_mesh_connection) bdry_connection = make_face_restriction( vol_discr, InterpolatoryQuadratureSimplexGroupFactory(bdry_quad_order), BTAG_ALL) bdry_discr = bdry_connection.to_discr vol_to_ovsmp_vol = make_same_mesh_connection(ovsmp_vol_discr, vol_discr) # }}} # {{{ visualizers vol_vis = make_visualizer(queue, vol_discr, 20) bdry_vis = make_visualizer(queue, bdry_discr, 20) # }}} vol_x = vol_discr.nodes().with_queue(queue) ovsmp_vol_x = ovsmp_vol_discr.nodes().with_queue(queue) rhs = rhs_func(vol_x[0], vol_x[1]) poisson_true_sol = sol_func(vol_x[0], vol_x[1]) vol_vis.write_vtk_file("volume.vtu", [("f", rhs)]) bdry_normals = bind(bdry_discr, p.normal( mesh.ambient_dim))(queue).as_vector(dtype=object) bdry_vis.write_vtk_file("boundary.vtu", [("normals", bdry_normals)]) bdry_nodes = bdry_discr.nodes().with_queue(queue) bdry_f = rhs_func(bdry_nodes[0], bdry_nodes[1]) bdry_f_2 = bdry_connection(queue, rhs) bdry_vis.write_vtk_file("y.vtu", [("f", bdry_f_2)]) if 0: vol_vis.show_scalar_in_mayavi(rhs, do_show=False) bdry_vis.show_scalar_in_mayavi(bdry_f - bdry_f_2, line_width=10, do_show=False) import mayavi.mlab as mlab mlab.colorbar() mlab.show() # {{{ compute volume potential from sumpy.qbx import LayerPotential from sumpy.expansion.local import LineTaylorLocalExpansion def get_kernel(): from sumpy.symbolic import pymbolic_real_norm_2 from pymbolic.primitives import make_sym_vector from pymbolic import var d = make_sym_vector("d", 3) r = pymbolic_real_norm_2(d[:-1]) # r3d = pymbolic_real_norm_2(d) #expr = var("log")(r3d) log = var("log") sqrt = var("sqrt") a = d[-1] expr = log(r) expr = log(sqrt(r**2 + a**2)) expr = log(sqrt(r + a**2)) #expr = log(sqrt(r**2 + a**2))-a**2/2/(r**2+a**2) #expr = 2*log(sqrt(r**2 + a**2)) scaling = 1 / (2 * var("pi")) from sumpy.kernel import ExpressionKernel return ExpressionKernel(dim=3, expression=expr, global_scaling_const=scaling, is_complex_valued=False) laplace_2d_in_3d_kernel = get_kernel() layer_pot = LayerPotential( ctx, [LineTaylorLocalExpansion(laplace_2d_in_3d_kernel, order=0)]) targets = cl.array.zeros(queue, (3, ) + vol_x.shape[1:], vol_x.dtype) targets[:2] = vol_x center_dist = 0.125 * np.min( cl.clmath.sqrt( bind(vol_discr, p.area_element(mesh.ambient_dim, mesh.dim))(queue)).get()) centers = make_obj_array( [ci.copy().reshape(vol_discr.nnodes) for ci in targets]) centers[2][:] = center_dist print(center_dist) sources = cl.array.zeros(queue, (3, ) + ovsmp_vol_x.shape[1:], ovsmp_vol_x.dtype) sources[:2] = ovsmp_vol_x ovsmp_rhs = vol_to_ovsmp_vol(queue, rhs) ovsmp_vol_weights = bind( ovsmp_vol_discr, p.area_element(mesh.ambient_dim, mesh.dim) * p.QWeight())(queue) print("volume: %d source nodes, %d target nodes" % (ovsmp_vol_discr.nnodes, vol_discr.nnodes)) evt, (vol_pot, ) = layer_pot( queue, targets=targets.reshape(3, vol_discr.nnodes), centers=centers, sources=sources.reshape(3, ovsmp_vol_discr.nnodes), strengths=((ovsmp_vol_weights * ovsmp_rhs).reshape( ovsmp_vol_discr.nnodes), ), expansion_radii=np.zeros(vol_discr.nnodes), ) vol_pot_bdry = bdry_connection(queue, vol_pot) # }}} # {{{ solve bvp from sumpy.kernel import LaplaceKernel from pytential.symbolic.pde.scalar import DirichletOperator op = DirichletOperator(LaplaceKernel(2), -1, use_l2_weighting=True) sym_sigma = sym.var("sigma") op_sigma = op.operator(sym_sigma) from pytential.qbx import QBXLayerPotentialSource qbx = QBXLayerPotentialSource( bdry_discr, fine_order=bdry_ovsmp_quad_order, qbx_order=qbx_order, fmm_order=fmm_order, ) bound_op = bind(qbx, op_sigma) poisson_bc = poisson_bc_func(bdry_nodes[0], bdry_nodes[1]) bvp_bc = poisson_bc - vol_pot_bdry bdry_f = rhs_func(bdry_nodes[0], bdry_nodes[1]) bvp_rhs = bind(bdry_discr, op.prepare_rhs(sym.var("bc")))(queue, bc=bvp_bc) from pytential.solve import gmres gmres_result = gmres(bound_op.scipy_op(queue, "sigma", dtype=np.float64), bvp_rhs, tol=1e-14, progress=True, hard_failure=False) sigma = gmres_result.solution print("gmres state:", gmres_result.state) # }}} bvp_sol = bind((qbx, vol_discr), op.representation(sym_sigma))(queue, sigma=sigma) poisson_sol = bvp_sol + vol_pot poisson_err = poisson_sol - poisson_true_sol rel_err = (norm(vol_discr, queue, poisson_err) / norm(vol_discr, queue, poisson_true_sol)) bdry_vis.write_vtk_file("poisson-boundary.vtu", [ ("vol_pot_bdry", vol_pot_bdry), ("sigma", sigma), ]) vol_vis.write_vtk_file("poisson-volume.vtu", [ ("bvp_sol", bvp_sol), ("poisson_sol", poisson_sol), ("poisson_true_sol", poisson_true_sol), ("poisson_err", poisson_err), ("vol_pot", vol_pot), ("rhs", rhs), ]) print("h = %s" % h) print("mesh_order = %s" % mesh_order) print("vol_quad_order = %s" % vol_quad_order) print("vol_ovsmp_quad_order = %s" % vol_ovsmp_quad_order) print("bdry_quad_order = %s" % bdry_quad_order) print("bdry_ovsmp_quad_order = %s" % bdry_ovsmp_quad_order) print("qbx_order = %s" % qbx_order) #print("vol_qbx_order = %s" % vol_qbx_order) print("fmm_order = %s" % fmm_order) print() print("rel err: %g" % rel_err)
inc_xyz_sym = EHField(sym.make_sym_vector("inc_fld", 6)) bound_j_op = bind(qbx, mfie.j_operator(loc_sign, jt_sym)) j_rhs = bind(qbx, mfie.j_rhs(inc_xyz_sym.h))(queue, inc_fld=inc_field_scat.field, **knl_kwargs) gmres_settings = dict(tol=case.gmres_tol, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) from pytential.solve import gmres gmres_result = gmres( bound_j_op.scipy_op(queue, "jt", np.complex128, **knl_kwargs), j_rhs, **gmres_settings) jt = gmres_result.solution bound_rho_op = bind(qbx, mfie.rho_operator(loc_sign, rho_sym)) rho_rhs = bind(qbx, mfie.rho_rhs(jt_sym, inc_xyz_sym.e))( queue, jt=jt, inc_fld=inc_field_scat.field, **knl_kwargs) gmres_result = gmres( bound_rho_op.scipy_op(queue, "rho", np.complex128, **knl_kwargs), rho_rhs, **gmres_settings) rho = gmres_result.solution # }}}
def test_pec_mfie_extinction(ctx_getter, case, visualize=False): """For (say) is_interior=False (the 'exterior' MFIE), this test verifies extinction of the combined (incoming + scattered) field on the interior of the scatterer. """ logging.basicConfig(level=logging.INFO) cl_ctx = ctx_getter() queue = cl.CommandQueue(cl_ctx) np.random.seed(12) knl_kwargs = {"k": case.k} # {{{ come up with a solution to Maxwell's equations j_sym = sym.make_sym_vector("j", 3) jt_sym = sym.make_sym_vector("jt", 2) rho_sym = sym.var("rho") from pytential.symbolic.pde.maxwell import ( PECChargeCurrentMFIEOperator, get_sym_maxwell_point_source, get_sym_maxwell_plane_wave) mfie = PECChargeCurrentMFIEOperator() test_source = case.get_source(queue) calc_patch = CalculusPatch(np.array([-3, 0, 0]), h=0.01) calc_patch_tgt = PointsTarget(cl.array.to_device(queue, calc_patch.points)) rng = cl.clrandom.PhiloxGenerator(cl_ctx, seed=12) src_j = rng.normal(queue, (3, test_source.nnodes), dtype=np.float64) def eval_inc_field_at(tgt): if 0: # plane wave return bind( tgt, get_sym_maxwell_plane_wave( amplitude_vec=np.array([1, 1, 1]), v=np.array([1, 0, 0]), omega=case.k) )(queue) else: # point source return bind( (test_source, tgt), get_sym_maxwell_point_source(mfie.kernel, j_sym, mfie.k) )(queue, j=src_j, k=case.k) pde_test_inc = EHField( vector_from_device(queue, eval_inc_field_at(calc_patch_tgt))) source_maxwell_resids = [ calc_patch.norm(x, np.inf) / calc_patch.norm(pde_test_inc.e, np.inf) for x in frequency_domain_maxwell( calc_patch, pde_test_inc.e, pde_test_inc.h, case.k)] print("Source Maxwell residuals:", source_maxwell_resids) assert max(source_maxwell_resids) < 1e-6 # }}} loc_sign = -1 if case.is_interior else +1 from pytools.convergence import EOCRecorder eoc_rec_repr_maxwell = EOCRecorder() eoc_pec_bc = EOCRecorder() eoc_rec_e = EOCRecorder() eoc_rec_h = EOCRecorder() from pytential.qbx import QBXLayerPotentialSource from meshmode.discretization import Discretization from meshmode.discretization.poly_element import \ InterpolatoryQuadratureSimplexGroupFactory from sumpy.expansion.level_to_order import SimpleExpansionOrderFinder for resolution in case.resolutions: scat_mesh = case.get_mesh(resolution, case.target_order) observation_mesh = case.get_observation_mesh(case.target_order) pre_scat_discr = Discretization( cl_ctx, scat_mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) qbx, _ = QBXLayerPotentialSource( pre_scat_discr, fine_order=4*case.target_order, qbx_order=case.qbx_order, fmm_level_to_order=SimpleExpansionOrderFinder( case.fmm_tolerance), fmm_backend=case.fmm_backend ).with_refinement(_expansion_disturbance_tolerance=0.05) h_max = qbx.h_max scat_discr = qbx.density_discr obs_discr = Discretization( cl_ctx, observation_mesh, InterpolatoryQuadratureSimplexGroupFactory(case.target_order)) inc_field_scat = EHField(eval_inc_field_at(scat_discr)) inc_field_obs = EHField(eval_inc_field_at(obs_discr)) # {{{ system solve inc_xyz_sym = EHField(sym.make_sym_vector("inc_fld", 6)) bound_j_op = bind(qbx, mfie.j_operator(loc_sign, jt_sym)) j_rhs = bind(qbx, mfie.j_rhs(inc_xyz_sym.h))( queue, inc_fld=inc_field_scat.field, **knl_kwargs) gmres_settings = dict( tol=case.gmres_tol, progress=True, hard_failure=True, stall_iterations=50, no_progress_factor=1.05) from pytential.solve import gmres gmres_result = gmres( bound_j_op.scipy_op(queue, "jt", np.complex128, **knl_kwargs), j_rhs, **gmres_settings) jt = gmres_result.solution bound_rho_op = bind(qbx, mfie.rho_operator(loc_sign, rho_sym)) rho_rhs = bind(qbx, mfie.rho_rhs(jt_sym, inc_xyz_sym.e))( queue, jt=jt, inc_fld=inc_field_scat.field, **knl_kwargs) gmres_result = gmres( bound_rho_op.scipy_op(queue, "rho", np.complex128, **knl_kwargs), rho_rhs, **gmres_settings) rho = gmres_result.solution # }}} jxyz = bind(qbx, sym.tangential_to_xyz(jt_sym))(queue, jt=jt) # {{{ volume eval sym_repr = mfie.scattered_volume_field(jt_sym, rho_sym) def eval_repr_at(tgt, source=None): if source is None: source = qbx return bind((source, tgt), sym_repr)(queue, jt=jt, rho=rho, **knl_kwargs) pde_test_repr = EHField( vector_from_device(queue, eval_repr_at(calc_patch_tgt))) maxwell_residuals = [ calc_patch.norm(x, np.inf) / calc_patch.norm(pde_test_repr.e, np.inf) for x in frequency_domain_maxwell( calc_patch, pde_test_repr.e, pde_test_repr.h, case.k)] print("Maxwell residuals:", maxwell_residuals) eoc_rec_repr_maxwell.add_data_point(h_max, max(maxwell_residuals)) # }}} # {{{ check PEC BC on total field bc_repr = EHField(mfie.scattered_volume_field( jt_sym, rho_sym, qbx_forced_limit=loc_sign)) pec_bc_e = sym.n_cross(bc_repr.e + inc_xyz_sym.e) pec_bc_h = sym.normal(3).as_vector().dot(bc_repr.h + inc_xyz_sym.h) eh_bc_values = bind(qbx, sym.join_fields(pec_bc_e, pec_bc_h))( queue, jt=jt, rho=rho, inc_fld=inc_field_scat.field, **knl_kwargs) def scat_norm(f): return norm(qbx, queue, f, p=np.inf) e_bc_residual = scat_norm(eh_bc_values[:3]) / scat_norm(inc_field_scat.e) h_bc_residual = scat_norm(eh_bc_values[3]) / scat_norm(inc_field_scat.h) print("E/H PEC BC residuals:", h_max, e_bc_residual, h_bc_residual) eoc_pec_bc.add_data_point(h_max, max(e_bc_residual, h_bc_residual)) # }}} # {{{ visualization if visualize: from meshmode.discretization.visualization import make_visualizer bdry_vis = make_visualizer(queue, scat_discr, case.target_order+3) bdry_normals = bind(scat_discr, sym.normal(3))(queue)\ .as_vector(dtype=object) bdry_vis.write_vtk_file("source-%s.vtu" % resolution, [ ("j", jxyz), ("rho", rho), ("Einc", inc_field_scat.e), ("Hinc", inc_field_scat.h), ("bdry_normals", bdry_normals), ("e_bc_residual", eh_bc_values[:3]), ("h_bc_residual", eh_bc_values[3]), ]) fplot = make_field_plotter_from_bbox( find_bounding_box(scat_discr.mesh), h=(0.05, 0.05, 0.3), extend_factor=0.3) from pytential.qbx import QBXTargetAssociationFailedException qbx_tgt_tol = qbx.copy(target_association_tolerance=0.2) fplot_tgt = PointsTarget(cl.array.to_device(queue, fplot.points)) try: fplot_repr = eval_repr_at(fplot_tgt, source=qbx_tgt_tol) except QBXTargetAssociationFailedException as e: fplot.write_vtk_file( "failed-targets.vts", [ ("failed_targets", e.failed_target_flags.get(queue)) ]) raise fplot_repr = EHField(vector_from_device(queue, fplot_repr)) fplot_inc = EHField( vector_from_device(queue, eval_inc_field_at(fplot_tgt))) fplot.write_vtk_file( "potential-%s.vts" % resolution, [ ("E", fplot_repr.e), ("H", fplot_repr.h), ("Einc", fplot_inc.e), ("Hinc", fplot_inc.h), ] ) # }}} # {{{ error in E, H obs_repr = EHField(eval_repr_at(obs_discr)) def obs_norm(f): return norm(obs_discr, queue, f, p=np.inf) rel_err_e = (obs_norm(inc_field_obs.e + obs_repr.e) / obs_norm(inc_field_obs.e)) rel_err_h = (obs_norm(inc_field_obs.h + obs_repr.h) / obs_norm(inc_field_obs.h)) # }}} print("ERR", h_max, rel_err_h, rel_err_e) eoc_rec_h.add_data_point(h_max, rel_err_h) eoc_rec_e.add_data_point(h_max, rel_err_e) print("--------------------------------------------------------") print("is_interior=%s" % case.is_interior) print("--------------------------------------------------------") good = True for which_eoc, eoc_rec, order_tol in [ ("maxwell", eoc_rec_repr_maxwell, 1.5), ("PEC BC", eoc_pec_bc, 1.5), ("H", eoc_rec_h, 1.5), ("E", eoc_rec_e, 1.5)]: print(which_eoc) print(eoc_rec.pretty_print()) if len(eoc_rec.history) > 1: if eoc_rec.order_estimate() < case.qbx_order - order_tol: good = False assert good