diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index e321993367925b7be9fa56a48473ab9bd4e876ff..c20eaf20fe1223cfc7704c3fea878ffa3ba69f26 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -115,10 +115,36 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): type(self).__name__, self.order)) - from sumpy.tools import MiDerivativeTaker - expr = src_expansion.evaluate(src_coeff_exprs, dvec) - taker = MiDerivativeTaker(expr, dvec) - result = [taker.diff(mi) for mi in self.get_coefficient_identifiers()] + from sumpy.expansion.multipole import VolumeTaylorMultipoleExpansionBase + if isinstance(src_expansion, VolumeTaylorMultipoleExpansionBase): + # We know the general form of the multipole expansion is: + # + # coeff0 * diff(kernel, mi0) + coeff1 * diff(kernel, mi1) + ... + # + # To get the local expansion coefficients, we take derivatives of + # the multipole expansion. + # + # This code speeds up derivative taking by caching all kernel + # derivatives. + taker = src_expansion.get_kernel_derivative_taker(dvec) + + def mi_sum(a, b): + return tuple(aval + bval for aval, bval in zip(a, b)) + + result = [] + for deriv in self.get_coefficient_identifiers(): + local_result = [] + for coeff, term in zip( + src_coeff_exprs, + src_expansion.get_coefficient_identifiers()): + kernel_deriv = taker.diff(mi_sum(deriv, term)) + local_result.append(coeff * kernel_deriv) + result.append(sp.Add(*local_result)) + else: + from sumpy.tools import MiDerivativeTaker + expr = src_expansion.evaluate(src_coeff_exprs, dvec) + taker = MiDerivativeTaker(expr, dvec) + result = [taker.diff(mi) for mi in self.get_coefficient_identifiers()] logger.info("building translation operator: done") return result diff --git a/sumpy/expansion/multipole.py b/sumpy/expansion/multipole.py index 79412e17a248e2d647ddbfe5a7a410dfd6bc72d0..0444179588b49c987a5b604edf57ad9cc3a20303 100644 --- a/sumpy/expansion/multipole.py +++ b/sumpy/expansion/multipole.py @@ -89,16 +89,19 @@ class VolumeTaylorMultipoleExpansionBase(MultipoleExpansionBase): return self.full_to_stored(result) def evaluate(self, coeffs, bvec): - ppkernel = self.kernel.postprocess_at_target( - self.kernel.get_expression(bvec), bvec) - - from sumpy.tools import MiDerivativeTaker - taker = MiDerivativeTaker(ppkernel, bvec) + taker = self.get_kernel_derivative_taker(bvec) result = sum( coeff * taker.diff(mi) for coeff, mi in zip(coeffs, self.get_coefficient_identifiers())) return result + def get_kernel_derivative_taker(self, bvec): + ppkernel = self.kernel.postprocess_at_target( + self.kernel.get_expression(bvec), bvec) + + from sumpy.tools import MiDerivativeTaker + return MiDerivativeTaker(ppkernel, bvec) + def translate_from(self, src_expansion, src_coeff_exprs, dvec): if not isinstance(src_expansion, type(self)): raise RuntimeError("do not know how to translate %s to "