-
Notifications
You must be signed in to change notification settings - Fork 0
/
spquad.m
122 lines (120 loc) · 3.68 KB
/
spquad.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
function [x,w]=spquad(dim,ord,bpt)
%SPQUAD
% Computes the sparse grid quadrature abscissae and weights
% on an orthotope/hyperrectangle using the Clenshaw-Curtis rule.
%
% [X,W]=SPQUAD(DIM,ORD,AB)
%
% Input Parameters:
% DIM - number of dimensions
% ORD - order of the integration rule
% BPT - boundary points (Optional. Defaults to [-1,1]^dim)
%
% If used, BPT should be a 2 by DIM matrix containing the
% endpoints of the hyperrectangle in each column.
%
% Example usage:
%
% f=@(x) (1+x(:,1)).*exp(x(:,2).*x(:,3))+(1+x(:,2)).*exp(x(:,3).*x(:,1))
% [x,w]=spquad(3,4,[-1 0 2; 1 1 3]);
% Q=w'*f(x);
%
% written by Greg von Winckel - March 3, 2008
% Contact: gregory(dot)von-winckel(at)uni-graz(dot)at
% Check that the number dimensions agree
if nargin>2
if size(bpt,2)~=dim
error('dimension mismatch');
end
else
bpt=repmat([-1,1]',1,dim);
end
% Length and midpoint in each dimesion
len=diff(bpt); mpt=mean(bpt);
if ord==0 % zeroth order case is just the midpoint rule
x=mpt; w=prod(len);
elseif ord~=0 && dim==1 % Special 1D case
x=mpt+len*cos(pi*2^(-ord)*(0:(2^ord))')/2;
w=clencurt(2^(ord)+1)*len/2;
else
% node and weight for single point grid
x0=mpt; w0=prod(len);
% Construct higher order grid hierarchically
for j=1:ord
[x,w]=sparsegridnd(dim,j,mpt,len);
[C,I]=intersect(x,x0,'rows');
w(I)=w(I)+w0; x0=x; w0=w;
end
end
%% Multidimensional nodes and difference weights
function [x,w]=sparsegridnd(n,ord,mpt,len)
% Generates the n-dimensional sparse grid of order ord on the
% hyperrectangle with centroid mpt and side lengths len, based
% on Chebyshev-Gauss-Lobatto points.
% Define 1D grid points
p=@(i) unique((i~=0)*cos(pi*2^(-i)*(0:(2^i)))');
% Get configurations of all possible subgrids
v=genindex(n,ord); vmax=1+v(1,n);
% Compute all orders of one-dimensional quadrature rules
P=uaf(@(j) p(j), (0:vmax-1));
Q=uaf(@(j) diffweight(j), (0:vmax));
% Take the union of all possible subgrids
m=size(v,1);
xw=uaf(@(k) getpts(P,Q,v(k,:),mpt,len), (1:m)',1);
x=xw(:,1:n); w=xw(:,n+1);
% Kludge to deal with small errors introduced by ndgrid
% need a better way to do this
roundn=@(a,n) round(a*10^n)/10^n;
x=roundn(x,15);
% Get unique points and weights
[x,ii,jj]=unique(x,'rows'); rows=length(ii); cols=length(jj);
% Do node condesation for combining weights
w=sparse(jj,(1:cols)',ones(cols,1),rows,cols)*w;
%% One dimensional difference weights
function dw=diffweight(ii)
if ii==0
dw=2;
elseif ii==1
dw=[1;-2;1]/3;
else
q=@(i) clencurt(2^(i)+1);
dw=q(ii); dw(1:2:end)=dw(1:2:end)-q(ii-1);
end
%% Compute the subset grid points and difference weights
function [XW]=getpts(P,Q,v,mpt,len)
n=size(v,2);
[x{1:n}]=ndgrid(P{1+v}); [w{1:n}]=ndgrid(Q{1+v});
d=size(v,2);
X=uaf(@(k) mpt(k)+x{k}(:)*len(k)/2, (1:d),1);
W=prod(uaf(@(k) w{k}(:), (1:d),1),2);
XW=[X,W];
%% Find all possible combinations of bases
function v=genindex(n, L1, head)
if n==1
v = L1;
else
v = uaf(@(j) genindex(n-1, L1-j, j),(0:L1)',1);
end
if nargin>=3
v = [head+zeros(size(v,1),1) v];
end
%% Compute 1D Clenshaw-Curtis weights
% Reference: Jörg Waldvogel, "Fast construction of the
% Fejér and Clenshaw-Curtis quadrature rules," BIT Numerical
% Mathematics 43 (1), p. 001-018 (2004).
function w=clencurt(N1)
if N1==1
w=2;
else
N=N1-1; c=zeros(N1,1);
c(1:2:N1,1)=(2./[1 1-(2:2:N).^2 ])';
f=real(ifft([c(1:N1,:);c(N:-1:2,:)]));
w=2*([f(1,1); 2*f(2:N,1); f(N1,1)])/2;
end
%% Shorthand array function with uniform output
% Optional third argument converts output to matrix
function result=uaf(arg,dex,varargin)
result=arrayfun(arg,dex,'UniformOutPut',false);
if nargin>2
result=cell2mat(result);
end