4848.. autoclass:: H2DLocalExpansion
4949.. autoclass:: Y2DLocalExpansion
5050.. autoclass:: LineTaylorLocalExpansion
51+ .. autoclass:: AsymptoticDividingLineTaylorExpansion
5152
5253"""
5354
@@ -106,6 +107,10 @@ def translate_from(self, src_expansion, src_coeff_exprs, src_rscale,
106107# {{{ line taylor
107108
108109class LineTaylorLocalExpansion (LocalExpansionBase ):
110+ def __init__ (self , kernel , order , tau = 1 , use_rscale = None , m2l_translation = None ):
111+ super ().__init__ (kernel , order , use_rscale , m2l_translation )
112+ self .tau = tau
113+
109114 def get_storage_index (self , k ):
110115 return k
111116
@@ -152,8 +157,9 @@ def evaluate(self, tgt_kernel, coeffs, bvec, rscale, sac=None):
152157
153158 # NOTE: We can't meaningfully apply target derivatives here.
154159 # Instead, this is handled in LayerPotentialBase._evaluate.
160+
155161 return sym .Add (* (
156- coeffs [self .get_storage_index (i )] / math .factorial (i )
162+ coeffs [self .get_storage_index (i )] / math .factorial (i ) * self . tau ** i
157163 for i in self .get_coefficient_identifiers ()))
158164
159165 def translate_from (self , src_expansion , src_coeff_exprs , src_rscale ,
@@ -163,6 +169,113 @@ def translate_from(self, src_expansion, src_coeff_exprs, src_rscale,
163169# }}}
164170
165171
172+ # {{{ Asymptotic dividing line Taylor expansion
173+
174+ class AsymptoticDividingLineTaylorExpansion (LocalExpansionBase ):
175+ r"""
176+ A target-specific modified line Taylor expansion.
177+
178+ The expansion line is defined as :math:`l(\tau) = \text{avec} + \tau \cdot
179+ \text{bvec}` at a target point :math:`x`. The modified line Taylor expansion takes
180+ the form:
181+
182+ .. math::
183+
184+ \sum_{k=0}^{\text{order}} \frac{g_k}{k!} \tau^k,
185+
186+ where:
187+
188+ .. math::
189+
190+ g_k := \frac{d^k}{d\tau^k} \left(
191+ \frac{\text{kernel}(l(\tau))}{\text{asymptotic}(l(\tau))} \right) \bigg|_{\tau=0}
192+
193+ .. automethod:: get_asymptotic_expression
194+ """
195+
196+ def __init__ (self ,
197+ kernel ,
198+ asymptotic ,
199+ order ,
200+ tau = 1 ,
201+ use_rscale = None ,
202+ m2l_translation = None ):
203+ super ().__init__ (kernel , order , use_rscale , m2l_translation )
204+ self .asymptotic = asymptotic
205+ self .tau = tau
206+
207+ def get_storage_index (self , k ):
208+ return k
209+
210+ def get_coefficient_identifiers (self ):
211+ return list (range (self .order + 1 ))
212+
213+ def get_asymptotic_expression (self , scaled_dist_vec ):
214+ from sumpy .symbolic import PymbolicToSympyMapperWithSymbols , Symbol
215+
216+ expr = PymbolicToSympyMapperWithSymbols ()(self .asymptotic )
217+ expr = expr .xreplace ({Symbol (f"d{ i } " ): dist_vec_i
218+ for i , dist_vec_i in enumerate (scaled_dist_vec )})
219+
220+ tau = sym .Symbol ("tau" )
221+
222+ b = scaled_dist_vec .applyfunc (lambda expr : expr .coeff (tau ))
223+ a = scaled_dist_vec - tau * b
224+ expr = expr .subs ({Symbol (f"a{ i } " ): a_i for i , a_i in enumerate (a )})
225+ expr = expr .subs ({Symbol (f"b{ i } " ): b_i for i , b_i in enumerate (b )})
226+
227+ return expr
228+
229+ def coefficients_from_source (self , kernel , avec , bvec , rscale , sac = None ):
230+ # no point in heeding rscale here--just ignore it
231+ if bvec is None :
232+ raise RuntimeError ("cannot use line-Taylor expansions in a setting "
233+ "where the center-target vector is not known at coefficient "
234+ "formation" )
235+
236+ tau = sym .Symbol ("tau" )
237+
238+ avec_line = avec + tau * bvec
239+ line_kernel = (
240+ kernel .get_expression (avec_line )
241+ / self .get_asymptotic_expression (avec_line ))
242+
243+ from sumpy .symbolic import USE_SYMENGINE
244+ if USE_SYMENGINE :
245+
246+ from sumpy .derivative_taker import ExprDerivativeTaker
247+ deriv_taker = ExprDerivativeTaker (line_kernel , (tau ,), sac = sac , rscale = 1 )
248+
249+ return [kernel .postprocess_at_source (
250+ deriv_taker .diff (i ), avec ).subs (tau , 0 )
251+ for i in self .get_coefficient_identifiers ()]
252+ else :
253+ # Workaround for sympy. The automatic distribution after
254+ # single-variable diff makes the expressions very large
255+ # (https://github.com/sympy/sympy/issues/4596), so avoid doing
256+ # single variable diff.
257+ #
258+ # See also https://gitlab.tiker.net/inducer/pytential/merge_requests/12
259+
260+ return [kernel .postprocess_at_source (
261+ line_kernel .diff (tau , i ), avec )
262+ .subs (tau , 0 )
263+ for i in self .get_coefficient_identifiers ()]
264+
265+ def evaluate (self , tgt_kernel , coeffs , bvec , rscale , sac = None ):
266+ # no point in heeding rscale here--just ignore it
267+
268+ return sym .Add (* (
269+ coeffs [self .get_storage_index (i )] / math .factorial (i ) * self .tau ** i
270+ for i in self .get_coefficient_identifiers ()))
271+
272+ def translate_from (self , src_expansion , src_coeff_exprs , src_rscale ,
273+ dvec , tgt_rscale , sac = None , m2l_translation_classes_dependent_data = None ):
274+ raise NotImplementedError
275+
276+ # }}}
277+
278+
166279# {{{ volume taylor
167280
168281class VolumeTaylorLocalExpansionBase (VolumeTaylorExpansionMixin , LocalExpansionBase ):
0 commit comments