@@ -43,25 +43,84 @@ getindex(A::DiskTrav, k::Int) = A[findblockindex(axes(A,1), k)]
43
43
44
44
ClassicalOrthogonalPolynomials. checkpoints (d:: UnitDisk{T} ) where T = [SVector {2,T} (0.1 ,0.2 ), SVector {2,T} (0.2 ,0.3 )]
45
45
46
+ """
47
+ ZernikeWeight(a, b)
48
+
49
+ is a quasi-vector representing `r^(2a) * (1-r^2)^b`
50
+ """
51
+ struct ZernikeWeight{T} <: Weight{T}
52
+ a:: T
53
+ b:: T
54
+ end
55
+
56
+ """
57
+ ZernikeWeight(b)
46
58
47
- struct Zernike{T} <: BivariateOrthogonalPolynomial{T} end
59
+ is a quasi-vector representing `(1-r^2)^b`
60
+ """
61
+
62
+ ZernikeWeight (b) = ZernikeWeight (zero (b), b)
63
+
64
+ axes (:: ZernikeWeight{T} ) where T = (Inclusion (UnitDisk {T} ()),)
65
+
66
+ == (w:: ZernikeWeight , v:: ZernikeWeight ) = w. a == v. a && w. b == v. b
67
+
68
+ function getindex (w:: ZernikeWeight , xy:: StaticVector{2} )
69
+ r = norm (xy)
70
+ r^ (2 w. a) * (1 - r^ 2 )^ w. b
71
+ end
48
72
73
+
74
+ """
75
+ Zernike(a, b)
76
+
77
+ is a quasi-matrix orthogonal `r^(2a) * (1-r^2)^b`
78
+ """
79
+ struct Zernike{T} <: BivariateOrthogonalPolynomial{T}
80
+ a:: T
81
+ b:: T
82
+ Zernike {T} (a:: T , b:: T ) where T = new {T} (a, b)
83
+ end
84
+ Zernike {T} (a, b) where T = Zernike {T} (convert (T,a), convert (T,b))
85
+ Zernike (a:: T , b:: V ) where {T,V} = Zernike {float(promote_type(T,V))} (a, b)
86
+ Zernike {T} (b) where T = Zernike {T} (zero (b), b)
87
+ Zernike {T} () where T = Zernike {T} (zero (T))
88
+
89
+ """
90
+ Zernike(b)
91
+
92
+ is a quasi-matrix orthogonal `(1-r^2)^b`
93
+ """
94
+ Zernike (b) = Zernike (zero (b), b)
49
95
Zernike () = Zernike {Float64} ()
50
96
51
97
axes (P:: Zernike{T} ) where T = (Inclusion (UnitDisk {T} ()),blockedrange (oneto (∞)))
52
98
99
+ == (w:: Zernike , v:: Zernike ) = w. a == v. a && w. b == v. b
100
+
53
101
copy (A:: Zernike ) = A
54
102
103
+ orthogonalityweight (Z:: Zernike ) = ZernikeWeight (Z. a, Z. b)
104
+
105
+ zerniker (ℓ, m, a, b, r:: T ) where T = sqrt (convert (T,2 )^ (m+ a+ b+ 2 - iszero (m))/ π) * r^ m * normalizedjacobip ((ℓ- m) ÷ 2 , b, m+ a, 2 r^ 2 - 1 )
106
+ zerniker (ℓ, m, b, r) = zerniker (ℓ, m, zero (b), b, r)
107
+ zerniker (ℓ, m, r) = zerniker (ℓ, m, zero (r), r)
108
+
109
+ function zernikez (ℓ, ms, a, b, rθ:: RadialCoordinate{T} ) where T
110
+ r,θ = rθ. r,rθ. θ
111
+ m = abs (ms)
112
+ zerniker (ℓ, m, a, b, r) * (signbit (ms) ? sin (m* θ) : cos (m* θ))
113
+ end
114
+
115
+ zernikez (ℓ, ms, a, b, xy:: StaticVector{2} ) = zernikez (ℓ, ms, a, b, RadialCoordinate (xy))
116
+ zernikez (ℓ, ms, b, xy:: StaticVector{2} ) = zernikez (ℓ, ms, zero (b), b, xy)
117
+ zernikez (ℓ, ms, xy:: StaticVector{2,T} ) where T = zernikez (ℓ, ms, zero (T), xy)
118
+
55
119
function getindex (Z:: Zernike{T} , rθ:: RadialCoordinate , B:: BlockIndex{1} ) where T
56
- r,θ = rθ. r, rθ. θ
57
120
ℓ = Int (block (B))- 1
58
121
k = blockindex (B)
59
122
m = iseven (ℓ) ? k- isodd (k) : k- iseven (k)
60
- if iszero (m)
61
- sqrt (convert (T,2 )/ π) * Normalized (Legendre {T} ())[2 r^ 2 - 1 , ℓ ÷ 2 + 1 ]
62
- else
63
- sqrt (convert (T,2 )^ (m+ 2 )/ π) * r^ m * Normalized (Jacobi {T} (0 , m))[2 r^ 2 - 1 ,(ℓ- m) ÷ 2 + 1 ] * (isodd (k+ ℓ) ? cos (m* θ) : sin (m* θ))
64
- end
123
+ zernikez (ℓ, (isodd (k+ ℓ) ? 1 : - 1 ) * m, Z. a, Z. b, rθ)
65
124
end
66
125
67
126
@@ -70,6 +129,8 @@ getindex(Z::Zernike, xy::StaticVector{2}, B::Block{1}) = [Z[xy, B[j]] for j=1:In
70
129
getindex (Z:: Zernike , xy:: StaticVector{2} , JR:: BlockOneTo ) = mortar ([Z[xy,Block (J)] for J = 1 : Int (JR[end ])])
71
130
72
131
132
+
133
+
73
134
# ##
74
135
# Transforms
75
136
# ##
@@ -93,10 +154,82 @@ struct ZernikeTransform{T} <: Plan{T}
93
154
analysis:: FastTransforms.FTPlan{T,2,FastTransforms.DISKANALYSIS}
94
155
end
95
156
96
- function ZernikeTransform {T} (N:: Int ) where T<: Real
157
+ function ZernikeTransform {T} (N:: Int , a :: Number , b :: Number ) where T<: Real
97
158
Ñ = N ÷ 2 + 1
98
- ZernikeTransform {T} (N, plan_disk2cxf (T, Ñ, 0 , 0 ), plan_disk_analysis (T, Ñ, 4 Ñ- 3 ))
159
+ ZernikeTransform {T} (N, plan_disk2cxf (T, Ñ, a, b ), plan_disk_analysis (T, Ñ, 4 Ñ- 3 ))
99
160
end
100
161
* (P:: ZernikeTransform{T} , f:: Matrix{T} ) where T = DiskTrav (P. disk2cxf \ (P. analysis * f))[Block .(1 : P. N)]
101
162
102
- factorize (S:: FiniteZernike{T} ) where T = TransformFactorization (grid (S), ZernikeTransform {T} (blocksize (S,2 )))
163
+ factorize (S:: FiniteZernike{T} ) where T = TransformFactorization (grid (S), ZernikeTransform {T} (blocksize (S,2 ), parent (S). a, parent (S). b))
164
+
165
+ # gives the entries for the Laplacian times (1-r^2) * Zernike(1)
166
+ struct WeightedZernikeLaplacianDiag{T} <: AbstractBlockVector{T} end
167
+
168
+ axes (:: WeightedZernikeLaplacianDiag ) = (blockedrange (oneto (∞)),)
169
+
170
+ function Base. view (W:: WeightedZernikeLaplacianDiag{T} , K:: Block{1} ) where T
171
+ K̃ = Int (K)
172
+ d = K̃÷ 2 + 1
173
+ if isodd (K̃)
174
+ v = (d: K̃) .* (d: (- 1 ): 1 )
175
+ convert (AbstractVector{T}, - 4 * interlace (v, v[2 : end ]))
176
+ else
177
+ v = (d: K̃) .* (d- 1 : (- 1 ): 1 )
178
+ convert (AbstractVector{T}, - 4 * interlace (v, v))
179
+ end
180
+ end
181
+
182
+ getindex (W:: WeightedZernikeLaplacianDiag , k:: Integer ) = W[findblockindex (axes (W,1 ),k)]
183
+
184
+ @simplify function * (Δ:: Laplacian , WZ:: Weighted{<:Any,<:Zernike} )
185
+ @assert WZ. P. a == 0 && WZ. P. b == 1
186
+ WZ. P * Diagonal (WeightedZernikeLaplacianDiag {eltype(eltype(WZ))} ())
187
+ end
188
+
189
+ struct ZernikeConversion{T} <: AbstractBandedBlockBandedMatrix{T} end
190
+
191
+ axes (Z:: ZernikeConversion ) = (blockedrange (oneto (∞)), blockedrange (oneto (∞)))
192
+
193
+ blockbandwidths (:: ZernikeConversion ) = (0 ,2 )
194
+ subblockbandwidths (:: ZernikeConversion ) = (0 ,0 )
195
+
196
+
197
+ function Base. view (W:: ZernikeConversion{T} , KJ:: Block{2} ) where T
198
+ K,J = KJ. n
199
+ dat = Matrix {T} (undef,1 ,J)
200
+ if J == K
201
+ if isodd (K)
202
+ R0 = Normalized (Jacobi (1 ,0 )) \ Normalized (Jacobi (0 ,0 ))
203
+ dat[1 ,1 ] = R0[K÷ 2 + 1 ,K÷ 2 + 1 ]
204
+ end
205
+ for m in range (2 - iseven (K); step= 2 , length= J÷ 2 )
206
+ Rm = Normalized (Jacobi (1 ,m)) \ Normalized (Jacobi (0 ,m))
207
+ j = K÷ 2 - m÷ 2 + isodd (K)
208
+ dat[1 ,m] = dat[1 ,m+ 1 ] = Rm[j,j]
209
+ end
210
+ elseif J == K + 2
211
+ if isodd (K)
212
+ R0 = Normalized (Jacobi (1 ,0 )) \ Normalized (Jacobi (0 ,0 ))
213
+ j = K÷ 2 + 1
214
+ dat[1 ,1 ] = R0[j,j+ 1 ]
215
+ end
216
+ for m in range (2 - iseven (K); step= 2 , length= K÷ 2 )
217
+ Rm = Normalized (Jacobi (1 ,m)) \ Normalized (Jacobi (0 ,m))
218
+ j = K÷ 2 - m÷ 2 + isodd (K)
219
+ dat[1 ,m] = dat[1 ,m+ 1 ] = Rm[j,j+ 1 ]
220
+ end
221
+ else
222
+ fill! (dat, zero (T))
223
+ end
224
+ dat ./= sqrt (2 one (T))
225
+ _BandedMatrix (dat, K, 0 , 0 )
226
+ end
227
+
228
+ getindex (R:: ZernikeConversion , k:: Integer , j:: Integer ) = R[findblockindex .(axes (R),(k,j))... ]
229
+
230
+ function \ (A:: Zernike{T} , B:: Zernike{V} ) where {T,V}
231
+ A. a == B. a && A. b == B. b && return Eye {promote_type(T,V)} (∞)
232
+ @assert A. a == 0 && A. b == 1
233
+ @assert B. a == 0 && B. b == 0
234
+ ZernikeConversion {promote_type(T,V)} ()
235
+ end
0 commit comments