Skip to content

Commit 230671a

Browse files
committed
Adds a Padua Transform
1 parent eb9f161 commit 230671a

File tree

2 files changed

+169
-0
lines changed

2 files changed

+169
-0
lines changed

src/PadTransform.jl

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
2+
# Creates (n+2)x(n+1) Chebyshev coefficient matrix from triangle coefficients.
3+
function trianglecfs(cfs::AbstractVector)
4+
N=length(cfs)
5+
n=ceil(Int,(-3+sqrt(1+8N))/2)
6+
@assert N==div((n+1)*(n+2),2)
7+
cfsmat=zeros(Float64,n+2,n+1)
8+
9+
m=1
10+
for d=1:n+1, k=1:d
11+
j=d-k+1
12+
13+
cfsmat[k,j]=cfs[m]
14+
15+
if m==N
16+
return cfsmat
17+
else
18+
m+=1
19+
end
20+
21+
end
22+
return cfsmat
23+
end
24+
25+
function paduavec(padmat::Matrix)
26+
n=size(padmat,2)-1
27+
N=div((n+1)*(n+2),2)
28+
padvals=zeros(N)
29+
if iseven(n)>0
30+
padmat=[padmat; zeros(1,n+1)]
31+
indices=zeros(div(n,2))
32+
indices=(n+3)*collect(1:div(n,2))
33+
padvals=padmat[2:2:end]
34+
padvals=deleteat!(padvals,indices)
35+
else
36+
padvals=padmat[1:2:end-1]
37+
end
38+
return padvals
39+
end
40+
41+
# Inverse Padua Transform maps the 2D Chebyshev coefficients to the values of the interpolation polynomial at the Padua points.
42+
function ipadtransform(cfs::AbstractVector)
43+
44+
cfsmat=trianglecfs(cfs)
45+
n=size(cfsmat,2)-1
46+
tensorvals=zeros(Float64,n+2,n+1)
47+
48+
cfsmat[:,2:end-1]=cfsmat[:,2:end-1]/2
49+
cfsmat[2:end-1,:]=cfsmat[2:end-1,:]/2
50+
tensorvals=FFTW.r2r(cfsmat,FFTW.REDFT00)
51+
paduavals=paduavec(tensorvals)
52+
53+
return paduavals
54+
end
55+
56+
# Creates (n+2)x(n+1) matrix of interpolant values on the tensor grid at the (n+1)*(n+2)/2 Padua points.
57+
function padvalsmat(v::AbstractVector)
58+
N=length(v)
59+
n=ceil(Int,(-3+sqrt(1+8N))/2)
60+
@assert N==div((n+1)*(n+2),2)
61+
vals=zeros(Float64,n+2,n+1)
62+
63+
if iseven(n)>0
64+
vals[2:2:end]=v
65+
vals=[vals; zeros(1,n+1)]
66+
indices=zeros(n)
67+
indices=sort([(n+3)*collect(1:2:n+1); (n+4)+(n+3)*collect(0:2:n-1)])
68+
vals=reshape(deleteat!(vec(vals),indices),n+2,n+1)
69+
else
70+
vals[1:2:end]=v
71+
end
72+
return vals
73+
end
74+
75+
# Creates length (n+1)*(n+2)/2 vector from matrix of triangle Chebyshev coefficients.
76+
function cfsvec(cfs::Matrix)
77+
n,m=size(cfs)
78+
ret=Array(Float64,sum(1:m))
79+
n=1
80+
for d=1:m,k=1:d
81+
j=d-k+1
82+
ret[n]=cfs[k,j]
83+
n+=1
84+
end
85+
return ret
86+
end
87+
88+
# Padua Transform maps from interpolant values at the Padua points to the 2D Chebyshev coefficients.
89+
function padtransform(v::AbstractVector)
90+
91+
N=length(v)
92+
n=ceil(Int,(-3+sqrt(1+8N))/2)
93+
vals=padvalsmat(v)
94+
tensorcfs=zeros(Float64,n+2,n+1)
95+
96+
tensorcfs=FFTW.r2r(vals,FFTW.REDFT00)
97+
tensorcfs=tensorcfs*2/(n*(n+1))
98+
tensorcfs[1,:]=tensorcfs[1,:]/2
99+
tensorcfs[:,1]=tensorcfs[:,1]/2
100+
tensorcfs[end,:]=tensorcfs[end,:]/2
101+
tensorcfs[:,end]=tensorcfs[:,end]/2
102+
cfs=cfsvec(tensorcfs)
103+
104+
return cfs
105+
end
106+
107+
# Returns coordinates of the (n+1)*(n+2)/2 Padua points
108+
function padpoints(m::Integer)
109+
M=div((m+1)*(m+2),2)
110+
θ=linspace(0.,pi,m+2)
111+
ϕ=linspace(0.,pi,m+1)
112+
pts=zeros(M,2)
113+
X=zeros(Float64,m+2,m+1)
114+
Y=zeros(Float64,m+2,m+1)
115+
X=[cos(ϕ) for θ in θ, ϕ in ϕ]
116+
Y=[cos(θ) for θ in θ, ϕ in ϕ]
117+
if iseven(m)>0
118+
X=[X; zeros(1,m+1)]
119+
Y=[Y; zeros(1,m+1)]
120+
indices=zeros(div(m,2))
121+
indices=(m+3)*collect(1:div(m,2))
122+
pts[:,1]=deleteat!(X[2:2:end],indices)
123+
pts[:,2]=deleteat!(Y[2:2:end],indices)
124+
else
125+
pts[:,1]=X[1:2:end-1]
126+
pts[:,2]=Y[1:2:end-1]
127+
end
128+
return pts
129+
end
130+
131+
# Interpolates a 2d function at a given point using 2d Chebyshev series
132+
function padeval(f::Function,x::Float64,y::Float64,m::Integer)
133+
134+
p=padpoints(m)
135+
pvals=zeros(div((m+1)*(m+2),2))
136+
pvals=map(f,p[:,1],p[:,2])
137+
coeffs=padtransform(pvals)
138+
cfs_mat=trianglecfs(coeffs)
139+
cfs_mat=cfs_mat[1:end-1,:]
140+
f_x=sum([cfs_mat[k,j]*cos((j-1)*acos(x))*cos((k-1)*acos(y)) for k=1:size(cfs_mat,1), j=1:size(cfs_mat,2)])
141+
142+
return f_x
143+
end

test/PadTransformTests.jl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
include("PadTransform.jl")
2+
using Base.Test
3+
4+
println("Testing Pad Transforms and their inverse function property")
5+
n=100
6+
N=div((n+1)*(n+2),2)
7+
v=rand(N) # Length of v is the no. of Padua points
8+
@test norm(padtransform(ipadtransform(v))-v)< 100eps()
9+
@test norm(ipadtransform(padtransform(v))-v)< 100eps()
10+
@test_approx_eq padtransform(ipadtransform(v)) v
11+
@test_approx_eq ipadtransform(padtransform(v)) v
12+
13+
println("Testing runtimes for Pad Transforms")
14+
@time padtransform(v)
15+
@time ipadtransform(v)
16+
17+
println("Accuracy of 2d function interpolation at a point")
18+
f = (x,y) -> x^2*y+x^3
19+
g = (x,y) ->cos(exp(2*x+y))*sin(y)
20+
x=0.1;y=0.2
21+
m=20
22+
l=80
23+
f_x=padeval(f,x,y,m)
24+
g_x=padeval(g,x,y,l)
25+
@test_approx_eq f(x,y) f_x
26+
@test_approx_eq g(x,y) g_x

0 commit comments

Comments
 (0)