LINE Solver
MATLAB API documentation
Loading...
Searching...
No Matches
gengausslegquadrule.m
1function [ zerosave,w,reccalls ] = gengausslegquadrule( nmax,tol,numpoint,reccalls,maxrec)
2%this function tested to work for N < 300, larger values suffer from
3%underflow issues in the weights and exponential.
4%this function generates a gauss Laguerre quadrature rule for a given value n, it
5%does so by generating via reccursion a table of the Laguerre functions
6% (i.e. a Laguerre polynomial times the root of a weight function) in
7%the positive domain and then looking for zeros via a change of sign and
8%interpolating (quadratically) between the two values (or finding an exact zero)
9%Using more points will give better accuracy, a warning is output if zeros
10%are missed due to lack of points
11%The function will then focus in on the zeros until a tolerance is reached,
12%this tolerance is based on absolute uncertainty in each root
13%note such rules are used to approximate integrals of the form
14% int_{0}^{inf} dx f(x) exp(-x) to sum_{i=1}^N w_i*f(x_i)
15%recalls follows how many times the function has called itself
16%Author David Holdaway: year 2012
17% https://www.mathworks.com/matlabcentral/fileexchange/35886-gauss-laguerre-quadrature
18%% check inputs
19if nargin==1
20 tol(1) = 1.0e-12; %default
21end
22if nargin <4
23 reccalls = 0;
24end
25if nargin <5
26 maxrec = 8; %maximum number of recalls to achieve convergence
27end
28if tol(1) < 5*eps && reccalls ==0
29 warning('this position tolerance is of order eps, function may fail')
30end
31if nargin < 3
32 numpoint = 100*(nmax+5); %usually an adequate amount
33end
34if nmax ==0
35 zerosave=nan; w=nan; return
36end
37if nmax ==1
38 zerosave=0; w=1; return
39end
40if length(numpoint) == 1 %initial course zero findings
41x = linspace(0,2*sqrt(nmax+1),numpoint); %needs lots of points for resolution
42x = x.^2; %want increasing spacing towards inf, reduced towards zero
43else %previous zeros fed back in
44 x = numpoint;
45end
46%tic
47%% generate Laguerre function table
48ltable = zeros(3,length(x)); %need to store three to generate
49ltable(1,:) = exp(-x/2);
50underflowchk = ltable(1,:)==0;
51if sum(underflowchk)~=0
52 warning('some x values cut off due to underflow, may still be fine or may cut off zeros')
53 %this is a problem for large N
54 x = x(ltable(1,:)~=0); %cut x
55 ltable = zeros(3,length(x));
56 ltable(1,:) = exp(-x/2);
57end
58ltable(2,:) = (1-x).*ltable(1,:);
59for k = 2:nmax
60 %L_{n} = (1/n) [ (2n-1 - x) L_{n-1} - (n-1) L_{n-2} ]
61 ltable(3,:) = ((2*k-1 - x).*ltable(2,:) -(k-1).*ltable(1,:))/k;
62 ltable([1,2,3],:) = ltable([2,3,1],:); %permute to use again
63
64
65end
66lfin = ltable(2,:);
67% if reccalls == 0
68% figure
69% plot(sqrt(x),lfin )
70% hold on
71% end
72clear ltable
73%% find zeros only in +ve
74zerosave = zeros(1,nmax);
75zcount = 0; zerosave2 = zerosave;
76rng = 2:length(x);
77for lp = rng
78 if sign(lfin(lp)) == 0 %found "exact" zero!
79 zcount = zcount + 1;
80 zerosave(zcount) = x(lp);
81 zerosave2(zcount) = lp;
82 %skip loop an extra one
83 elseif sign(lfin(lp-1)) == 0
84 %skip this as it will screw up next logic
85 elseif sign(lfin(lp-1)) ~= sign(lfin(lp))
86 %change of sign implies zero
87 zcount = zcount + 1;
88 %linearly interpolate between two x points to approximate zero
89 xpsave = x(lp)-x(lp-1); %spacing
90 root = xpsave*abs(lfin(lp-1))/abs(lfin(lp)-lfin(lp-1));
91 zerosave(zcount) = x(lp-1) + root;
92 zerosave2(zcount) = lp;
93 end
94
95end
96clear hgrad hfin
97if zcount < nmax
98
99 warning('missed zeros, doubling number of points')
100 if reccalls == 0
101 x = linspace(0,nmax^2*20+4*(1+nmax),numpoint*2);
102 x = sqrt(x);
103 [ zerosave,w,reccalls ] = gengausslegquadrule( nmax,tol,x,reccalls,maxrec );
104 return
105 end %call again with double number of points
106 warning('failed: not enough zeros found use more points or nmax too large')
107
108 w=nan; zerosave=zcount ;
109 return %fail
110end
111if zcount > nmax
112 warning('failed to distinguish zeros, tolerance likely set low, removing extra zeros')
113 %zcount
114tmp = diff(sqrt(zerosave)) > 1e-5; %find repeated zeros.. low x has too much resolution for dp
115if sum(tmp) ==nmax;
116
117 zerosave = zerosave(tmp); %remove repeated
118 zerosave2 = zerosave2(tmp); %remove repeated
119else
120 zerosave=zcount; w = nan; return %fail
121
122end
123end
124 xpsave = zerosave2;
125 for k=1:length(zerosave2)
126 xpsave(k) = x(zerosave2(k)) - x(zerosave2(k)-1);
127 end
128 converged = xpsave <= tol;
129 notconv = logical(1-converged);
130 convcond = sum(notconv) ==0;
131 %spacings vary
132clear x %no longer required
133%toc
134%% used to refine results by feeding back zero estimate
135if convcond==false %feed back x to function, create refined x range
136if reccalls < maxrec
137% finex = kron(zerosave,ones(1,9));
138% finex = sort([0,finex + kron(xpsave.*ones(1,length(zerosave)),...
139% [-1,-1/4,-1/16,-1/64,0,1/64,1/16,1/4,1])]);
140%
141% finex = finex( diff(finex)>eps); %if these points are not distinct, remove them
142
143 tmp1 = kron(zerosave(notconv),ones(1,9)) + ...
144 kron(xpsave(notconv).*ones(1,sum(notconv)),...
145 [-1,-1/4,-1/16,-1/32,0,1/32,1/16,1/4,1]);
146 tmp2 = kron(zerosave(converged),ones(1,3)) + ...
147 kron(xpsave(converged).*ones(1,sum(converged)),...
148 [-1,0,1]); %converged so don't both refining much
149 finex = sort([0,tmp1,tmp2]);
150 clear tmp1 tmp2
151 reccalls = reccalls+1;
152 [ zerosave,w,reccalls ] = gengausslegquadrule( nmax,tol,finex,reccalls,maxrec );
153 return
154else
155 warning('failed to converge to desired tolerence, after max reccursions')
156 bestachieved1 = max(xpsave)
157end
158end
159%% find weights if zeros to tolerance
160% find weights, regenerate legtable using zero positions only and no
161% exp(-x/2) factor
162%w_i = x_i/(n+1)^2(L_{n+1}(x_i))^2
163ltable = zeros(nmax+2,length(zerosave));
164ltable(1,:) = ones(size(zerosave));
165ltable(2,:) = (1-zerosave).*ltable(1,:);
166for k = 2:nmax+1 %up to n+1th, note again indexes start from zero
167 %L_{n} = (1/n) [ (2n-1 - x) L_{n-1} - (n-1) L_{n-2} ]
168 ltable(k+1,:) = ((2*k-1 - zerosave).*ltable(k,:) -(k-1).*ltable(k-1,:))/k;
169
170end
171w = zerosave;
172for k = 1:length(zerosave)
173 w(k) = zerosave(k)./ltable(nmax+2,k).^2;
174
175end
176w = w/(nmax+1)^2;
177% format longe
178% for k =1:20
179% diffsave(k)=(sum(x.^k.*w)-factorial(k))/factorial(k);
180% end
181end