|
48 | 48 | from collections.abc import Sequence |
49 | 49 |
|
50 | 50 | import loopy as lp |
| 51 | + from pymbolic.typing import Expression |
51 | 52 |
|
52 | 53 | from sumpy.assignment_collection import SymbolicAssignmentCollection |
53 | 54 | from sumpy.expansion.diff_op import MultiIndex |
|
67 | 68 | .. autoclass:: H2DLocalExpansion |
68 | 69 | .. autoclass:: Y2DLocalExpansion |
69 | 70 | .. autoclass:: LineTaylorLocalExpansion |
| 71 | +.. autoclass:: AsymptoticDividingLineTaylorExpansion |
70 | 72 | """ |
71 | 73 |
|
72 | 74 |
|
@@ -145,6 +147,8 @@ def coefficients_from_source(self, |
145 | 147 | "formation") |
146 | 148 |
|
147 | 149 | tau = sym.Symbol("tau") |
| 150 | + # In the LineTaylor expansion, bvec is the expansion line. |
| 151 | + # It is not necessarily the target-center vector. |
148 | 152 | expansion_line = bvec |
149 | 153 | avec_line = avec + tau*expansion_line |
150 | 154 | line_kernel = kernel.get_expression(avec_line) |
@@ -216,90 +220,121 @@ def translate_from(self, |
216 | 220 |
|
217 | 221 | # {{{ Asymptotic dividing line Taylor expansion |
218 | 222 |
|
219 | | -# @dataclass(frozen=True) |
220 | | -# class AsymptoticDividingLineTaylorExpansion(LineTaylorLocalExpansion): |
221 | | -# r""" |
222 | | -# A target-specific modified line Taylor expansion. |
223 | | -# |
224 | | -# The expansion line is defined as :math:`l(\tau) = \text{avec} + \tau \cdot |
225 | | -# \text{bvec}` at a target point :math:`x`. The modified line Taylor expansion |
226 | | -# takes the form: |
227 | | -# |
228 | | -# .. math:: |
229 | | -# |
230 | | -# \sum_{k=0}^{\text{order}} \frac{g_k}{k!} \tau^k, |
231 | | -# |
232 | | -# where: |
233 | | -# |
234 | | -# .. math:: |
235 | | -# |
236 | | -# g_k := \frac{d^k}{d\tau^k} \left( |
237 | | -# \frac{\text{kernel}(l(\tau))}{\text{asymptotic}(l(\tau))} |
238 | | -# \right) \bigg|_{\tau=0} |
239 | | -# |
240 | | -# .. automethod:: get_asymptotic_expression |
241 | | -# """ |
242 | | -# |
243 | | -# asymptotic: Any = field(kw_only=True) |
244 | | -# |
245 | | -# def get_asymptotic_expression(self, scaled_dist_vec: sym.Matrix) -> sym.Expr: |
246 | | -# from sumpy.symbolic import PymbolicToSympyMapperWithSymbols, Symbol |
247 | | -# |
248 | | -# expr = PymbolicToSympyMapperWithSymbols()(self.asymptotic) |
249 | | -# expr = expr.xreplace({Symbol(f"d{i}"): dist_vec_i |
250 | | -# for i, dist_vec_i in enumerate(scaled_dist_vec)}) |
251 | | -# |
252 | | -# tau = sym.Symbol("tau") |
253 | | -# |
254 | | -# b = scaled_dist_vec.applyfunc(lambda expr: expr.coeff(tau)) |
255 | | -# a = scaled_dist_vec - tau*b |
256 | | -# expr = expr.subs({Symbol(f"a{i}"): a_i for i, a_i in enumerate(a)}) |
257 | | -# expr = expr.subs({Symbol(f"b{i}"): b_i for i, b_i in enumerate(b)}) |
258 | | -# |
259 | | -# return expr |
260 | | -# |
261 | | -# @override |
262 | | -# def coefficients_from_source(self, |
263 | | -# kernel: Kernel, |
264 | | -# avec: sym.Matrix, |
265 | | -# bvec: sym.Matrix | None, |
266 | | -# rscale: sym.Expr, |
267 | | -# sac: SymbolicAssignmentCollection | None = None |
268 | | -# ) -> Sequence[sym.Expr]: |
269 | | -# # no point in heeding rscale here--just ignore it |
270 | | -# if bvec is None: |
271 | | -# raise RuntimeError("cannot use line-Taylor expansions in a setting " |
272 | | -# "where the center-target vector is not known at coefficient " |
273 | | -# "formation") |
274 | | -# |
275 | | -# tau = sym.Symbol("tau") |
276 | | -# |
277 | | -# line_vec = bvec |
278 | | -# avec_line = avec + tau*line_vec |
279 | | -# line_kernel = ( |
280 | | -# kernel.get_expression(avec_line) |
281 | | -# / self.get_asymptotic_expression(avec_line)) |
282 | | -# |
283 | | -# from sumpy.symbolic import USE_SYMENGINE |
284 | | -# if USE_SYMENGINE: |
285 | | -# from sumpy.derivative_taker import ExprDerivativeTaker |
286 | | -# deriv_taker = ExprDerivativeTaker(line_kernel, (tau,), sac=sac, |
287 | | -# rscale=sym.sympify(1)) |
288 | | -# |
289 | | -# return [kernel.postprocess_at_source(deriv_taker.diff(i), avec) |
290 | | -# .subs(tau, 0) |
291 | | -# for i in self.get_coefficient_identifiers()] |
292 | | -# else: |
293 | | -# # Workaround for sympy. The automatic distribution after |
294 | | -# # single-variable diff makes the expressions very large |
295 | | -# # (https://github.com/sympy/sympy/issues/4596), so avoid doing |
296 | | -# # single variable diff. |
297 | | -# # |
298 | | -# # See also https://gitlab.tiker.net/inducer/pytential/merge_requests/12 |
299 | | -# |
300 | | -# return [kernel.postprocess_at_source(line_kernel.diff(tau, i), avec) |
301 | | -# .subs(tau, 0) |
302 | | -# for i, in self.get_coefficient_identifiers()] |
| 223 | +@dataclass(frozen=True) |
| 224 | +class AsymptoticDividingLineTaylorExpansion(LineTaylorLocalExpansion): |
| 225 | + r""" |
| 226 | + A target-specific asymptotic-dividing line Taylor expansion. |
| 227 | +
|
| 228 | + The asymptotic-dividing line Taylor expansion takes the form: |
| 229 | +
|
| 230 | + .. math:: |
| 231 | +
|
| 232 | + \text{asymptotic}(\tau \cdot \text{expansion}\_\text{vec}) \, |
| 233 | + \sum_{k=0}^{\text{order}} \frac{g_k}{k!} \tau^k, |
| 234 | +
|
| 235 | + where: |
| 236 | +
|
| 237 | + .. math:: |
| 238 | +
|
| 239 | + g_k := \frac{d^k}{d\tau^k} \left( |
| 240 | + \frac{\text{kernel}(\text{avec} |
| 241 | + + \tau \cdot \text{expansion}\_\text{vec})} |
| 242 | + {\text{asymptotic}(\tau \cdot \text{expansion}\_\text{vec})} |
| 243 | + \right) \bigg|_{\tau=0} |
| 244 | +
|
| 245 | + .. attribute:: asymptotic |
| 246 | +
|
| 247 | + A :mod:`pymbolic` expression for the asymptotic factor along the |
| 248 | + expansion line. May reference ``tau`` and ``b0, b1, ...`` (components |
| 249 | + of ``expansion_vec``). |
| 250 | +
|
| 251 | + .. automethod:: get_asymptotic_expression |
| 252 | + """ |
| 253 | + |
| 254 | + asymptotic: Expression |
| 255 | + |
| 256 | + def get_asymptotic_expression(self, |
| 257 | + asymptotic_line: sym.Matrix, |
| 258 | + tau: sym.Symbol | None = None |
| 259 | + ) -> sym.Expr: |
| 260 | + from sumpy.symbolic import PymbolicToSympyMapperWithSymbols, Symbol |
| 261 | + |
| 262 | + if tau is None: |
| 263 | + tau = sym.Symbol("tau") |
| 264 | + |
| 265 | + expansion_vec = asymptotic_line.applyfunc(lambda expr: expr.coeff(tau)) |
| 266 | + |
| 267 | + expr = PymbolicToSympyMapperWithSymbols()(self.asymptotic) |
| 268 | + expr = expr.subs({Symbol("tau"): tau}) |
| 269 | + expr = expr.subs({Symbol(f"b{i}"): b_i |
| 270 | + for i, b_i in enumerate(expansion_vec)}) |
| 271 | + |
| 272 | + return cast("sym.Expr", expr) |
| 273 | + |
| 274 | + @override |
| 275 | + def coefficients_from_source(self, |
| 276 | + kernel: Kernel, |
| 277 | + avec: sym.Matrix, |
| 278 | + bvec: sym.Matrix | None, |
| 279 | + rscale: sym.Expr, |
| 280 | + sac: SymbolicAssignmentCollection | None = None |
| 281 | + ) -> Sequence[sym.Expr]: |
| 282 | + # no point in heeding rscale here--just ignore it |
| 283 | + if bvec is None: |
| 284 | + raise RuntimeError("cannot use line-Taylor expansions in a setting " |
| 285 | + "where the center-target vector is not known at coefficient " |
| 286 | + "formation") |
| 287 | + |
| 288 | + tau = sym.Symbol("tau") |
| 289 | + |
| 290 | + expansion_vec = bvec |
| 291 | + # Here, we assume the asymptotic expansion is independent of the source. |
| 292 | + asymptotic_line = expansion_vec*tau |
| 293 | + avec_line = avec + asymptotic_line |
| 294 | + line_kernel = ( |
| 295 | + kernel.get_expression(avec_line) |
| 296 | + / self.get_asymptotic_expression(asymptotic_line, tau=tau)) |
| 297 | + |
| 298 | + from sumpy.symbolic import USE_SYMENGINE |
| 299 | + if USE_SYMENGINE: |
| 300 | + from sumpy.derivative_taker import ExprDerivativeTaker |
| 301 | + deriv_taker = ExprDerivativeTaker(line_kernel, (tau,), sac=sac, |
| 302 | + rscale=sym.sympify(1)) |
| 303 | + |
| 304 | + return [kernel.postprocess_at_source(deriv_taker.diff(i), avec) |
| 305 | + .subs(tau, 0) |
| 306 | + for i in self.get_coefficient_identifiers()] |
| 307 | + else: |
| 308 | + # Workaround for sympy. The automatic distribution after |
| 309 | + # single-variable diff makes the expressions very large |
| 310 | + # (https://github.com/sympy/sympy/issues/4596), so avoid doing |
| 311 | + # single variable diff. |
| 312 | + # |
| 313 | + # See also https://gitlab.tiker.net/inducer/pytential/merge_requests/12 |
| 314 | + |
| 315 | + return [kernel.postprocess_at_source(line_kernel.diff(tau, i), avec) |
| 316 | + .subs(tau, 0) |
| 317 | + for i, in self.get_coefficient_identifiers()] |
| 318 | + |
| 319 | + @override |
| 320 | + def evaluate(self, |
| 321 | + kernel: Kernel, |
| 322 | + coeffs: Sequence[sym.Expr], |
| 323 | + bvec: sym.Matrix, |
| 324 | + rscale: sym.Expr, |
| 325 | + sac: SymbolicAssignmentCollection | None = None, |
| 326 | + *, |
| 327 | + expansion_vec: sym.Matrix) -> sym.Expr: |
| 328 | + result = super().evaluate(kernel, coeffs, bvec, rscale, sac=sac, |
| 329 | + expansion_vec=expansion_vec) |
| 330 | + |
| 331 | + tau = sym.Symbol("tau") |
| 332 | + eval_tau = ((bvec.T*expansion_vec)[0, 0] |
| 333 | + / (expansion_vec.T*expansion_vec)[0, 0]) |
| 334 | + return ( |
| 335 | + result |
| 336 | + * self.get_asymptotic_expression(expansion_vec*tau, tau=tau) |
| 337 | + .subs(tau, eval_tau)) |
303 | 338 |
|
304 | 339 | # }}} |
305 | 340 |
|
|
0 commit comments