|
1 | | -function mat = pquadwts(r,d,n,d2,ct,bw,j,... |
2 | | - rt,dt,nt,d2t,kern,opdims,t,w,opts,intp_ab,intp) |
3 | | -%CHNK.INTERPQUADWTS product integration for interaction of kernel on chunk |
| 1 | +function [varargout] = pquadwts(r,d,n,d2,wts,j,... |
| 2 | + rt,t,w,opts,intp_ab,intp,types) |
| 3 | +%CHNK.pquadwts product integration for interaction of kernel on chunk |
4 | 4 | % at targets |
5 | 5 | % |
6 | 6 | % WARNING: this routine is not designed to be user-callable and assumes |
7 | 7 | % a lot of precomputed values as input |
8 | 8 | % |
9 | | -% Syntax: mat = interpquadwts(r,d,d2,h,ct,bw,j, ... |
10 | | -% rt,dt,d2t,kern,opdims,t,w,opts) |
| 9 | +% Syntax: [varargout] = pquadwts(r,d,n,d2,wts,j,... |
| 10 | +% rt,t,w,opts,intp_ab,intp,types) |
11 | 11 | % |
12 | 12 | % Input: |
13 | 13 | % r - chnkr nodes |
14 | 14 | % d - chnkr derivatives at nodes |
15 | 15 | % n - chnkr normals at nodes |
16 | 16 | % d2 - chnkr 2nd derivatives at nodes |
17 | | -% ct - Legendre nodes at order of chunker |
18 | | -% bw - barycentric interpolation weights for Legendre nodes at order of |
19 | | -% chunker |
| 17 | +% wts - chnkr integration weights for smooth functions |
20 | 18 | % j - chunk of interest |
21 | | -% rt,dt,nt,d2t - position, derivative, normal,second derivative of select |
22 | | -% target points. if any are not used by kernel (or not well |
23 | | -% defined, e.g. when not on curve), a dummy array |
24 | | -% of the appropriate size should be supplied |
25 | | -% kern - kernel function of form kern(srcinfo,targinfo) |
26 | | -% opdims - dimensions of kernel |
27 | | -% t - (Legendre) integration nodes for adaptive integration |
28 | | -% w - integration nodes for adaptive integrator (t and w not necessarily |
29 | | -% same order as chunker order) |
| 19 | +% rt - position of target points. if any are not used by kernel |
| 20 | +% (or not well defined, e.g. when not on curve), a |
| 21 | +% dummy array of the appropriate size should be supplied |
| 22 | +% t - (Legendre) integration nodes |
| 23 | +% w - (Legendre) integration weights |
| 24 | +% opts - opts.side |
| 25 | +% intp_ab - panel endpoints interpolation matrix |
| 26 | +% types - specified singularity types |
| 27 | +% [0 0 0 0] - smooth quadr |
| 28 | +% [1 0 0 0] - log singularity |
| 29 | +% [0 0 -1 0] - cauchy singularity |
| 30 | +% each [a, b, c, d] |
| 31 | +% corresponds to (log(z-w))^a (log(zc-wc))^b (z-w)^c (zc-wc)^d |
30 | 32 | % |
31 | 33 | % Output |
32 | | -% mat - integration matrix |
| 34 | +% varargout - integration matrices for specified singularity types |
33 | 35 | % |
34 | 36 |
|
35 | 37 | % Helsing-Ojala (interior/exterior?) |
36 | | - |
37 | 38 | xlohi = intp_ab*(r(1,:,j)'+1i*r(2,:,j)'); % panel end points |
38 | 39 | r_i = intp*(r(1,:,j)'+1i*r(2,:,j)'); % upsampled panel |
39 | | -d_i = (intp*(d(1,:,j)'+1i*d(2,:,j)')); % r' |
40 | | -d2_i = (intp*(d2(1,:,j)'+1i*d2(2,:,j)')); % r'' |
| 40 | +d_i = (intp*(d(1,:,j)'+1i*d(2,:,j)')); % r' |
| 41 | +d2_i = (intp*(d2(1,:,j)'+1i*d2(2,:,j)')); % r'' |
| 42 | +wts_i = wts(:,j)'; % |
41 | 43 | sp = abs(d_i); tang = d_i./sp; % speed, tangent |
42 | 44 | n_i = -1i*tang; % normal |
43 | 45 | cur = -real(conj(d2_i).*n_i)./sp.^2; % curvature |
44 | | -wxp_i = w.*d_i; % complex speed weights (Helsing's wzp) |
| 46 | +wxp_i = w.*d_i; % complex speed weights (Helsing's wzp) |
| 47 | + |
| 48 | +varargout = cell(size(types)); |
| 49 | + |
| 50 | +% [As, Ad, A1, A2, A3, A4] = SDspecialquad(struct('x',rt(1,:)' + 1i*rt(2,:)'),... |
| 51 | +% struct('x',r_i,'nx',n_i,'wxp',wxp_i),xlohi(1),xlohi(2),opts.side); |
| 52 | +[As, Ad] = SDspecialquad(struct('x',rt(1,:)' + 1i*rt(2,:)'),... |
| 53 | + struct('x',r_i,'nx',n_i,'wxp',wxp_i),xlohi(1),xlohi(2),opts.side); |
| 54 | +As = As*intp; |
| 55 | +Ad = Ad*intp; |
45 | 56 |
|
46 | | -mat_ho_slp = Sspecialquad(struct('x',rt(1,:)' + 1i*rt(2,:)'),... |
47 | | - struct('x',r_i,'nx',n_i,'wxp',wxp_i),xlohi(1),xlohi(2),'e'); |
48 | | -mat_ho_dlp = Dspecialquad(struct('x',rt(1,:)' + 1i*rt(2,:)'),... |
49 | | - struct('x',r_i,'nx',n_i,'wxp',wxp_i),xlohi(1),xlohi(2),'e'); |
| 57 | +for j = 1:length(types) |
| 58 | + type0 = types{j}; |
50 | 59 |
|
51 | | -mat = (mat_ho_slp+real(mat_ho_dlp))*intp; % depends on kern, different mat1? |
| 60 | + if (all(type0 == [0 0 0 0])) |
| 61 | + varargout{j} = ones(size(rt,2),numel(wts_i)).*wts_i; |
| 62 | + elseif (all(type0 == [1 0 0 0])) |
| 63 | + % varargout{j} = Sspecialquad(struct('x',rt(1,:)' + 1i*rt(2,:)'),... |
| 64 | + % struct('x',r_i,'nx',n_i,'wxp',wxp_i),xlohi(1),xlohi(2),opts.side)*intp; |
| 65 | + varargout{j} = As; |
| 66 | + elseif (all(type0 == [0 0 -1 0])) |
| 67 | + % varargout{j} = Dspecialquad(struct('x',rt(1,:)' + 1i*rt(2,:)'),... |
| 68 | + % struct('x',r_i,'nx',n_i,'wxp',wxp_i),xlohi(1),xlohi(2),opts.side)*intp; |
| 69 | + varargout{j} = Ad; |
| 70 | + else |
| 71 | + error("split panel quad type " + join(string([1 2 3]),",") + " not available"); |
| 72 | + end |
52 | 73 |
|
53 | 74 | end |
| 75 | +end |
54 | 76 |
|
55 | 77 | function [A, A1, A2] = Sspecialquad(t,s,a,b,side) |
56 | 78 | % SSPECIALQUAD - SLP val+grad close-eval Helsing "special quadrature" matrix |
|
66 | 88 | % Efficient only if multiple targs, since O(p^3). |
67 | 89 | % See Helsing-Ojala 2008 (special quadr Sec 5.1-2), Helsing 2009 mixed (p=16), |
68 | 90 | % and Helsing's tutorial demo11b.m LGIcompRecFAS() |
| 91 | +% See https://github.com/ahbarnett/BIE2D/blob/master/panels/LapSLP_closepanel.m |
69 | 92 | if nargin<5, side = 'i'; end % interior or exterior |
70 | 93 | zsc = (b-a)/2; zmid = (b+a)/2; % rescaling factor and midpoint of src segment |
71 | 94 | y = (s.x-zmid)/zsc; x = (t.x-zmid)/zsc; % transformed src nodes, targ pts |
|
146 | 169 | % Efficient only if multiple targs, since O(p^3). |
147 | 170 | % See Helsing-Ojala 2008 (special quadr Sec 5.1-2), Helsing 2009 mixed (p=16), |
148 | 171 | % and Helsing's tutorial demo11b.m M1IcompRecFS() |
| 172 | +% See https://github.com/ahbarnett/BIE2D/blob/master/panels/LapDLP_closepanel.m |
149 | 173 | if nargin<5, side = 'i'; end % interior or exterior |
150 | 174 | zsc = (b-a)/2; zmid = (b+a)/2; % rescaling factor and midpoint of src segment |
151 | 175 | y = (s.x-zmid)/zsc; x = (t.x-zmid)/zsc; % transformed src nodes, targ pts |
|
203 | 227 | end |
204 | 228 | end |
205 | 229 | end |
| 230 | + |
| 231 | +function [As, A, A1, A2, A3, A4] = SDspecialquad(t,s,a,b,side) |
| 232 | +% S+D together... (with Sn) should be the same as requesting S or D |
| 233 | +% more expensive if request Dn... |
| 234 | +% https://github.com/ahbarnett/BIE2D/blob/master/panels/LapDLP_closepanel.m |
| 235 | +%%% d = 100; |
| 236 | +zsc = (b-a)/2; zmid = (b+a)/2; % rescaling factor and midpoint of src segment |
| 237 | +y = (s.x-zmid)/zsc; x = (t.x-zmid)/zsc; % transformed src nodes, targ pts |
| 238 | +%figure; plot(x,'.'); hold on; plot(y,'+-'); plot([-1 1],[0 0],'ro'); % debug |
| 239 | +N = numel(x); % # of targets |
| 240 | +p = numel(s.x); % assume panel order is # nodes |
| 241 | +if N*p==0 |
| 242 | + As = 0; A = 0; A1=0; A2=0; |
| 243 | + return |
| 244 | +end |
| 245 | +c = (1-(-1).^(1:p))./(1:p); % Helsing c_k, k = 1..p. |
| 246 | +V = ones(p,p); for k=2:p, V(:,k) = V(:,k-1).*y; end % Vandermonde mat @ nodes |
| 247 | +P = zeros(p+1,N); % Build P, Helsing's p_k vectorized on all targs... |
| 248 | +d = 1.1; inr = abs(x)<=d; ifr = abs(x)>d; % near & far treat separately |
| 249 | +%gam = 1i; |
| 250 | +gam = exp(1i*pi/4); % smaller makes cut closer to panel. barnett 4/17/18 |
| 251 | +if side == 'e', gam = conj(gam); end % note gam is a phase, rots branch cut |
| 252 | +P(1,:) = log(gam) + log((1-x)./(gam*(-1-x))); % init p_1 for all targs int |
| 253 | + |
| 254 | +% upwards recurrence for near targets, faster + more acc than quadr... |
| 255 | +% (note rotation of cut in log to -Im; so cut in x space is lower unit circle) |
| 256 | +if N>1 || (N==1 && inr==1) % Criterion added by Bowei Wu 03/05/15 to ensure inr not empty |
| 257 | + for k=1:p |
| 258 | + P(k+1,inr) = x(inr).'.*P(k,inr) + c(k); |
| 259 | + end % recursion for p_k |
| 260 | +end |
| 261 | +% fine quadr (no recurrence) for far targets (too inaccurate cf downwards)... |
| 262 | +Nf = numel(find(ifr)); wxp = s.wxp/zsc; % rescaled complex speed weights |
| 263 | +if Nf>0 % Criterion added by Bowei Wu 03/05/15 to ensure ifr not empty |
| 264 | + P(end,ifr) = sum(((wxp.*(V(:,end).*y(:)))*ones(1,Nf))./bsxfun(@minus,y,x(ifr).')); % int y^p/(y-x) |
| 265 | + for ii = p:-1:2 |
| 266 | + P( ii,ifr) = (P(ii+1,ifr)-c(ii))./x(ifr).'; |
| 267 | + end |
| 268 | +end |
| 269 | + |
| 270 | +Q = zeros(p,N); % compute q_k from p_k via Helsing 2009 eqn (18)... (p even!) |
| 271 | +% Note a rot ang appears here too... 4/17/18 |
| 272 | +%gam = exp(1i*pi/4); % 1i; % moves a branch arc as in p_1 |
| 273 | +%if side == 'e', gam = conj(gam); end % note gam is a phase, rots branch cut |
| 274 | +Q(1:2:end,:) = P(2:2:end,:) - repmat(log((1-x.').*(-1-x.')),[ceil(p/2) 1]); % guessed! |
| 275 | +% (-1)^k, k odd, note each log has branch cut in semicircle from -1 to 1 |
| 276 | +% Q(2:2:end,:) = P(3:2:end,:) - repmat(log((1-x.')./((-1-x.'))),[floor(p/2) 1]); % same cut as for p_1 |
| 277 | +Q(2:2:end,:) = P(3:2:end,:) - repmat(log(gam) + log((1-x.')./(gam*(-1-x.'))),[floor(p/2) 1]); % same cut as for p_1 |
| 278 | +Q = Q.*repmat(1./(1:p)',[1 N]); % k even |
| 279 | +As = real((V.'\Q).'.*repmat((1i*s.nx)',[N 1])*zsc)/(2*pi*abs(zsc)); |
| 280 | +As = As*abs(zsc) - log(abs(zsc))/(2*pi)*repmat(abs(s.wxp)',[N 1]); % unscale, yuk |
| 281 | +warning('off','MATLAB:nearlySingularMatrix'); |
| 282 | +% A = real((V.'\P).'*(1i/(2*pi))); % solve for special quadr weights |
| 283 | +A = ((V.'\P(1:p,:)).'*(1i/(2*pi))); % do not take real for the eval of Stokes DLP non-laplace term. Bowei 10/19/14 |
| 284 | +%A = (P.'*inv(V))*(1i/(2*pi)); % equiv in exact arith, but not bkw stable. |
| 285 | +if nargout>2 |
| 286 | + R = -(kron(ones(p,1),1./(1-x.')) + kron((-1).^(0:p-1).',1./(1+x.'))) +... |
| 287 | + repmat((0:p-1)',[1 N]).*[zeros(1,N); P(1:p-1,:)]; % hypersingular kernel weights of Helsing 2009 eqn (14) |
| 288 | + Az = (V.'\R).'*(1i/(2*pi*zsc)); % solve for targ complex-deriv mat & rescale |
| 289 | + A1 = Az; |
| 290 | + if nargout > 3 |
| 291 | + S = -(kron(ones(p,1),1./(1-x.').^2) - kron((-1).^(0:p-1).',1./(1+x.').^2))/2 +... |
| 292 | + repmat((0:p-1)',[1 N]).*[zeros(1,N); R(1:p-1,:)]/2; % supersingular kernel weights |
| 293 | + Azz = (V.'\S).'*(1i/(2*pi*zsc^2)); |
| 294 | + if nargout > 4 |
| 295 | + A1 = real(Az); A2 = -imag(Az); % note sign for y-deriv from C-deriv |
| 296 | + A3 = real(Azz); A4 = -imag(Azz); |
| 297 | + else |
| 298 | + A1 = Az; A2 = Azz; |
| 299 | + end |
| 300 | + end |
| 301 | +end |
| 302 | +end |
0 commit comments