|
| 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 |
0 commit comments