From 2e9e72767d7d995614c3884fd17dd86ae04d0f22 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Thu, 19 Mar 2020 00:20:59 -0500 Subject: [PATCH 01/17] Add FFT --- sumpy/tools.py | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/sumpy/tools.py b/sumpy/tools.py index 2719f43a..7cfe6138 100644 --- a/sumpy/tools.py +++ b/sumpy/tools.py @@ -3,6 +3,8 @@ from __future__ import division, absolute_import __copyright__ = """ Copyright (C) 2012 Andreas Kloeckner Copyright (C) 2018 Alexandru Fikl +Copyright (C) 2006-2019 SymPy Development Team +Copyright (C) 2020 Isuru Fernando """ __license__ = """ @@ -30,6 +32,8 @@ from six.moves import range, zip from pytools import memoize_method, memoize_in import numpy as np import sumpy.symbolic as sym +import numbers +import math import pyopencl as cl import pyopencl.array # noqa @@ -670,6 +674,8 @@ def my_syntactic_subs(expr, subst_dict): return expr +# {{{ matrices + def reduced_row_echelon_form(m): """Calculates a reduced row echelon form of a matrix `m`. @@ -760,4 +766,98 @@ def solve_symbolic(A, b): # noqa: N803 red = reduced_row_echelon_form(big)[0] return red[:, big.shape[0]:] +# }}} + + +# {{{ FFT + +def _fft_uneval_expr(expr): + """ + Creates a CSE node if the expr is not a numeric type + """ + if isinstance(expr, (numbers.Number, sym.Number, int, float, complex)): + return expr + # UnevaluatedExpr is not implemented in SymEngine, but that's fine + # as SymEngine doesn't distribute 2*(a+b) to 2*a + 2*b. + # SymPy distributes which destroys the complexity. + return sym.UnevaluatedExpr(expr) + + +def _complex_tuple_mul(a, b): + """ + Multiply the two complex numbers represented as a tuple + for real and imaginary parts + """ + return (_fft_uneval_expr((a[0]*b[0])-(a[1]*b[1])), + _fft_uneval_expr((a[0]*b[1])+(a[1]*b[0]))) + + +def _binary_reverse(n, bits): + # Returns the reverse of the number n in binary form with bits + # number of bits + b = bin(n)[2:].rjust(bits, "0") + return int(b[::-1], 2) + + +def fft(seq, inverse=False): + """ + Return the discrete fourier transform of the sequence seq. + seq should be a python iterable with tuples of length 2 + corresponding to the real part and imaginary part. + """ + + a = seq + n = len(a) + if n < 2: + return a + + b = n.bit_length() - 1 + if n & (n - 1): # not a power of 2 + b += 1 + n = 2**b + + a += [(0, 0)]*(n - len(a)) + for i in range(1, n): + j = _binary_reverse(i, b) + if i < j: + a[i], a[j] = a[j], a[i] + ang = -2*math.pi/n if inverse else 2*math.pi/n + + w = [(math.cos(ang*i), math.sin(ang*i)) for i in range(n // 2)] + for i in range(len(w)): + if abs(w[i][0]) == 1.0: + w[i] = (int(w[i][0]), 0) + if abs(w[i][1]) == 1.0: + w[i] = (0, int(w[i][1])) + + h = 2 + while h <= n: + hf, ut = h // 2, n // h + for i in range(0, n, h): + for j in range(hf): + u, v = a[i + j], _complex_tuple_mul(a[i + j + hf], w[ut * j]) + a[i + j] = (u[0] + v[0], u[1] + v[1]) + a[i + j + hf] = (u[0] - v[0], u[1] - v[1]) + h *= 2 + + if inverse: + a = [(x[0]/n, x[1]/n) for x in a] + + return a + + +def toeplitz(v, x): + """ + Returns the matvec of the Toeplitz matrix given by + the Toeplitz vector v and the vector x using a Fourier transform + """ + assert len(v) == len(x) + v_fft = fft([(a, 0) for a in v]) + x_fft = fft([(a, 0) for a in x]) + res_fft = [_complex_tuple_mul(a, b) for a, b in zip(v_fft, x_fft)] + res = fft(res_fft, inverse=True) + return [a for a, _ in res] + +# }}} + # vim: fdm=marker -- GitLab From ab662aaf4bf5dc88922ac7b84a96aff7a5679ea7 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sat, 21 Mar 2020 16:22:50 -0500 Subject: [PATCH 02/17] Generate Toeplitz matrix --- sumpy/expansion/local.py | 86 +++++++++++++++++++++++----------------- sumpy/symbolic.py | 2 +- sumpy/tools.py | 25 ++++++++++-- 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index c32778ae..2b8c8b3c 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -141,6 +141,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): for coeff, mi in zip( evaluated_coeffs, self.get_full_coefficient_identifiers())) + def translate_from(self, src_expansion, src_coeff_exprs, src_rscale, dvec, tgt_rscale): logger.info("building translation operator: %s(%d) -> %s(%d): start" @@ -168,6 +169,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): taker = src_expansion.get_kernel_derivative_taker(dvec) from sumpy.tools import add_mi + from pytools import generate_nonnegative_integer_tuples_below as gnitb max_mi = [0]*self.dim for i in range(self.dim): @@ -176,54 +178,64 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): max_mi[i] += max(mi[i] for mi in self.get_coefficient_identifiers()) + toeplitz_matrix_coeffs = list(gnitb([m + 1 for m in max_mi])) + toeplitz_matrix_ident_to_index = dict((ident, i) for i, ident in + enumerate(toeplitz_matrix_coeffs)) + # Create a expansion terms wrangler for derivatives up to order # (tgt order)+(src order) including a corresponding reduction matrix + # For eg: 2D full Taylor Laplace, this is (n, m), + # n+m<=2*p, n<=2*p, m<=2*p tgtplusderiv_exp_terms_wrangler = \ src_expansion.expansion_terms_wrangler.copy( order=self.order + src_expansion.order, max_mi=tuple(max_mi)) - tgtplusderiv_coeff_ids = \ - tgtplusderiv_exp_terms_wrangler.get_coefficient_identifiers() tgtplusderiv_full_coeff_ids = \ tgtplusderiv_exp_terms_wrangler.get_full_coefficient_identifiers() - tgtplusderiv_ident_to_index = dict((ident, i) for i, ident in enumerate(tgtplusderiv_full_coeff_ids)) + # The vector has the kernel derivatives and depends only on the distance + # between the two centers + taker = src_expansion.get_kernel_derivative_taker(dvec) + vector_stored = [] + # Calculate the kernel derivatives for the compressed set + for term in tgtplusderiv_exp_terms_wrangler.get_coefficient_identifiers(): + kernel_deriv = taker.diff(term) + vector_stored.append(kernel_deriv) + # Calculate the kernel derivatives for the full set + vector_full = tgtplusderiv_exp_terms_wrangler.get_full_kernel_derivatives_from_stored( + vector_stored, src_rscale) + + from sumpy.tools import add_mi + needed_vector_terms = set([]) + # For eg: 2D full Taylor Laplace, we only need kernel derivatives + # (n1+n2, m1+m2), n1+m1<=p, n2+m2<=p + for tgt_deriv in self.get_coefficient_identifiers(): + for src_deriv in src_expansion.get_coefficient_identifiers(): + needed = add_mi(src_deriv, tgt_deriv) + needed_vector_terms.add(needed) + + vector = [0]*len(toeplitz_matrix_coeffs) + for i, term in enumerate(toeplitz_matrix_coeffs): + if term in tgtplusderiv_ident_to_index: + vector[i] = vector_full[tgtplusderiv_ident_to_index[term]] + + # Calculate the first row of the upper triangular Toeplitz matrix + toeplitz_first_row = [0] * len(toeplitz_matrix_coeffs) + for coeff, term in zip( + src_coeff_exprs, + src_expansion.get_coefficient_identifiers()): + toeplitz_first_row[toeplitz_matrix_ident_to_index[term]] = coeff * src_rscale**sum(term) + + # Do the matvec + output = matvec_toeplitz_upper_triangular(toeplitz_first_row, vector) + + # Filter out the dummy rows and scale them for target result = [] - for lexp_mi in self.get_coefficient_identifiers(): - lexp_mi_terms = [] - - # Embed the source coefficients in the coefficient array - # for the (tgt order)+(src order) wrangler, offset by lexp_mi. - embedded_coeffs = [0] * len(tgtplusderiv_full_coeff_ids) - for coeff, term in zip( - src_coeff_exprs, - src_expansion.get_coefficient_identifiers()): - embedded_coeffs[ - tgtplusderiv_ident_to_index[add_mi(lexp_mi, term)]] \ - = coeff - - # Compress the embedded coefficient set - stored_coeffs = tgtplusderiv_exp_terms_wrangler \ - .get_stored_mpole_coefficients_from_full( - embedded_coeffs, src_rscale) - - # Sum the embedded coefficient set - for i, coeff in enumerate(stored_coeffs): - if coeff == 0: - continue - nderivatives_for_scaling = \ - sum(tgtplusderiv_coeff_ids[i])-sum(lexp_mi) - kernel_deriv = ( - src_expansion.get_scaled_multipole( - taker.diff(tgtplusderiv_coeff_ids[i]), - dvec, src_rscale, - nderivatives=sum(tgtplusderiv_coeff_ids[i]), - nderivatives_for_scaling=nderivatives_for_scaling)) - - lexp_mi_terms.append( - coeff * kernel_deriv * tgt_rscale**sum(lexp_mi)) - result.append(sym.Add(*lexp_mi_terms)) + for term in self.get_coefficient_identifiers(): + index = toeplitz_matrix_ident_to_index[term] + result.append(output[index]*tgt_rscale**sum(term)) + logger.info("building translation operator: done") return result diff --git a/sumpy/symbolic.py b/sumpy/symbolic.py index 7a86958a..e0f22671 100644 --- a/sumpy/symbolic.py +++ b/sumpy/symbolic.py @@ -76,7 +76,7 @@ _find_symbolic_backend() # Before adding a function here, make sure it's present in both modules. SYMBOLIC_API = """ Add Basic Mul Pow exp sqrt log symbols sympify cos sin atan2 Function Symbol -Derivative Integer Matrix Subs I pi functions""".split() +Derivative Integer Matrix Subs I pi functions Number""".split() if USE_SYMENGINE: import symengine as sym diff --git a/sumpy/tools.py b/sumpy/tools.py index 7cfe6138..ddd9800e 100644 --- a/sumpy/tools.py +++ b/sumpy/tools.py @@ -846,17 +846,34 @@ def fft(seq, inverse=False): return a -def toeplitz(v, x): +def fft_toeplitz_upper_triangular(first_row, x): """ Returns the matvec of the Toeplitz matrix given by - the Toeplitz vector v and the vector x using a Fourier transform + the first row and the vector x using a Fourier transform """ - assert len(v) == len(x) + assert len(first_row) == len(x) + n = len(first_row) + v = list(first_row) + v += [0]*(n-1) + + x = list(reversed(x)) + x += [0]*(n-1) + v_fft = fft([(a, 0) for a in v]) x_fft = fft([(a, 0) for a in x]) res_fft = [_complex_tuple_mul(a, b) for a, b in zip(v_fft, x_fft)] res = fft(res_fft, inverse=True) - return [a for a, _ in res] + return [a for a, _ in reversed(res[:n])] + + +def matvec_toeplitz_upper_triangular(first_row, vector): + n = len(first_row) + assert len(vector) == n + output = [0]*n + for row in range(n): + for col in range(row, n): + output[row] += first_row[col-row]*vector[col] + return output # }}} -- GitLab From 83e921419dcb83d04d0a968e463b1b67dd1cc73e Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sat, 21 Mar 2020 19:18:20 -0500 Subject: [PATCH 03/17] Fix missing import and formatting --- sumpy/expansion/local.py | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index 2b8c8b3c..1c24c7db 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -30,6 +30,9 @@ from sumpy.expansion import ( HelmholtzConformingVolumeTaylorExpansion, BiharmonicConformingVolumeTaylorExpansion) +from sumpy.tools import (matvec_toeplitz_upper_triangular, + fft_toeplitz_upper_triangular) + class LocalExpansionBase(ExpansionBase): pass @@ -141,9 +144,8 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): for coeff, mi in zip( evaluated_coeffs, self.get_full_coefficient_identifiers())) - def translate_from(self, src_expansion, src_coeff_exprs, src_rscale, - dvec, tgt_rscale): + dvec, tgt_rscale, use_fft=False): logger.info("building translation operator: %s(%d) -> %s(%d): start" % (type(src_expansion).__name__, src_expansion.order, @@ -186,27 +188,28 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): # (tgt order)+(src order) including a corresponding reduction matrix # For eg: 2D full Taylor Laplace, this is (n, m), # n+m<=2*p, n<=2*p, m<=2*p - tgtplusderiv_exp_terms_wrangler = \ + srcplusderiv_terms_wrangler = \ src_expansion.expansion_terms_wrangler.copy( order=self.order + src_expansion.order, max_mi=tuple(max_mi)) - tgtplusderiv_full_coeff_ids = \ - tgtplusderiv_exp_terms_wrangler.get_full_coefficient_identifiers() - tgtplusderiv_ident_to_index = dict((ident, i) for i, ident in - enumerate(tgtplusderiv_full_coeff_ids)) + srcplusderiv_full_coeff_ids = \ + srcplusderiv_terms_wrangler.get_full_coefficient_identifiers() + srcplusderiv_ident_to_index = dict((ident, i) for i, ident in + enumerate(srcplusderiv_full_coeff_ids)) # The vector has the kernel derivatives and depends only on the distance # between the two centers taker = src_expansion.get_kernel_derivative_taker(dvec) vector_stored = [] # Calculate the kernel derivatives for the compressed set - for term in tgtplusderiv_exp_terms_wrangler.get_coefficient_identifiers(): + for term in \ + srcplusderiv_terms_wrangler.get_coefficient_identifiers(): kernel_deriv = taker.diff(term) vector_stored.append(kernel_deriv) # Calculate the kernel derivatives for the full set - vector_full = tgtplusderiv_exp_terms_wrangler.get_full_kernel_derivatives_from_stored( + vector_full = \ + srcplusderiv_terms_wrangler.get_full_kernel_derivatives_from_stored( vector_stored, src_rscale) - from sumpy.tools import add_mi needed_vector_terms = set([]) # For eg: 2D full Taylor Laplace, we only need kernel derivatives # (n1+n2, m1+m2), n1+m1<=p, n2+m2<=p @@ -217,18 +220,22 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): vector = [0]*len(toeplitz_matrix_coeffs) for i, term in enumerate(toeplitz_matrix_coeffs): - if term in tgtplusderiv_ident_to_index: - vector[i] = vector_full[tgtplusderiv_ident_to_index[term]] + if term in srcplusderiv_ident_to_index: + vector[i] = vector_full[srcplusderiv_ident_to_index[term]] # Calculate the first row of the upper triangular Toeplitz matrix toeplitz_first_row = [0] * len(toeplitz_matrix_coeffs) for coeff, term in zip( src_coeff_exprs, src_expansion.get_coefficient_identifiers()): - toeplitz_first_row[toeplitz_matrix_ident_to_index[term]] = coeff * src_rscale**sum(term) + toeplitz_first_row[toeplitz_matrix_ident_to_index[term]] = \ + coeff * src_rscale**sum(term) # Do the matvec - output = matvec_toeplitz_upper_triangular(toeplitz_first_row, vector) + if use_fft: + output = fft_toeplitz_upper_triangular(toeplitz_first_row, vector) + else: + output = matvec_toeplitz_upper_triangular(toeplitz_first_row, vector) # Filter out the dummy rows and scale them for target result = [] -- GitLab From a17c60fb14f1185908be6205e1aadc4615ee9cee Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sun, 22 Mar 2020 00:46:05 -0500 Subject: [PATCH 04/17] Fix rscaling --- sumpy/expansion/local.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index 1c24c7db..52cce2fc 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -203,7 +203,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): # Calculate the kernel derivatives for the compressed set for term in \ srcplusderiv_terms_wrangler.get_coefficient_identifiers(): - kernel_deriv = taker.diff(term) + kernel_deriv = taker.diff(term) * src_rscale**sum(term) vector_stored.append(kernel_deriv) # Calculate the kernel derivatives for the full set vector_full = \ @@ -228,8 +228,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): for coeff, term in zip( src_coeff_exprs, src_expansion.get_coefficient_identifiers()): - toeplitz_first_row[toeplitz_matrix_ident_to_index[term]] = \ - coeff * src_rscale**sum(term) + toeplitz_first_row[toeplitz_matrix_ident_to_index[term]] = coeff # Do the matvec if use_fft: @@ -241,7 +240,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): result = [] for term in self.get_coefficient_identifiers(): index = toeplitz_matrix_ident_to_index[term] - result.append(output[index]*tgt_rscale**sum(term)) + result.append(output[index]*(tgt_rscale/src_rscale)**sum(term)) logger.info("building translation operator: done") return result -- GitLab From 56682e04f8b620830fbff3b6c41a2f929df42c54 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sun, 22 Mar 2020 01:35:57 -0500 Subject: [PATCH 05/17] use get_scaled_multipole --- sumpy/expansion/local.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index 52cce2fc..0db59480 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -203,7 +203,12 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): # Calculate the kernel derivatives for the compressed set for term in \ srcplusderiv_terms_wrangler.get_coefficient_identifiers(): - kernel_deriv = taker.diff(term) * src_rscale**sum(term) + kernel_deriv = src_expansion.get_scaled_multipole( + taker.diff(term), + dvec, src_rscale, + nderivatives=sum(term), + nderivatives_for_scaling=sum(term), + ) vector_stored.append(kernel_deriv) # Calculate the kernel derivatives for the full set vector_full = \ -- GitLab From 0978271dcd3123662ea09a1f09c67502c50790f9 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sun, 22 Mar 2020 01:39:44 -0500 Subject: [PATCH 06/17] Use UnevaluatedExpr for the ratio of rscales --- sumpy/expansion/local.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index 0db59480..025ce5fe 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -243,9 +243,10 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): # Filter out the dummy rows and scale them for target result = [] + rscale_ratio = sym.UnevaluatedExpr(tgt_rscale/src_rscale) for term in self.get_coefficient_identifiers(): index = toeplitz_matrix_ident_to_index[term] - result.append(output[index]*(tgt_rscale/src_rscale)**sum(term)) + result.append(output[index]*rscale_ratio**sum(term)) logger.info("building translation operator: done") return result -- GitLab From 320cc8a4d6fc5dc97ee73eafdf1c1ba2b9b005c3 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Sun, 22 Mar 2020 11:23:02 -0500 Subject: [PATCH 07/17] Rewrite cosines and sines using cosines of angle in the first quadrant --- sumpy/tools.py | 46 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/sumpy/tools.py b/sumpy/tools.py index ddd9800e..84b45195 100644 --- a/sumpy/tools.py +++ b/sumpy/tools.py @@ -25,6 +25,36 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +============================================================================= +Copyright (c) 2006-2019 SymPy Development Team + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + a. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + b. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + c. Neither the name of SymPy nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. """ import six @@ -823,12 +853,16 @@ def fft(seq, inverse=False): a[i], a[j] = a[j], a[i] ang = -2*math.pi/n if inverse else 2*math.pi/n - w = [(math.cos(ang*i), math.sin(ang*i)) for i in range(n // 2)] - for i in range(len(w)): - if abs(w[i][0]) == 1.0: - w[i] = (int(w[i][0]), 0) - if abs(w[i][1]) == 1.0: - w[i] = (0, int(w[i][1])) + ang = 2*math.pi/n + # Rewrite cosines and sines using cosines of angle in the first quadrant + # This is to reduce duplicate of floating point numbers with 1 ULP difference + # and also make sure quantities like cos(pi/2) - sin(pi/2) produces 0 exactly. + w = [(math.cos(ang*i), math.cos(ang*(n/4.0 - i))) for i in range((n + 3)//4)] + w[0] = (1, 0) + w += [(-math.cos(ang*(n/2 - i)), math.cos(ang*(i - n/4.0))) for + i in range((n + 3)//4, n//2)] + if inverse: + w = [(a[0], -a[1]) for a in w] h = 2 while h <= n: -- GitLab From ef2731f35c365489d34a9d38238b00221ff48967 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Mon, 23 Mar 2020 23:30:37 -0500 Subject: [PATCH 08/17] Add a test to check for FFT --- sumpy/symbolic.py | 2 +- sumpy/tools.py | 5 ++--- test/test_tools.py | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 4 deletions(-) create mode 100644 test/test_tools.py diff --git a/sumpy/symbolic.py b/sumpy/symbolic.py index e0f22671..0fed239d 100644 --- a/sumpy/symbolic.py +++ b/sumpy/symbolic.py @@ -76,7 +76,7 @@ _find_symbolic_backend() # Before adding a function here, make sure it's present in both modules. SYMBOLIC_API = """ Add Basic Mul Pow exp sqrt log symbols sympify cos sin atan2 Function Symbol -Derivative Integer Matrix Subs I pi functions Number""".split() +Derivative Integer Matrix Subs I pi functions Number Float""".split() if USE_SYMENGINE: import symengine as sym diff --git a/sumpy/tools.py b/sumpy/tools.py index 84b45195..eebb9efb 100644 --- a/sumpy/tools.py +++ b/sumpy/tools.py @@ -851,8 +851,6 @@ def fft(seq, inverse=False): j = _binary_reverse(i, b) if i < j: a[i], a[j] = a[j], a[i] - ang = -2*math.pi/n if inverse else 2*math.pi/n - ang = 2*math.pi/n # Rewrite cosines and sines using cosines of angle in the first quadrant # This is to reduce duplicate of floating point numbers with 1 ULP difference @@ -861,9 +859,10 @@ def fft(seq, inverse=False): w[0] = (1, 0) w += [(-math.cos(ang*(n/2 - i)), math.cos(ang*(i - n/4.0))) for i in range((n + 3)//4, n//2)] + if n%4 == 0: + w[n//4] = (0, 1) if inverse: w = [(a[0], -a[1]) for a in w] - h = 2 while h <= n: hf, ut = h // 2, n // h diff --git a/test/test_tools.py b/test/test_tools.py new file mode 100644 index 00000000..eed6d304 --- /dev/null +++ b/test/test_tools.py @@ -0,0 +1,55 @@ +from __future__ import division, absolute_import, print_function + +__copyright__ = "Copyright (C) 2020 Isuru Fernando" + +__license__ = """ +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +""" + +import logging +logger = logging.getLogger(__name__) + +import sumpy.symbolic as sym +from sumpy.tools import (fft_toeplitz_upper_triangular, + matvec_toeplitz_upper_triangular) +import numpy as np + +def test_fft(): + k = 5 + v = np.random.rand(k) + x = np.random.rand(k) + + fft = fft_toeplitz_upper_triangular(v, x) + matvec = matvec_toeplitz_upper_triangular(v, x) + + for i in range(k): + assert abs(fft[i] - matvec[i]) < 1e-15 + + +def test_fft_small_floats(): + k = 5 + v = sym.make_sym_vector("v", k) + x = sym.make_sym_vector("x", k) + + fft = fft_toeplitz_upper_triangular(v, x) + for expr in fft: + for f in expr.atoms(sym.Float): + if f == 0: + continue + assert abs(f) > 1e-10 -- GitLab From 5001688caa7cf6ec15accf88cb61b7d72347fda2 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Tue, 24 Mar 2020 00:37:04 -0500 Subject: [PATCH 09/17] Fix formatting --- sumpy/tools.py | 2 +- test/test_tools.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sumpy/tools.py b/sumpy/tools.py index eebb9efb..7f979526 100644 --- a/sumpy/tools.py +++ b/sumpy/tools.py @@ -859,7 +859,7 @@ def fft(seq, inverse=False): w[0] = (1, 0) w += [(-math.cos(ang*(n/2 - i)), math.cos(ang*(i - n/4.0))) for i in range((n + 3)//4, n//2)] - if n%4 == 0: + if n % 4 == 0: w[n//4] = (0, 1) if inverse: w = [(a[0], -a[1]) for a in w] diff --git a/test/test_tools.py b/test/test_tools.py index eed6d304..743caa14 100644 --- a/test/test_tools.py +++ b/test/test_tools.py @@ -30,6 +30,7 @@ from sumpy.tools import (fft_toeplitz_upper_triangular, matvec_toeplitz_upper_triangular) import numpy as np + def test_fft(): k = 5 v = np.random.rand(k) -- GitLab From 76ac6fc7b0254c4417678bdf5e3d3fc04fb3c9e9 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Tue, 24 Mar 2020 00:54:55 -0500 Subject: [PATCH 10/17] Python2 has no notion of local variables --- sumpy/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sumpy/tools.py b/sumpy/tools.py index 7f979526..d6daeb45 100644 --- a/sumpy/tools.py +++ b/sumpy/tools.py @@ -862,7 +862,7 @@ def fft(seq, inverse=False): if n % 4 == 0: w[n//4] = (0, 1) if inverse: - w = [(a[0], -a[1]) for a in w] + w = [(x[0], -x[1]) for x in w] h = 2 while h <= n: hf, ut = h // 2, n // h -- GitLab From 166a20dd476cb3f440dfa217c56fa310ed9b202a Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Tue, 24 Mar 2020 21:26:20 -0500 Subject: [PATCH 11/17] Add a numeric test that M2L is toeplitz using simple translation --- test/test_kernels.py | 70 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/test/test_kernels.py b/test/test_kernels.py index 8225723c..a8af5827 100644 --- a/test/test_kernels.py +++ b/test/test_kernels.py @@ -45,6 +45,7 @@ from sumpy.expansion.local import ( from sumpy.kernel import (LaplaceKernel, HelmholtzKernel, AxisTargetDerivative, DirectionalSourceDerivative, BiharmonicKernel, StokesletKernel) from pytools.convergence import PConvergenceVerifier +import sumpy.symbolic as sym import logging logger = logging.getLogger(__name__) @@ -345,6 +346,75 @@ def test_p2e2p(ctx_getter, base_knl, expn_class, order, with_source_derivative): assert eoc_rec_pot.order_estimate() > tgt_order - slack assert eoc_rec_grad_x.order_estimate() > tgt_order_grad - grad_slack +# {{{ test toeplitz + +def _m2l_translate_simple(tgt_expansion, src_expansion, src_coeff_exprs, src_rscale, + dvec, tgt_rscale): + + if not tgt_expansion.use_rscale: + src_rscale = 1 + tgt_rscale = 1 + + from sumpy.expansion.multipole import VolumeTaylorMultipoleExpansionBase + if not isinstance(src_expansion, VolumeTaylorMultipoleExpansionBase): + return 1 + + # 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. + taker = src_expansion.get_kernel_derivative_taker(dvec) + + from sumpy.tools import add_mi + + result = [] + for deriv in tgt_expansion.get_coefficient_identifiers(): + local_result = [] + for coeff, term in zip( + src_coeff_exprs, + src_expansion.get_coefficient_identifiers()): + + kernel_deriv = ( + src_expansion.get_scaled_multipole( + taker.diff(add_mi(deriv, term)), + dvec, src_rscale, + nderivatives=sum(deriv) + sum(term), + nderivatives_for_scaling=sum(term))) + + local_result.append( + coeff * kernel_deriv * tgt_rscale**sum(deriv)) + result.append(sym.Add(*local_result)) + return result + + +def test_m2l_toeplitz(ctx_getter): + dim = 3 + knl = LaplaceKernel(dim) + local_expn_class = LaplaceConformingVolumeTaylorLocalExpansion + mpole_expn_class = LaplaceConformingVolumeTaylorMultipoleExpansion + + local_expn = local_expn_class(knl, order=5) + mpole_expn = mpole_expn_class(knl, order=5) + + dvec = sym.make_sym_vector("d", dim) + src_coeff_exprs = list(1 + np.random.randn(len(mpole_expn))) + src_rscale = 2.0 + tgt_rscale = 1.0 + + expected_output = _m2l_translate_simple(local_expn, mpole_expn, src_coeff_exprs, + src_rscale, dvec, tgt_rscale) + actual_output = local_expn.translate_from(mpole_expn, src_coeff_exprs, + src_rscale, dvec, tgt_rscale) + + replace_dict = dict((d, np.random.rand(1)[0]) for d in dvec) + for sym_a, sym_b in zip(expected_output, actual_output): + num_a = sym_a.xreplace(replace_dict) + num_b = sym_b.xreplace(replace_dict) + assert abs(num_a - num_b)/abs(num_a) < 1e-13 + +# }}} @pytest.mark.parametrize("knl, local_expn_class, mpole_expn_class", [ (LaplaceKernel(2), VolumeTaylorLocalExpansion, VolumeTaylorMultipoleExpansion), -- GitLab From 906abb36aeaaee96e936ff979299e8f893f9f57a Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Tue, 24 Mar 2020 22:43:35 -0500 Subject: [PATCH 12/17] Use 1e-10 for now --- test/test_kernels.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/test_kernels.py b/test/test_kernels.py index a8af5827..64c5b217 100644 --- a/test/test_kernels.py +++ b/test/test_kernels.py @@ -346,6 +346,7 @@ def test_p2e2p(ctx_getter, base_knl, expn_class, order, with_source_derivative): assert eoc_rec_pot.order_estimate() > tgt_order - slack assert eoc_rec_grad_x.order_estimate() > tgt_order_grad - grad_slack + # {{{ test toeplitz def _m2l_translate_simple(tgt_expansion, src_expansion, src_coeff_exprs, src_rscale, @@ -412,7 +413,8 @@ def test_m2l_toeplitz(ctx_getter): for sym_a, sym_b in zip(expected_output, actual_output): num_a = sym_a.xreplace(replace_dict) num_b = sym_b.xreplace(replace_dict) - assert abs(num_a - num_b)/abs(num_a) < 1e-13 + assert abs(num_a - num_b)/abs(num_a) < 1e-10 + # }}} -- GitLab From beec30c4212eac4812b2f99d4db2283ce2f0f98a Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Tue, 24 Mar 2020 23:45:18 -0500 Subject: [PATCH 13/17] Use _fft_uneval_expr --- sumpy/expansion/local.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index 025ce5fe..5aa98c92 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -170,7 +170,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): taker = src_expansion.get_kernel_derivative_taker(dvec) - from sumpy.tools import add_mi + from sumpy.tools import add_mi, _fft_uneval_expr from pytools import generate_nonnegative_integer_tuples_below as gnitb max_mi = [0]*self.dim @@ -243,7 +243,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): # Filter out the dummy rows and scale them for target result = [] - rscale_ratio = sym.UnevaluatedExpr(tgt_rscale/src_rscale) + rscale_ratio = _fft_uneval_expr(tgt_rscale/src_rscale) for term in self.get_coefficient_identifiers(): index = toeplitz_matrix_ident_to_index[term] result.append(output[index]*rscale_ratio**sum(term)) -- GitLab From 6fc7d05ac52cd3643e41b305166aaef8c1ed5d5f Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Tue, 5 May 2020 23:33:00 -0500 Subject: [PATCH 14/17] Add _use_fft parameter --- sumpy/expansion/__init__.py | 13 +++++++++++-- sumpy/expansion/local.py | 24 ++++++++++++++---------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/sumpy/expansion/__init__.py b/sumpy/expansion/__init__.py index 9d3a917a..8c931a68 100644 --- a/sumpy/expansion/__init__.py +++ b/sumpy/expansion/__init__.py @@ -622,7 +622,7 @@ class VolumeTaylorExpansion(VolumeTaylorExpansionBase): expansion_terms_wrangler_cache = {} # not user-facing, be strict about having to pass use_rscale - def __init__(self, kernel, order, use_rscale): + def __init__(self, kernel, order, use_rscale, _use_fft): self.expansion_terms_wrangler_key = (order, kernel.dim) @@ -632,7 +632,10 @@ class LaplaceConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): expansion_terms_wrangler_cache = {} # not user-facing, be strict about having to pass use_rscale - def __init__(self, kernel, order, use_rscale): + def __init__(self, kernel, order, use_rscale, _use_fft): + super(LaplaceConformingVolumeTaylorExpansion, self).__init__( + kernel, order, use_rscale, _use_fft, + ) self.expansion_terms_wrangler_key = (order, kernel.dim) @@ -643,6 +646,9 @@ class HelmholtzConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): # not user-facing, be strict about having to pass use_rscale def __init__(self, kernel, order, use_rscale): + super(HelmholtzConformingVolumeTaylorExpansion, self).__init__( + kernel, order, use_rscale, _use_fft, + ) helmholtz_k_name = kernel.get_base_kernel().helmholtz_k_name self.expansion_terms_wrangler_key = (order, kernel.dim, helmholtz_k_name) @@ -654,6 +660,9 @@ class BiharmonicConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): # not user-facing, be strict about having to pass use_rscale def __init__(self, kernel, order, use_rscale): + super(BiharmonicConformingVolumeTaylorExpansion, self).__init__( + kernel, order, use_rscale, _use_fft, + ) self.expansion_terms_wrangler_key = (order, kernel.dim) # }}} diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index 5aa98c92..fe04e700 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -145,7 +145,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): evaluated_coeffs, self.get_full_coefficient_identifiers())) def translate_from(self, src_expansion, src_coeff_exprs, src_rscale, - dvec, tgt_rscale, use_fft=False): + dvec, tgt_rscale): logger.info("building translation operator: %s(%d) -> %s(%d): start" % (type(src_expansion).__name__, src_expansion.order, @@ -236,7 +236,7 @@ class VolumeTaylorLocalExpansionBase(LocalExpansionBase): toeplitz_first_row[toeplitz_matrix_ident_to_index[term]] = coeff # Do the matvec - if use_fft: + if self._use_fft: output = fft_toeplitz_upper_triangular(toeplitz_first_row, vector) else: output = matvec_toeplitz_upper_triangular(toeplitz_first_row, vector) @@ -335,8 +335,9 @@ class VolumeTaylorLocalExpansion( VolumeTaylorExpansion, VolumeTaylorLocalExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft) VolumeTaylorExpansion.__init__(self, kernel, order, use_rscale) @@ -344,8 +345,9 @@ class LaplaceConformingVolumeTaylorLocalExpansion( LaplaceConformingVolumeTaylorExpansion, VolumeTaylorLocalExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft) LaplaceConformingVolumeTaylorExpansion.__init__( self, kernel, order, use_rscale) @@ -354,8 +356,9 @@ class HelmholtzConformingVolumeTaylorLocalExpansion( HelmholtzConformingVolumeTaylorExpansion, VolumeTaylorLocalExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft) HelmholtzConformingVolumeTaylorExpansion.__init__( self, kernel, order, use_rscale) @@ -364,8 +367,9 @@ class BiharmonicConformingVolumeTaylorLocalExpansion( BiharmonicConformingVolumeTaylorExpansion, VolumeTaylorLocalExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft) BiharmonicConformingVolumeTaylorExpansion.__init__( self, kernel, order, use_rscale) -- GitLab From 4c0b5c18482df2839054fb98848e09a462d79a55 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Wed, 6 May 2020 00:07:15 -0500 Subject: [PATCH 15/17] Fix typo --- sumpy/expansion/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sumpy/expansion/__init__.py b/sumpy/expansion/__init__.py index 8c931a68..2525fbfa 100644 --- a/sumpy/expansion/__init__.py +++ b/sumpy/expansion/__init__.py @@ -645,7 +645,7 @@ class HelmholtzConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): expansion_terms_wrangler_cache = {} # not user-facing, be strict about having to pass use_rscale - def __init__(self, kernel, order, use_rscale): + def __init__(self, kernel, order, use_rscale, _use_fft): super(HelmholtzConformingVolumeTaylorExpansion, self).__init__( kernel, order, use_rscale, _use_fft, ) @@ -659,7 +659,7 @@ class BiharmonicConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): expansion_terms_wrangler_cache = {} # not user-facing, be strict about having to pass use_rscale - def __init__(self, kernel, order, use_rscale): + def __init__(self, kernel, order, use_rscale, _use_fft): super(BiharmonicConformingVolumeTaylorExpansion, self).__init__( kernel, order, use_rscale, _use_fft, ) -- GitLab From a9da37d2ce839ca2417abc9abe96050bd15515f0 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Wed, 6 May 2020 01:17:33 -0500 Subject: [PATCH 16/17] Forgot _use_fft in multipole --- sumpy/expansion/multipole.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sumpy/expansion/multipole.py b/sumpy/expansion/multipole.py index b7e2769b..48e0c553 100644 --- a/sumpy/expansion/multipole.py +++ b/sumpy/expansion/multipole.py @@ -301,8 +301,9 @@ class VolumeTaylorMultipoleExpansion( VolumeTaylorExpansion, VolumeTaylorMultipoleExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft=_use_fft) VolumeTaylorExpansion.__init__(self, kernel, order, use_rscale) @@ -310,8 +311,9 @@ class LaplaceConformingVolumeTaylorMultipoleExpansion( LaplaceConformingVolumeTaylorExpansion, VolumeTaylorMultipoleExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft=_use_fft) LaplaceConformingVolumeTaylorExpansion.__init__( self, kernel, order, use_rscale) @@ -320,8 +322,9 @@ class HelmholtzConformingVolumeTaylorMultipoleExpansion( HelmholtzConformingVolumeTaylorExpansion, VolumeTaylorMultipoleExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft=_use_fft) HelmholtzConformingVolumeTaylorExpansion.__init__( self, kernel, order, use_rscale) @@ -330,8 +333,9 @@ class BiharmonicConformingVolumeTaylorMultipoleExpansion( BiharmonicConformingVolumeTaylorExpansion, VolumeTaylorMultipoleExpansionBase): - def __init__(self, kernel, order, use_rscale=None): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) + def __init__(self, kernel, order, use_rscale=None, _use_fft=False): + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, + _use_fft=_use_fft) BiharmonicConformingVolumeTaylorExpansion.__init__( self, kernel, order, use_rscale) -- GitLab From d189ff472848e6fa3ff3a8415572cdd138116c72 Mon Sep 17 00:00:00 2001 From: Isuru Fernando Date: Wed, 6 May 2020 01:31:10 -0500 Subject: [PATCH 17/17] Fix passing _use_fft --- sumpy/expansion/__init__.py | 13 ++++--------- sumpy/expansion/local.py | 20 ++++++++------------ sumpy/expansion/multipole.py | 20 ++++++++------------ 3 files changed, 20 insertions(+), 33 deletions(-) diff --git a/sumpy/expansion/__init__.py b/sumpy/expansion/__init__.py index 2525fbfa..fffb48c8 100644 --- a/sumpy/expansion/__init__.py +++ b/sumpy/expansion/__init__.py @@ -623,6 +623,7 @@ class VolumeTaylorExpansion(VolumeTaylorExpansionBase): # not user-facing, be strict about having to pass use_rscale def __init__(self, kernel, order, use_rscale, _use_fft): + self._use_fft = _use_fft self.expansion_terms_wrangler_key = (order, kernel.dim) @@ -633,9 +634,7 @@ class LaplaceConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): # not user-facing, be strict about having to pass use_rscale def __init__(self, kernel, order, use_rscale, _use_fft): - super(LaplaceConformingVolumeTaylorExpansion, self).__init__( - kernel, order, use_rscale, _use_fft, - ) + self._use_fft = _use_fft self.expansion_terms_wrangler_key = (order, kernel.dim) @@ -646,9 +645,7 @@ class HelmholtzConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): # not user-facing, be strict about having to pass use_rscale def __init__(self, kernel, order, use_rscale, _use_fft): - super(HelmholtzConformingVolumeTaylorExpansion, self).__init__( - kernel, order, use_rscale, _use_fft, - ) + self._use_fft = _use_fft helmholtz_k_name = kernel.get_base_kernel().helmholtz_k_name self.expansion_terms_wrangler_key = (order, kernel.dim, helmholtz_k_name) @@ -660,9 +657,7 @@ class BiharmonicConformingVolumeTaylorExpansion(VolumeTaylorExpansionBase): # not user-facing, be strict about having to pass use_rscale def __init__(self, kernel, order, use_rscale, _use_fft): - super(BiharmonicConformingVolumeTaylorExpansion, self).__init__( - kernel, order, use_rscale, _use_fft, - ) + self._use_fft = _use_fft self.expansion_terms_wrangler_key = (order, kernel.dim) # }}} diff --git a/sumpy/expansion/local.py b/sumpy/expansion/local.py index fe04e700..6edf79d4 100644 --- a/sumpy/expansion/local.py +++ b/sumpy/expansion/local.py @@ -336,9 +336,8 @@ class VolumeTaylorLocalExpansion( VolumeTaylorLocalExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft) - VolumeTaylorExpansion.__init__(self, kernel, order, use_rscale) + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) + VolumeTaylorExpansion.__init__(self, kernel, order, use_rscale, _use_fft) class LaplaceConformingVolumeTaylorLocalExpansion( @@ -346,10 +345,9 @@ class LaplaceConformingVolumeTaylorLocalExpansion( VolumeTaylorLocalExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft) + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) LaplaceConformingVolumeTaylorExpansion.__init__( - self, kernel, order, use_rscale) + self, kernel, order, use_rscale, _use_fft) class HelmholtzConformingVolumeTaylorLocalExpansion( @@ -357,10 +355,9 @@ class HelmholtzConformingVolumeTaylorLocalExpansion( VolumeTaylorLocalExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft) + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) HelmholtzConformingVolumeTaylorExpansion.__init__( - self, kernel, order, use_rscale) + self, kernel, order, use_rscale, _use_fft) class BiharmonicConformingVolumeTaylorLocalExpansion( @@ -368,10 +365,9 @@ class BiharmonicConformingVolumeTaylorLocalExpansion( VolumeTaylorLocalExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft) + VolumeTaylorLocalExpansionBase.__init__(self, kernel, order, use_rscale) BiharmonicConformingVolumeTaylorExpansion.__init__( - self, kernel, order, use_rscale) + self, kernel, order, use_rscale, _use_fft) # }}} diff --git a/sumpy/expansion/multipole.py b/sumpy/expansion/multipole.py index 48e0c553..8e217109 100644 --- a/sumpy/expansion/multipole.py +++ b/sumpy/expansion/multipole.py @@ -302,9 +302,8 @@ class VolumeTaylorMultipoleExpansion( VolumeTaylorMultipoleExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft=_use_fft) - VolumeTaylorExpansion.__init__(self, kernel, order, use_rscale) + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) + VolumeTaylorExpansion.__init__(self, kernel, order, use_rscale, _use_fft) class LaplaceConformingVolumeTaylorMultipoleExpansion( @@ -312,10 +311,9 @@ class LaplaceConformingVolumeTaylorMultipoleExpansion( VolumeTaylorMultipoleExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft=_use_fft) + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) LaplaceConformingVolumeTaylorExpansion.__init__( - self, kernel, order, use_rscale) + self, kernel, order, use_rscale, _use_fft) class HelmholtzConformingVolumeTaylorMultipoleExpansion( @@ -323,10 +321,9 @@ class HelmholtzConformingVolumeTaylorMultipoleExpansion( VolumeTaylorMultipoleExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft=_use_fft) + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) HelmholtzConformingVolumeTaylorExpansion.__init__( - self, kernel, order, use_rscale) + self, kernel, order, use_rscale, _use_fft) class BiharmonicConformingVolumeTaylorMultipoleExpansion( @@ -334,10 +331,9 @@ class BiharmonicConformingVolumeTaylorMultipoleExpansion( VolumeTaylorMultipoleExpansionBase): def __init__(self, kernel, order, use_rscale=None, _use_fft=False): - VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale, - _use_fft=_use_fft) + VolumeTaylorMultipoleExpansionBase.__init__(self, kernel, order, use_rscale) BiharmonicConformingVolumeTaylorExpansion.__init__( - self, kernel, order, use_rscale) + self, kernel, order, use_rscale, _use_fft) # }}} -- GitLab