Skip to content

Commit ee27a70

Browse files
committed
Remove intermediate tools.jacobi interface
1 parent 65de52a commit ee27a70

File tree

7 files changed

+77
-298
lines changed

7 files changed

+77
-298
lines changed

dedalus/core/basis.py

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@
1919
from ..tools.cache import CachedAttribute
2020
from ..tools.cache import CachedMethod
2121
from ..tools.cache import CachedClass
22-
from ..tools import jacobi
2322
from ..tools import clenshaw
2423
from ..tools.array import reshape_vector, axindex, axslice, interleave_matrices
2524
from ..tools.dispatch import MultiClass, SkipDispatchException
2625
from ..tools.general import unify, DeferredTuple
2726

28-
from .spaces import ParityInterval, Disk
2927
from .coords import Coordinate, CartesianCoordinates, S2Coordinates, SphericalCoordinates, PolarCoordinates, AzimuthalCoordinate
3028
from .domain import Domain
3129
from .field import Operand, LockedField
@@ -478,23 +476,19 @@ def __init__(self, coord, size, bounds, a, b, a0=None, b0=None, dealias=1, libra
478476
self.b0 = float(b0)
479477
self.library = library
480478
self.grid_params = (coord, bounds, a0, b0)
481-
self.constant_mode_value = 1 / np.sqrt(jacobi.mass(self.a, self.b))
479+
self.constant_mode_value = (1 / np.sqrt(dedalus_sphere.jacobi.mass(self.a, self.b))).astype(np.float64)
482480

483481
def _native_grid(self, scale):
484482
"""Native flat global grid."""
485483
N, = self.grid_shape((scale,))
486-
return jacobi.build_grid(N, a=self.a0, b=self.b0)
484+
grid, weights = dedalus_sphere.jacobi.quadrature(N, self.a0, self.b0)
485+
return grid.astype(np.float64)
487486

488487
@CachedMethod
489488
def transform_plan(self, grid_size):
490489
"""Build transform plan."""
491490
return self.transforms[self.library](grid_size, self.size, self.a, self.b, self.a0, self.b0)
492491

493-
# def weights(self, scales):
494-
# """Gauss-Jacobi weights."""
495-
# N = self.grid_shape(scales)[0]
496-
# return jacobi.build_weights(N, a=self.a, b=self.b)
497-
498492
# def __str__(self):
499493
# space = self.space
500494
# cls = self.__class__
@@ -556,14 +550,30 @@ def Jacobi_matrix(self, size):
556550
size = self.size
557551
return dedalus_sphere.jacobi.operator('Z')(size, self.a, self.b).square
558552

553+
@staticmethod
554+
def conversion_matrix(N, a0, b0, a1, b1):
555+
if not float(a1-a0).is_integer():
556+
raise ValueError("a0 and a1 must be integer-separated")
557+
if not float(b1-b0).is_integer():
558+
raise ValueError("b0 and b1 must be integer-separated")
559+
if a0 > a1:
560+
raise ValueError("a0 must be less than or equal to a1")
561+
if b0 > b1:
562+
raise ValueError("b0 must be less than or equal to b1")
563+
A = dedalus_sphere.jacobi.operator('A')(+1)
564+
B = dedalus_sphere.jacobi.operator('B')(+1)
565+
da, db = int(a1-a0), int(b1-b0)
566+
conv = A**da @ B**db
567+
return conv(N, a0, b0).astype(np.float64)
568+
559569
def ncc_matrix(self, arg_basis, coeffs, cutoff=1e-6):
560570
"""Build NCC matrix via Clenshaw algorithm."""
561571
if arg_basis is None:
562572
return super().ncc_matrix(arg_basis, coeffs)
563573
# Kronecker Clenshaw on argument Jacobi matrix
564574
elif isinstance(arg_basis, Jacobi):
565575
N = self.size
566-
J = jacobi.jacobi_matrix(N, arg_basis.a, arg_basis.b)
576+
J = dedalus_sphere.jacobi.operator('Z')(N, arg_basis.a, arg_basis.b).square.astype(np.float64)
567577
A, B = clenshaw.jacobi_recursion(N, self.a, self.b, J)
568578
f0 = self.const * sparse.identity(N)
569579
total = clenshaw.kronecker_clenshaw(coeffs, A, B, f0, cutoff=cutoff)
@@ -595,7 +605,7 @@ def _last_axis_component_ncc_matrix(cls, subproblem, ncc_basis, arg_basis, out_b
595605
A, B = clenshaw.jacobi_recursion(Nmat, a_ncc, b_ncc, J)
596606
f0 = dedalus_sphere.jacobi.polynomials(1, a_ncc, b_ncc, 1)[0].astype(np.float64) * sparse.identity(Nmat)
597607
matrix = clenshaw.matrix_clenshaw(coeffs.ravel(), A, B, f0, cutoff=cutoff)
598-
convert = jacobi.conversion_matrix(Nmat, arg_basis.a, arg_basis.b, out_basis.a, out_basis.b)
608+
convert = Jacobi.conversion_matrix(Nmat, arg_basis.a, arg_basis.b, out_basis.a, out_basis.b)
599609
matrix = convert @ matrix
600610
return matrix[:N, :N]
601611

@@ -647,7 +657,7 @@ def _full_matrix(input_basis, output_basis):
647657
N = input_basis.size
648658
a0, b0 = input_basis.a, input_basis.b
649659
a1, b1 = output_basis.a, output_basis.b
650-
matrix = jacobi.conversion_matrix(N, a0, b0, a1, b1)
660+
matrix = Jacobi.conversion_matrix(N, a0, b0, a1, b1)
651661
return matrix.tocsr()
652662

653663

@@ -686,8 +696,9 @@ def _output_basis(input_basis):
686696
def _full_matrix(input_basis, output_basis):
687697
N = input_basis.size
688698
a, b = input_basis.a, input_basis.b
689-
matrix = jacobi.differentiation_matrix(N, a, b) / input_basis.COV.stretch
690-
return matrix.tocsr()
699+
native_matrix = dedalus_sphere.jacobi.operator('D')(+1)(N, a, b).square.astype(np.float64)
700+
problem_matrix = native_matrix / input_basis.COV.stretch
701+
return problem_matrix.tocsr()
691702

692703

693704
class InterpolateJacobi(operators.Interpolate, operators.SpectralOperator1D):
@@ -709,9 +720,9 @@ def _full_matrix(input_basis, output_basis, position):
709720
N = input_basis.size
710721
a, b = input_basis.a, input_basis.b
711722
x = input_basis.COV.native_coord(position)
712-
interp_vector = jacobi.build_polynomials(N, a, b, x)
713-
# Return with shape (1, N)
714-
return interp_vector[None, :]
723+
x = np.array([x])
724+
matrix = dedalus_sphere.jacobi.polynomials(N, a, b, x).T
725+
return matrix.astype(np.float64)
715726

716727

717728
class IntegrateJacobi(operators.Integrate, operators.SpectralOperator1D):
@@ -731,7 +742,7 @@ def _full_matrix(input_basis, output_basis):
731742
# Build native integration vector
732743
N = input_basis.size
733744
a, b = input_basis.a, input_basis.b
734-
integ_vector = jacobi.integration_vector(N, a, b)
745+
integ_vector = dedalus_sphere.jacobi.polynomial_integrals(N, a, b).astype(np.float64)
735746
# Rescale and return with shape (1, N)
736747
return integ_vector[None, :] * input_basis.COV.stretch
737748

@@ -753,7 +764,7 @@ def _full_matrix(input_basis, output_basis):
753764
# Build native integration vector
754765
N = input_basis.size
755766
a, b = input_basis.a, input_basis.b
756-
integ_vector = jacobi.integration_vector(N, a, b)
767+
integ_vector = dedalus_sphere.jacobi.polynomial_integrals(N, a, b).astype(np.float64)
757768
ave_vector = integ_vector / 2
758769
# Rescale and return with shape (1, N)
759770
return ave_vector[None, :]

dedalus/core/spaces.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import numpy as np
66

7-
from ..tools import jacobi
87
from ..tools.array import reshape_vector
98
from ..tools.cache import CachedMethod, CachedAttribute
109

dedalus/core/transforms.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
from . import basis
1212
from ..libraries.fftw import fftw_wrappers as fftw
13-
from ..tools import jacobi
1413
from ..tools.array import apply_matrix, apply_dense, axslice, splu_inverse, apply_sparse, prod
1514
from ..tools.cache import CachedAttribute
1615
from ..tools.cache import CachedMethod
@@ -118,10 +117,9 @@ def forward_matrix(self):
118117
a, a0 = self.a, self.a0
119118
b, b0 = self.b, self.b0
120119
# Gauss quadrature with base (a0, b0) polynomials
121-
base_grid = jacobi.build_grid(N, a=a0, b=b0)
122-
base_polynomials = jacobi.build_polynomials(max(M, N), a0, b0, base_grid)
123-
base_weights = jacobi.build_weights(N, a=a0, b=b0)
124-
base_transform = (base_polynomials * base_weights)
120+
base_grid, base_weights = dedalus_sphere.jacobi.quadrature(N, a0, b0)
121+
base_polynomials = dedalus_sphere.jacobi.polynomials(max(M, N), a0, b0, base_grid)
122+
base_transform = (base_polynomials * base_weights).astype(np.float64)
125123
# Zero higher coefficients for transforms with grid_size < coeff_size
126124
base_transform[N:, :] = 0
127125
if DEALIAS_BEFORE_CONVERTING():
@@ -131,7 +129,7 @@ def forward_matrix(self):
131129
if (a == a0) and (b == b0):
132130
forward_matrix = base_transform
133131
else:
134-
conversion = jacobi.conversion_matrix(base_transform.shape[0], a0, b0, a, b)
132+
conversion = basis.Jacobi.conversion_matrix(base_transform.shape[0], a0, b0, a, b)
135133
forward_matrix = conversion @ base_transform
136134
if not DEALIAS_BEFORE_CONVERTING():
137135
# Truncate to specified coeff_size
@@ -146,8 +144,8 @@ def backward_matrix(self):
146144
a, a0 = self.a, self.a0
147145
b, b0 = self.b, self.b0
148146
# Construct polynomials on the base grid
149-
base_grid = jacobi.build_grid(N, a=a0, b=b0)
150-
polynomials = jacobi.build_polynomials(M, a, b, base_grid)
147+
base_grid, base_weights = dedalus_sphere.jacobi.quadrature(N, a0, b0)
148+
polynomials = dedalus_sphere.jacobi.polynomials(M, a, b, base_grid).astype(np.float64)
151149
# Zero higher polynomials for transforms with grid_size < coeff_size
152150
polynomials[N:, :] = 0
153151
# Transpose and ensure C ordering for fast dot products
@@ -817,12 +815,12 @@ def __init__(self, grid_size, coeff_size, a, b, a0, b0):
817815
else:
818816
# Conversion matrices
819817
if DEALIAS_BEFORE_CONVERTING() and (self.M_orig < self.N): # truncate prior to conversion matrix
820-
self.forward_conversion = jacobi.conversion_matrix(self.M_orig, a0, b0, a, b)
818+
self.forward_conversion = basis.Jacobi.conversion_matrix(self.M_orig, a0, b0, a, b)
821819
else: # input to conversion matrix not truncated
822-
self.forward_conversion = jacobi.conversion_matrix(self.N, a0, b0, a, b)
820+
self.forward_conversion = basis.Jacobi.conversion_matrix(self.N, a0, b0, a, b)
823821
self.forward_conversion.resize(self.M_orig, self.N)
824822
self.forward_conversion = self.forward_conversion.tocsr()
825-
self.backward_conversion = jacobi.conversion_matrix(self.M_orig, a0, b0, a, b)
823+
self.backward_conversion = basis.Jacobi.conversion_matrix(self.M_orig, a0, b0, a, b)
826824
self.backward_conversion = splu_inverse(self.backward_conversion)
827825
self.resize_rescale_forward = self._resize_rescale_forward_convert
828826
self.resize_rescale_backward = self._resize_rescale_backward_convert

dedalus/libraries/dedalus_sphere/jacobi.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,42 @@ def polynomials(n, a, b, z, init=None, Newton=False, normalized=True, dtype=None
113113
return P[:n]
114114

115115

116+
def polynomial_integrals(n, a, b, dtype=None, **kw):
117+
"""
118+
Definite integrals of the Jacobi polynomials, evaluated with Gauss-Legendre quadrature.
119+
120+
Parameters
121+
----------
122+
n : int
123+
Number of polynomials to compute (max degree + 1).
124+
a, b : float
125+
Jacobi parameters.
126+
dtype : dtype, optional
127+
Data type. Default: module-level DEFAULT_GRID_DTYPE.
128+
**kw : dict, optional
129+
Other keywords passed to jacobi.polynomials.
130+
131+
Returns
132+
-------
133+
integrals : array
134+
Vector of polynomial integrals.
135+
"""
136+
if dtype is None:
137+
dtype = DEFAULT_GRID_DTYPE
138+
# Build Legendre quadrature
139+
grid, weights = quadrature(n, a=0, b=0, dtype=dtype)
140+
# Evaluate polynomials on Legendre grid
141+
polys = polynomials(n, a, b, grid, dtype=dtype, **kw)
142+
# Compute integrals using Legendre quadrature
143+
integrals = weights @ polys.T
144+
# Eliminate known zeros
145+
if a == b == 0:
146+
integrals[1:] = 0
147+
elif a == b:
148+
integrals[1::2] = 0
149+
return integrals
150+
151+
116152
def quadrature(n, a, b, iterations=3, probability=False, dtype=None):
117153
"""
118154
Gauss-Jacobi quadrature grid z and weights w.

dedalus/tests/test_clenshaw.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
from scipy import sparse
55
from dedalus.core import coords, distributor, basis, field, operators
66
from dedalus.tools.array import apply_matrix
7-
from dedalus.tools import jacobi
87
from dedalus.tools import clenshaw
98
from ..libraries import dedalus_sphere
109

dedalus/tools/clenshaw.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import numpy as np
44
from scipy import sparse
55

6-
from . import jacobi
6+
from ..libraries import dedalus_sphere
77
from .general import DeferredTuple
88

99

@@ -78,7 +78,7 @@ def jacobi_recursion(N, a, b, X):
7878
B[n] = - J[n,n-1]/J[n,n+1]
7979
"""
8080
# Jacobi matrix
81-
J = jacobi.jacobi_matrix(N, a, b)
81+
J = dedalus_sphere.jacobi.operator('Z')(N, a, b).square.astype(np.float64)
8282
JA = J.A
8383
# Identity element
8484
if np.isscalar(X):

0 commit comments

Comments
 (0)