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,109 @@ 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+ \sum_{k=0}^{\text{order}} \frac{g_k}{k!} \tau^k,
184+
185+ where:
186+
187+ .. math::
188+ g_k := \frac{d^k}{d\tau^k} \left(
189+ \frac{\text{kernel}(l(\tau))}{\text{asymptotic}(l(\tau))} \right) \bigg|_{\tau=0}
190+ """
191+
192+ def __init__ (self ,
193+ kernel ,
194+ asymptotic ,
195+ order ,
196+ tau = 1 ,
197+ use_rscale = None ,
198+ m2l_translation = None ):
199+ super ().__init__ (kernel , order , use_rscale , m2l_translation )
200+ self .asymptotic = asymptotic
201+ self .tau = tau
202+
203+ def get_storage_index (self , k ):
204+ return k
205+
206+ def get_coefficient_identifiers (self ):
207+ return list (range (self .order + 1 ))
208+
209+ def get_asymptotic_expression (self , scaled_dist_vec ):
210+ from sumpy .symbolic import PymbolicToSympyMapperWithSymbols , Symbol
211+
212+ expr = PymbolicToSympyMapperWithSymbols ()(self .asymptotic )
213+ expr = expr .xreplace ({Symbol (f"d{ i } " ): dist_vec_i
214+ for i , dist_vec_i in enumerate (scaled_dist_vec )})
215+
216+ tau = sym .Symbol ("tau" )
217+
218+ b = scaled_dist_vec .applyfunc (lambda expr : expr .coeff (tau ))
219+ a = scaled_dist_vec - tau * b
220+ expr = expr .subs ({Symbol (f"a{ i } " ): a_i for i , a_i in enumerate (a )})
221+ expr = expr .subs ({Symbol (f"b{ i } " ): b_i for i , b_i in enumerate (b )})
222+
223+ return expr
224+
225+ def coefficients_from_source (self , kernel , avec , bvec , rscale , sac = None ):
226+ # no point in heeding rscale here--just ignore it
227+ if bvec is None :
228+ raise RuntimeError ("cannot use line-Taylor expansions in a setting "
229+ "where the center-target vector is not known at coefficient "
230+ "formation" )
231+
232+ tau = sym .Symbol ("tau" )
233+
234+ avec_line = avec + tau * bvec
235+ line_kernel = (
236+ kernel .get_expression (avec_line )
237+ / self .get_asymptotic_expression (avec_line ))
238+
239+ from sumpy .symbolic import USE_SYMENGINE
240+ if USE_SYMENGINE :
241+
242+ from sumpy .derivative_taker import ExprDerivativeTaker
243+ deriv_taker = ExprDerivativeTaker (line_kernel , (tau ,), sac = sac , rscale = 1 )
244+
245+ return [kernel .postprocess_at_source (
246+ deriv_taker .diff (i ), avec ).subs (tau , 0 )
247+ for i in self .get_coefficient_identifiers ()]
248+ else :
249+ # Workaround for sympy. The automatic distribution after
250+ # single-variable diff makes the expressions very large
251+ # (https://github.com/sympy/sympy/issues/4596), so avoid doing
252+ # single variable diff.
253+ #
254+ # See also https://gitlab.tiker.net/inducer/pytential/merge_requests/12
255+
256+ return [kernel .postprocess_at_source (
257+ line_kernel .diff (tau , i ), avec )
258+ .subs (tau , 0 )
259+ for i in self .get_coefficient_identifiers ()]
260+
261+ def evaluate (self , tgt_kernel , coeffs , bvec , rscale , sac = None ):
262+ # no point in heeding rscale here--just ignore it
263+
264+ return sym .Add (* (
265+ coeffs [self .get_storage_index (i )] / math .factorial (i ) * self .tau ** i
266+ for i in self .get_coefficient_identifiers ()))
267+
268+ def translate_from (self , src_expansion , src_coeff_exprs , src_rscale ,
269+ dvec , tgt_rscale , sac = None , m2l_translation_classes_dependent_data = None ):
270+ raise NotImplementedError
271+
272+ # }}}
273+
274+
166275# {{{ volume taylor
167276
168277class VolumeTaylorLocalExpansionBase (VolumeTaylorExpansionMixin , LocalExpansionBase ):
0 commit comments