def __init__(self, dim=None, helmholtz_k_name="k", allow_evanescent=False): """ :arg helmholtz_k_name: The argument name to use for the Helmholtz parameter when generating functions to evaluate this kernel. """ k = var(helmholtz_k_name) # Guard against code using the old positional interface. assert isinstance(allow_evanescent, bool) if dim == 2: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) expr = var("hankel_1")(0, k*r) scaling = var("I")/4 elif dim == 3: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) expr = var("exp")(var("I")*k*r)/r scaling = 1/(4*var("pi")) elif dim is None: expr = None scaling = None else: raise RuntimeError("unsupported dimensionality") ExpressionKernel.__init__( self, dim, expression=expr, scaling=scaling, is_complex_valued=True) self.helmholtz_k_name = helmholtz_k_name self.allow_evanescent = allow_evanescent
def __init__(self, dim=None, icomp=None, jcomp=None, viscosity_mu_name="mu", stresslet_vector_name="stresslet_vec"): """ :arg viscosity_mu_name: The argument name to use for dynamic viscosity :math:`\mu` the then generating functions to evaluate this kernel. """ # Mu is unused but kept for consistency with the stokeslet. if dim == 2: d = make_sym_vector("d", dim) n = make_sym_vector(stresslet_vector_name, dim) r = pymbolic_real_norm_2(d) expr = ( sum(n[axis]*d[axis] for axis in range(dim)) * d[icomp]*d[jcomp]/r**4 ) scaling = 1/(var("pi")) elif dim == 3: d = make_sym_vector("d", dim) n = make_sym_vector(stresslet_vector_name, dim) r = pymbolic_real_norm_2(d) expr = ( sum(n[axis]*d[axis] for axis in range(dim)) * d[icomp]*d[jcomp]/r**5 ) scaling = -3/(4*var("pi")) elif dim is None: expr = None scaling = None else: raise RuntimeError("unsupported dimensionality") self.viscosity_mu_name = viscosity_mu_name self.stresslet_vector_name = stresslet_vector_name self.icomp = icomp self.jcomp = jcomp ExpressionKernel.__init__( self, dim, expression=expr, scaling=scaling, is_complex_valued=False)
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)
def __init__(self, dim=None, yukawa_lambda_name="lam"): """ :arg yukawa_lambda_name: The argument name to use for the Yukawa parameter when generating functions to evaluate this kernel. """ lam = var(yukawa_lambda_name) if dim == 2: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) # http://dlmf.nist.gov/10.27#E8 expr = var("hankel_1")(0, var("I")*lam*r) scaling_for_K0 = 1/2*var("pi")*var("I") # noqa: N806 scaling = -1/(2*var("pi")) * scaling_for_K0 else: raise RuntimeError("unsupported dimensionality") super(YukawaKernel, self).__init__( dim, expression=expr, global_scaling_const=scaling, is_complex_valued=True) self.yukawa_lambda_name = yukawa_lambda_name
def __init__(self, dim=None): # See (Kress LIE, Thm 6.2) for scaling if dim == 2: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) expr = var("log")(r) scaling = 1/(-2*var("pi")) elif dim == 3: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) expr = 1/r scaling = 1/(4*var("pi")) else: raise NotImplementedError("unsupported dimensionality") super(LaplaceKernel, self).__init__( dim, expression=expr, global_scaling_const=scaling, is_complex_valued=False)
def __init__(self, dim, icomp, jcomp, viscosity_mu_name="mu"): """ :arg viscosity_mu_name: The argument name to use for dynamic viscosity :math:`\mu` the then generating functions to evaluate this kernel. """ mu = var(viscosity_mu_name) if dim == 2: d = make_sym_vector("d", dim) r = pymbolic_real_norm_2(d) expr = ( -var("log")(r)*(1 if icomp == jcomp else 0) + d[icomp]*d[jcomp]/r**2 ) scaling = 1/(4*var("pi")*mu) elif dim == 3: d = make_sym_vector("d", dim) r = pymbolic_real_norm_2(d) expr = ( (1/r)*(1 if icomp == jcomp else 0) + d[icomp]*d[jcomp]/r**3 ) scaling = -1/(8*var("pi")*mu) elif dim is None: expr = None scaling = None else: raise RuntimeError("unsupported dimensionality") self.viscosity_mu_name = viscosity_mu_name self.icomp = icomp self.jcomp = jcomp ExpressionKernel.__init__( self, dim, expression=expr, scaling=scaling, is_complex_valued=False)
def _norm_inf_op(discr, num_components): from pytential import sym, bind if num_components is not None: from pymbolic.primitives import make_sym_vector v = make_sym_vector("arg", num_components) max_arg = sym.abs(v) else: max_arg = sym.abs(sym.var("arg")) return bind(discr, sym.NodeMax(max_arg))
def _norm_op(discr, num_components): from pytential import sym, bind if num_components is not None: from pymbolic.primitives import make_sym_vector v = make_sym_vector("integrand", num_components) integrand = sym.real(np.dot(sym.conj(v), v)) else: integrand = sym.abs(sym.var("integrand"))**2 return bind(discr, sym.integral(integrand))
def __init__(self, dim=None, icomp=None, jcomp=None, kcomp=None, viscosity_mu_name="mu"): r""" :arg viscosity_mu_name: The argument name to use for dynamic viscosity :math:`\mu` the then generating functions to evaluate this kernel. """ # Mu is unused but kept for consistency with the stokeslet. if dim == 2: d = make_sym_vector("d", dim) r = pymbolic_real_norm_2(d) expr = ( d[icomp]*d[jcomp]*d[kcomp]/r**4 ) scaling = 1/(var("pi")) elif dim == 3: d = make_sym_vector("d", dim) r = pymbolic_real_norm_2(d) expr = ( d[icomp]*d[jcomp]*d[kcomp]/r**5 ) scaling = 3/(4*var("pi")) elif dim is None: expr = None scaling = None else: raise RuntimeError("unsupported dimensionality") self.viscosity_mu_name = viscosity_mu_name self.icomp = icomp self.jcomp = jcomp self.kcomp = kcomp super(StressletKernel, self).__init__( dim, expression=expr, global_scaling_const=scaling, is_complex_valued=False)
def __init__(self, dim=None): # See (Kress LIE, Thm 6.2) for scaling if dim == 2: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) expr = var("log")(r) scaling = 1/(-2*var("pi")) elif dim == 3: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) expr = 1/r scaling = 1/(4*var("pi")) elif dim is None: expr = None scaling = None else: raise RuntimeError("unsupported dimensionality") ExpressionKernel.__init__( self, dim, expression=expr, scaling=scaling, is_complex_valued=False)
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)
def __init__(self, dim=None): r = pymbolic_real_norm_2(make_sym_vector("d", dim)) if dim == 2: expr = r**2 * var("log")(r) scaling = 1/(8*var("pi")) elif dim == 3: expr = r scaling = 1 # FIXME: Unknown else: raise RuntimeError("unsupported dimensionality") super(BiharmonicKernel, self).__init__( dim, expression=expr, global_scaling_const=scaling, is_complex_valued=False)
def get_decaying_trig(dim, alpha): # 1D: u(x,t) = exp(-alpha*t)*cos(x) # 2D: u(x,y,t) = exp(-2*alpha*t)*sin(x)*cos(y) # 3D: u(x,y,z,t) = exp(-3*alpha*t)*sin(x)*sin(y)*cos(z) # on [-pi/2, pi/2]^{#dims} def get_mesh(n): dim_names = ["x", "y", "z"] neumann_boundaries = [] for i in range(dim - 1): neumann_boundaries += ["+" + dim_names[i], "-" + dim_names[i]] dirichlet_boundaries = [ "+" + dim_names[dim - 1], "-" + dim_names[dim - 1] ] from meshmode.mesh.generation import generate_regular_rect_mesh return generate_regular_rect_mesh(a=(-0.5 * np.pi, ) * dim, b=(0.5 * np.pi, ) * dim, n=(n, ) * dim, boundary_tag_to_face={ "dirichlet": dirichlet_boundaries, "neumann": neumann_boundaries }) sym_coords = prim.make_sym_vector("x", dim) sym_t = pmbl.var("t") sym_cos = pmbl.var("cos") sym_sin = pmbl.var("sin") sym_exp = pmbl.var("exp") sym_u = sym_exp(-dim * alpha * sym_t) for i in range(dim - 1): sym_u *= sym_sin(sym_coords[i]) sym_u *= sym_cos(sym_coords[dim - 1]) def get_boundaries(discr, actx, t): return { grudge_sym.DTAG_BOUNDARY("dirichlet"): DirichletDiffusionBoundary(0.), grudge_sym.DTAG_BOUNDARY("neumann"): NeumannDiffusionBoundary(0.), } return HeatProblem(dim, alpha, get_mesh, sym_u, get_boundaries)
def __init__(self, dim=None, yukawa_lambda_name="lam"): """ :arg yukawa_lambda_name: The argument name to use for the Yukawa parameter when generating functions to evaluate this kernel. """ lam = var(yukawa_lambda_name) # NOTE: The Yukawa kernel is given by [1] # -1/(2 pi)**(n/2) * (lam/r)**(n/2-1) * K(n/2-1, lam r) # where K is a modified Bessel function of the second kind. # # [1] https://en.wikipedia.org/wiki/Green%27s_function # [2] http://dlmf.nist.gov/10.27#E8 # [3] https://dlmf.nist.gov/10.47#E2 # [4] https://dlmf.nist.gov/10.49 r = pymbolic_real_norm_2(make_sym_vector("d", dim)) if dim == 2: # NOTE: transform K(0, lam r) into a Hankel function using [2] expr = var("hankel_1")(0, var("I")*lam*r) scaling_for_K0 = var("pi")/2*var("I") # noqa: N806 scaling = -1/(2*var("pi")) * scaling_for_K0 elif dim == 3: # NOTE: to get the expression, we do the following and simplify # 1. express K(1/2, lam r) as a modified spherical Bessel function # k(0, lam r) using [3] and use expression for k(0, lam r) from [4] # 2. or use (AS 10.2.17) directly expr = var("exp")(-lam*r) / r scaling = -1/(4 * var("pi")**2) else: raise RuntimeError("unsupported dimensionality") super(YukawaKernel, self).__init__( dim, expression=expr, global_scaling_const=scaling, is_complex_valued=True) self.yukawa_lambda_name = yukawa_lambda_name
def __init__(self, dim=None): r = pymbolic_real_norm_2(make_sym_vector("d", dim)) if dim == 2: # Ref: Farkas, Peter. Mathematical foundations for fast algorithms # for the biharmonic equation. Technical Report 765, # Department of Computer Science, Yale University, 1990. expr = r**2 * var("log")(r) scaling = 1 / (8 * var("pi")) elif dim == 3: # Ref: Jiang, Shidong, Bo Ren, Paul Tsuji, and Lexing Ying. # "Second kind integral equations for the first kind Dirichlet problem # of the biharmonic equation in three dimensions." # Journal of Computational Physics 230, no. 19 (2011): 7488-7501. expr = r scaling = -1 / (8 * var("pi")) else: raise RuntimeError("unsupported dimensionality") super().__init__(dim, expression=expr, global_scaling_const=scaling, is_complex_valued=False)
def run_symbolic_step(self, phase_name, shapes=None): """ `shapes` maps variable names to vector lengths. """ if shapes is None: shapes = {} phase = self.code.phases[phase_name] from pymbolic import var self.context.clear() from pymbolic.primitives import make_sym_vector # Includes variables expanded into vector components components = [] # Initial values, as variables / subscripts. Matched with "components" initial_vals = [] for vname in self.variables: if vname in shapes and shapes[vname] > 1: ival = make_sym_vector(vname+"_0", shapes[vname]) initial_vals.extend(ival) names = [self.VectorComponent(vname, i) for i in range(len(ival))] components.extend(names) else: ival = var(vname+"_0") initial_vals.append(ival) components.append(vname) self.context[vname] = ival self.context["<dt>"] = var("<dt>") self.context["<t>"] = 0 self.exec_controller.reset() self.exec_controller.update_plan(phase, phase.depends_on) for _event in self.exec_controller(phase, self): pass return components, initial_vals
def get_static_trig_var_diff(dim): def get_mesh(n): return get_box_mesh(dim, -0.5 * np.pi, 0.5 * np.pi, n) sym_coords = prim.make_sym_vector("x", dim) sym_cos = pmbl.var("cos") sym_sin = pmbl.var("sin") sym_alpha = 1 for i in range(dim): sym_alpha *= sym_cos(3. * sym_coords[i]) sym_alpha = 1 + 0.2 * sym_alpha sym_u = 1 for i in range(dim - 1): sym_u *= sym_sin(sym_coords[i]) sym_u *= sym_cos(sym_coords[dim - 1]) def get_boundaries(discr, actx, t): boundaries = {} for i in range(dim - 1): boundaries[DTAG_BOUNDARY("-" + str(i))] = NeumannDiffusionBoundary(0.) boundaries[DTAG_BOUNDARY("+" + str(i))] = NeumannDiffusionBoundary(0.) boundaries[DTAG_BOUNDARY("-" + str(dim - 1))] = DirichletDiffusionBoundary(0.) boundaries[DTAG_BOUNDARY("+" + str(dim - 1))] = DirichletDiffusionBoundary(0.) return boundaries return HeatProblem(dim, get_mesh, sym_alpha, sym_u, get_boundaries)
def __init__(self, dim=None, yukawa_lambda_name="lam"): """ :arg yukawa_lambda_name: The argument name to use for the Yukawa parameter when generating functions to evaluate this kernel. """ lam = var(yukawa_lambda_name) if dim == 2: r = pymbolic_real_norm_2(make_sym_vector("d", dim)) # http://dlmf.nist.gov/10.27#E8 expr = var("hankel_1")(0, var("I") * lam * r) scaling_for_K0 = 1 / 2 * var("pi") * var("I") # noqa: N806 scaling = -1 / (2 * var("pi")) * scaling_for_K0 else: raise RuntimeError("unsupported dimensionality") super(YukawaKernel, self).__init__(dim, expression=expr, global_scaling_const=scaling, is_complex_valued=True) self.yukawa_lambda_name = yukawa_lambda_name
def map_multivector_field(self, expr): from pymbolic.primitives import make_sym_vector return MultiVector( make_sym_vector( expr.name, self.ambient_dim, var_class=p.Field))
def map_multivector_variable(self, expr): from pymbolic.primitives import make_sym_vector return MultiVector( make_sym_vector(expr.name, self.ambient_dim, var_factory=type(expr)))
def grad(dim, func): """Return the symbolic *dim*-dimensional gradient of *func*.""" coords = prim.make_sym_vector("x", dim) return [diff(coords[i])(func) for i in range(dim)]
def get_decaying_trig_truncated_domain(dim, alpha): # 1D: u(x,t) = exp(-alpha*t)*cos(x) # 2D: u(x,y,t) = exp(-2*alpha*t)*sin(x)*cos(y) # 3D: u(x,y,z,t) = exp(-3*alpha*t)*sin(x)*sin(y)*cos(z) # on [-pi/2, pi/4]^{#dims} def get_mesh(n): dim_names = ["x", "y", "z"] neumann_lower_boundaries = ["-" + dim_names[i] for i in range(dim - 1)] neumann_upper_boundaries = ["+" + dim_names[i] for i in range(dim - 1)] dirichlet_lower_boundaries = ["-" + dim_names[dim - 1]] dirichlet_upper_boundaries = ["+" + dim_names[dim - 1]] from meshmode.mesh.generation import generate_regular_rect_mesh return generate_regular_rect_mesh(a=(-0.5 * np.pi, ) * dim, b=(0.25 * np.pi, ) * dim, n=(n, ) * dim, boundary_tag_to_face={ "dirichlet_lower": dirichlet_lower_boundaries, "dirichlet_upper": dirichlet_upper_boundaries, "neumann_lower": neumann_lower_boundaries, "neumann_upper": neumann_upper_boundaries }) sym_coords = prim.make_sym_vector("x", dim) sym_t = pmbl.var("t") sym_cos = pmbl.var("cos") sym_sin = pmbl.var("sin") sym_exp = pmbl.var("exp") sym_u = sym_exp(-dim * alpha * sym_t) for i in range(dim - 1): sym_u *= sym_sin(sym_coords[i]) sym_u *= sym_cos(sym_coords[dim - 1]) def get_boundaries(discr, actx, t): nodes = thaw(actx, discr.nodes()) def sym_eval(expr): return sym.EvaluationMapper({"x": nodes, "t": t})(expr) dirichlet_lower_btag = grudge_sym.DTAG_BOUNDARY("dirichlet_lower") dirichlet_upper_btag = grudge_sym.DTAG_BOUNDARY("dirichlet_upper") neumann_lower_btag = grudge_sym.DTAG_BOUNDARY("neumann_lower") neumann_upper_btag = grudge_sym.DTAG_BOUNDARY("neumann_upper") exact_u = sym_eval(sym_u) exact_grad_u = make_obj_array(sym_eval(sym.grad(dim, sym_u))) upper_u = discr.project("vol", dirichlet_upper_btag, exact_u) upper_grad_u = discr.project("vol", neumann_upper_btag, exact_grad_u) normal = thaw(actx, discr.normal(neumann_upper_btag)) upper_grad_u_dot_n = np.dot(upper_grad_u, normal) return { dirichlet_lower_btag: DirichletDiffusionBoundary(0.), dirichlet_upper_btag: DirichletDiffusionBoundary(upper_u), neumann_lower_btag: NeumannDiffusionBoundary(0.), neumann_upper_btag: NeumannDiffusionBoundary(upper_grad_u_dot_n) } return HeatProblem(dim, alpha, get_mesh, sym_u, get_boundaries)
def make_sym_mv(name, num_components): return MultiVector(make_sym_vector(name, num_components))