diff --git a/sumpy/expansion/__init__.py b/sumpy/expansion/__init__.py index afdd9248110efb84e04c9ca231a68900ea15aa1a..8ba654af8114a8ef41893d6a957c6b7f9ffc8f2b 100644 --- a/sumpy/expansion/__init__.py +++ b/sumpy/expansion/__init__.py @@ -192,6 +192,13 @@ class DerivativeWrangler(object): res = sorted(gnitstam(self.order, self.dim), key=sum) return res + @memoize_method + def get_wrangler_of_order(self, order): + obj = self.__class__.__new__(self.__class__) + obj.order = order + obj.dim = self.dim + return obj + class FullDerivativeWrangler(DerivativeWrangler): @@ -391,8 +398,14 @@ class LinearRecurrenceBasedDerivativeWrangler(DerivativeWrangler): raise NotImplementedError def get_derivative_taker(self, expr, var_list): - from sumpy.tools import NewLinearRecurrenceBasedMiDerivativeTaker - return NewLinearRecurrenceBasedMiDerivativeTaker(expr, var_list, self) + from sumpy.tools import MiDerivativeTaker + return MiDerivativeTaker(expr, var_list) + + @memoize_method + def get_wrangler_of_order(self, order): + obj = DerivativeWrangler.get_wrangler_of_order(self, order) + obj.deriv_multiplier = self.deriv_multiplier + return obj class LaplaceDerivativeWrangler(LinearRecurrenceBasedDerivativeWrangler): diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index 483bc0eb16fcee7b43d54aedb4eaa8092f593620..dc55797cf2d6f9a6a5be1ca2945dda7c2a2af115 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -167,19 +167,44 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): from sumpy.tools import add_mi + src_max_sum = max(sum(mi) for mi in + src_expansion.get_coefficient_identifiers()) + tgt_max_sum = max(sum(mi) for mi in + self.get_coefficient_identifiers()) + + max_sum = src_max_sum + tgt_max_sum + new_deriv_wrangler = \ + src_expansion.derivative_wrangler.get_wrangler_of_order(max_sum) + new_coeffs = new_deriv_wrangler.get_coefficient_identifiers() + new_full_coeffs = new_deriv_wrangler.get_full_coefficient_identifiers() + + ident_to_index = dict((ident, i) for i, ident in + enumerate(new_full_coeffs)) + result = [] for deriv in self.get_coefficient_identifiers(): local_result = [] + + full_coeffs = [0] * len(new_full_coeffs) for coeff, term in zip( src_coeff_exprs, src_expansion.get_coefficient_identifiers()): + full_coeffs[ident_to_index[add_mi(deriv, term)]] = coeff + + stored_coeffs = \ + new_deriv_wrangler.get_stored_mpole_coefficients_from_full( + full_coeffs, src_rscale) + for i, coeff in enumerate(stored_coeffs): + if coeff == 0: + continue + nderivatives_for_scaling = sum(new_coeffs[i])-sum(deriv) kernel_deriv = ( src_expansion.get_scaled_multipole( - taker.diff(add_mi(deriv, term)), + taker.diff(new_coeffs[i]), dvec, src_rscale, - nderivatives=sum(deriv) + sum(term), - nderivatives_for_scaling=sum(term))) + nderivatives=sum(new_coeffs[i]), + nderivatives_for_scaling=nderivatives_for_scaling)) local_result.append( coeff * kernel_deriv * tgt_rscale**sum(deriv)) diff --git a/sumpy/tools.py b/sumpy/tools.py index 730c52d275ec49c8f41d59b0edca93d57a5ebb00..91c7605060bd46d071093a9c6131f7a71a7f89d7 100644 --- a/sumpy/tools.py +++ b/sumpy/tools.py @@ -92,84 +92,6 @@ class MiDerivativeTaker(object): if (np.array(mi) >= np.array(other_mi)).all()), key=lambda other_mi: sum(self.mi_dist(mi, other_mi))) - -class LinearRecurrenceBasedMiDerivativeTaker(MiDerivativeTaker): - """ - The derivative taker for expansions that use - :class:`sumpy.expansion.LinearRecurrenceBasedDerivativeWrangler` - """ - - def __init__(self, expr, var_list, wrangler): - super(LinearRecurrenceBasedMiDerivativeTaker, self).__init__( - expr, var_list) - self.wrangler = wrangler - - @memoize_method - def diff(self, mi): - """ - :arg mi: a multi-index (tuple) indicating how many x/y derivatives are - to be taken. - """ - try: - expr = self.cache_by_mi[mi] - except KeyError: - from six import iteritems - from sumpy.symbolic import Add - - closest_mi = self.get_closest_cached_mi(mi) - expr = self.cache_by_mi[closest_mi] - - # Try to reduce the derivative using recurrences first, and if that - # fails fall back to derivative taking. - for next_deriv, next_mi in ( - self.get_derivative_taking_sequence(closest_mi, mi)): - - recurrence = ( - self.wrangler.try_get_recurrence_for_derivative( - next_mi, self.cache_by_mi)) - - if recurrence is not None: - expr = Add(*tuple( - coeff * self.cache_by_mi[ident] - for ident, coeff in iteritems(recurrence))) - else: - expr = expr.diff(next_deriv) - - self.cache_by_mi[next_mi] = expr - - return expr - - -class NewLinearRecurrenceBasedMiDerivativeTaker(MiDerivativeTaker): - """ - The derivative taker for expansions that use - :class:`sumpy.expansion.LinearRecurrenceBasedDerivativeWrangler` - """ - - def __init__(self, expr, var_list, wrangler): - super(NewLinearRecurrenceBasedMiDerivativeTaker, self).__init__( - expr, var_list) - self.wrangler = wrangler - - @memoize_method - def diff(self, mi): - """ - :arg mi: a multi-index (tuple) indicating how many x/y derivatives are - to be taken. - """ - try: - expr = self.cache_by_mi[mi] - except KeyError: - closest_mi = self.get_closest_cached_mi(mi) - expr = self.cache_by_mi[closest_mi] - - for next_deriv, next_mi in ( - self.get_derivative_taking_sequence(closest_mi, mi)): - expr = expr.diff(next_deriv) - self.cache_by_mi[next_mi] = expr - - return expr - # }}}