Skip to content

Commit 8c84d9d

Browse files
authored
Merge pull request #113 from jacobtlinden/master
using helmdiffgreen for helm2ddiff
2 parents a391a1c + 904da56 commit 8c84d9d

File tree

6 files changed

+544
-60
lines changed

6 files changed

+544
-60
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
function [cf1,cf2] = besseldiff_etc_pscoefs(nterms)
2+
% powerseries coefficients for J_0 - 1 and the other series in
3+
% definition of Y_0
4+
%
5+
% these are both series with the terms z^2,z^4,z^6,..z^(2*nterms)
6+
%
7+
% cf1 are power series coeffs of even terms (excluding constant)
8+
% for J_0(z) - 1
9+
%
10+
% cf2 are power series coeffs for the similar series
11+
% z^2/4 - (1+1/2)*(z^2/4)^2/(2!)^2 + (1+1/2+1/3)*(z^2/4)^3/(3!)^2 - ...
12+
%
13+
% which appears in the power series for H_0(z)
14+
15+
sum1 = 0;
16+
fac1 = 1;
17+
pow1 = 1;
18+
19+
cf1 = zeros(nterms,1);
20+
cf2 = zeros(nterms,1);
21+
sgn = 1;
22+
23+
for j = 1:nterms
24+
fac1 = fac1/(j*j);
25+
sum1 = sum1 + 1.0/j;
26+
pow1 = pow1*0.25;
27+
cf1(j) = -sgn*pow1*fac1;
28+
cf2(j) = sgn*sum1*pow1*fac1;
29+
sgn = -sgn;
30+
end
31+
32+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
function [v] = even_pseval(cf,x)
2+
% evaluates an even power series with no constant term
3+
% with coefficients given in cf.
4+
%
5+
% x can be an array
6+
7+
x2 = x.*x;
8+
9+
xp = x2;
10+
11+
v = zeros(size(x));
12+
13+
nterms = length(cf);
14+
for j = 1:nterms
15+
v = v + cf(j)*xp;
16+
xp = xp.*x2;
17+
end
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
function [val,grad,hess,der3,der4,der5] = helmdiffgreen(k,src,targ,ifr2logr)
2+
%HELMDIFFGREEN evaluate the difference of the
3+
% Helmholtz Green function and the Laplace Green function
4+
% for the given sources and targets, i.e.
5+
%
6+
% G(x,y) = i/4 H_0^(1)(k|x-y|) + 1/(2 pi) log(|x-y|)
7+
%
8+
% or the difference of the Helmholtz and Laplace Green funcions
9+
% and k^2 r^2 log r/ 8 pi (a constant times the biharmonic Green function)
10+
% i.e.
11+
%
12+
% G(x,y) = i/4 H_0^(1)(k|x-y|) + 1/(2 pi) log(|x-y|) + ...
13+
% - k^2/(8*pi) |x-y|^2 log(|x-y|)
14+
%
15+
% where H_0^(1) is the principal branch of the Hankel function
16+
% of the first kind. This routine avoids numerical cancellation
17+
% when |k||x-y| is small.
18+
%
19+
% - grad(:,:,1) has G_{x1}, grad(:,:,2) has G_{x2}
20+
% - hess(:,:,1) has G_{x1x1}, hess(:,:,2) has G_{x1x2},
21+
% hess(:,:,3) has G_{x2x2}
22+
% - der3 has the third derivatives in the order G_{x1x1x1}, G_{x1x1x2},
23+
% G_{x1x2x2}, G_{x2x2x2}
24+
% - der4 has the fourth derivatives in the order G_{x1x1x1x1},
25+
% G_{x1x1x1x2}, G_{x1x1x2x2}, G_{x1x2x2x2}, G_{x2x2x2x2}
26+
%
27+
% derivatives are on the *target* variables
28+
%
29+
% input:
30+
%
31+
% src - (2,ns) array of source locations
32+
% targ - (2,nt) array of target locations
33+
% k - wave number, as above
34+
%
35+
% optional input:
36+
%
37+
% ifr2logr - boolean, default: false. If true, also subtract off the
38+
% k^2/(8pi) r^2 log r kernel
39+
40+
if nargin < 4
41+
ifr2logr = false;
42+
end
43+
44+
r2logrfac = 1;
45+
if ifr2logr
46+
r2logrfac = 0;
47+
end
48+
49+
[~,ns] = size(src);
50+
[~,nt] = size(targ);
51+
52+
xs = repmat(src(1,:),nt,1);
53+
ys = repmat(src(2,:),nt,1);
54+
55+
xt = repmat(targ(1,:).',1,ns);
56+
yt = repmat(targ(2,:).',1,ns);
57+
58+
dx = xt-xs;
59+
dy = yt-ys;
60+
61+
dx2 = dx.*dx;
62+
dx3 = dx2.*dx;
63+
dx4 = dx3.*dx;
64+
dx5 = dx4.*dx;
65+
66+
dy2 = dy.*dy;
67+
dy3 = dy2.*dy;
68+
dy4 = dy3.*dy;
69+
dy5 = dy4.*dy;
70+
71+
r2 = dx2 + dy2;
72+
r = sqrt(r2);
73+
rm1 = 1./r;
74+
rm2 = rm1.*rm1;
75+
rm3 = rm1.*rm2;
76+
rm4 = rm1.*rm3;
77+
rm5 = rm1.*rm4;
78+
79+
% get value and r derivatives
80+
81+
[g0,g1,g21,g3,g4,g5] = diff_h0log_and_rders(k,r,r2logrfac);
82+
83+
% evaluate potential and derivatives
84+
85+
if nargout > 0
86+
val = g0;
87+
end
88+
if nargout > 1
89+
grad(:,:,1) = dx.*g1.*rm1;
90+
grad(:,:,2) = dy.*g1.*rm1;
91+
end
92+
if nargout > 2
93+
hess(:,:,1) = dx2.*g21.*rm2+g1.*rm1;
94+
hess(:,:,2) = dx.*dy.*g21.*rm2;
95+
hess(:,:,3) = dy2.*g21.*rm2+g1.*rm1;
96+
end
97+
if nargout > 3
98+
der3(:,:,1) = (dx3.*g3+3*dy2.*dx.*g21.*rm1).*rm3;
99+
der3(:,:,2) = dx2.*dy.*(g3.*rm3-3*g21.*rm4) + ...
100+
dy.*g21.*rm2;
101+
der3(:,:,3) = dx.*dy2.*(g3.*rm3-3*g21.*rm4) + ...
102+
dx.*g21.*rm2;
103+
der3(:,:,4) = (dy3.*g3+3*dx2.*dy.*g21.*rm1).*rm3;
104+
end
105+
106+
if nargout > 4
107+
der4(:,:,1) = (dx4.*(g4-6*g3.*rm1+15*g21.*rm2)).*rm4 + ...
108+
(6*dx2.*(g3-3*g21.*rm1)).*rm3 + ...
109+
3*g21.*rm2;
110+
der4(:,:,2) = (dx3.*dy.*(g4-6*g3.*rm1+15*g21.*rm2)).*rm4 + ...
111+
(3*dx.*dy.*(g3-3*g21.*rm1)).*rm3;
112+
der4(:,:,3) = dx2.*dy2.*(g4-6*g3.*rm1+15*g21.*rm2).*rm4 + ...
113+
g3.*rm1 - 2*g21.*rm2;
114+
der4(:,:,4) = dx.*dy3.*(g4-6*g3.*rm1+15*g21.*rm2).*rm4 + ...
115+
3*dx.*dy.*(g3-3*g21.*rm1).*rm3;
116+
der4(:,:,5) = dy4.*(g4-6*g3.*rm1+15*g21.*rm2).*rm4 + ...
117+
6*dy2.*(g3-3*g21.*rm1).*rm3 + ...
118+
3*g21.*rm2;
119+
end
120+
121+
if nargout > 5
122+
der5(:,:,1) = (dx5.*g5+10*dy2.*dx3.*g4.*rm1 + ...
123+
(15*dy4.*dx-30*dy2.*dx3).*g3.*rm2 + ...
124+
(60*dy2.*dx3-45*dy4.*dx).*g21.*rm3).*rm5;
125+
der5(:,:,2) = (dy.*dx4.*g5+(6*dy3.*dx2-4*dy.*dx4).*g4.*rm1 + ...
126+
(3*dy5+12*dy.*dx4-30*dy3.*dx2).*g3.*rm2 + ...
127+
(72*dy3.*dx2-9*dy5-24*dy.*dx4).*g21.*rm3).*rm5;
128+
der5(:,:,3) = (dy2.*dx3.*g5+(3*dy4.*dx-6*dy2.*dx3+dx5).*g4.*rm1 + ...
129+
(27*dy2.*dx3-15*dy4.*dx-3*dx5).*g3.*rm2 + ...
130+
(36*dy4.*dx-63*dy2.*dx3+6*dx5).*g21.*rm3).*rm5;
131+
der5(:,:,4) = (dx2.*dy3.*g5+(3*dx4.*dy-6*dx2.*dy3+dy5).*g4.*rm1 + ...
132+
(27*dx2.*dy3-15*dx4.*dy-3*dy5).*g3.*rm2 + ...
133+
(36*dx4.*dy-63*dx2.*dy3+6*dy5).*g21.*rm3).*rm5;
134+
der5(:,:,5) = (dx.*dy4.*g5+(6*dx3.*dy2-4*dx.*dy4).*g4.*rm1 + ...
135+
(3*dx5+12*dx.*dy4-30*dx3.*dy2).*g3.*rm2 + ...
136+
(72*dx3.*dy2-9*dx5-24*dx.*dy4).*g21.*rm3).*rm5;
137+
der5(:,:,6) = (dy5.*g5+10*dx2.*dy3.*g4.*rm1 + ...
138+
(15*dx4.*dy-30*dx2.*dy3).*g3.*rm2 + ...
139+
(60*dx2.*dy3-45*dx4.*dy).*g21.*rm3).*rm5;
140+
end
141+
142+
end
143+
144+
function [g0,g1,g21,g3,g4,g5] = diff_h0log_and_rders(k,r,r2logrfac)
145+
% g0 = g
146+
% g1 = g'
147+
% g21 = g'' - g'/r
148+
%
149+
% maybe later:
150+
% g321 = g''' - 3*g''/r + 3g'/r^2
151+
% g4321 = g'''' - 6*g'''/r + 15*g''/r^2 - 15*g'/r^3
152+
153+
g0 = zeros(size(r));
154+
g1 = zeros(size(r));
155+
g3 = zeros(size(r));
156+
g4 = zeros(size(r));
157+
g5 = zeros(size(r));
158+
g21 = zeros(size(r));
159+
160+
io4 = 1i*0.25;
161+
o2p = 1/(2*pi);
162+
163+
isus = abs(k)*r < 1;
164+
%isus = false(size(r));
165+
%isus = true(size(r));
166+
167+
% straightforward formulas for sufficiently large
168+
169+
rnot = r(~isus);
170+
171+
kr = k*rnot;
172+
173+
h0 = besselh(0,1,kr);
174+
h1 = besselh(1,1,kr);
175+
176+
rm1 = 1./rnot;
177+
rm2 = rm1.*rm1;
178+
rm3 = rm1.*rm2;
179+
rm4 = rm1.*rm3;
180+
rm5 = rm1.*rm4;
181+
182+
r2fac = (1-r2logrfac)*k*k*0.25*o2p;
183+
logr = log(rnot);
184+
g0(~isus) = io4*h0 + o2p*logr - r2fac*rnot.*rnot.*logr;
185+
g1(~isus) = -k*io4*h1 + o2p*rm1 - r2fac*(rnot+2*rnot.*logr);
186+
g21(~isus) = -k*k*io4*h0 + k*io4*h1.*rm1 - o2p*rm2 - r2fac*(3+2*logr) - ...
187+
g1(~isus).*rm1;
188+
g3(~isus) = k*k*io4*h0.*rm1 + io4*k*(k*k-2*rm2).*h1 + 2*o2p*rm3 - r2fac*2*rm1;
189+
g4(~isus) = k*io4*(3*rm2-k*k).*(2*h1.*rm1-k*h0) - 6*o2p*rm4 + r2fac*2*rm2;
190+
g5(~isus) = io4*k*( (12*k*rm3-2*k^3*rm1).*h0 + ...
191+
(-24*rm4+7*k*k*rm2-k^4).*h1) + 24*o2p*rm5 - r2fac*4*rm3;
192+
193+
% manually cancel when small
194+
195+
rsus = r(isus);
196+
rm1 = 1./rsus;
197+
rm2 = rm1.*rm1;
198+
rm3 = rm1.*rm2;
199+
rm4 = rm1.*rm3;
200+
rm5 = rm1.*rm4;
201+
202+
gam = 0.57721566490153286060651209;
203+
nterms = 14;
204+
const1 = (io4+(log(2)-gam-log(k))*o2p);
205+
206+
% relevant parts of hankel function represented as power series
207+
[cf1,cf2] = chnk.helm2d.besseldiff_etc_pscoefs(nterms);
208+
cf1(1) = cf1(1)*r2logrfac;
209+
kpow = (k*k).^(1:nterms);
210+
cf1 = cf1(:).*kpow(:); cf2 = cf2(:).*kpow(:);
211+
212+
logr = log(rsus);
213+
214+
j0m1 = chnk.helm2d.even_pseval(cf1,rsus);
215+
f = chnk.helm2d.even_pseval(cf2,rsus);
216+
217+
% differentiate power series to get derivatives
218+
fac = 2*(1:nterms);
219+
d21 = fac(:).*(fac(:)-1)-fac(:);
220+
fd21 = chnk.helm2d.even_pseval(cf2(:).*d21,rsus).*rm2;
221+
cf1 = cf1.*fac(:); cf2 = cf2.*fac(:);
222+
j0m1d1 = chnk.helm2d.even_pseval(cf1,rsus).*rm1;
223+
fd1 = chnk.helm2d.even_pseval(cf2,rsus).*rm1;
224+
cf1 = cf1.*(fac(:)-1); cf2 = cf2.*(fac(:)-1);
225+
j0m1d2 = chnk.helm2d.even_pseval(cf1,rsus).*rm2;
226+
fd2 = chnk.helm2d.even_pseval(cf2,rsus).*rm2;
227+
228+
cf1 = cf1(:).*(fac(:)-2); cf1 = cf1(2:end);
229+
cf2 = cf2(:).*(fac(:)-2); cf2 = cf2(2:end);
230+
j0m1d3 = chnk.helm2d.even_pseval(cf1,rsus).*rm1;
231+
232+
fd3 = chnk.helm2d.even_pseval(cf2,rsus).*rm1;
233+
fac = fac(1:end-1);
234+
cf1 = cf1(:).*(fac(:)-1); cf2 = cf2(:).*(fac(:)-1);
235+
j0m1d4 = chnk.helm2d.even_pseval(cf1,rsus).*rm2;
236+
fd4 = chnk.helm2d.even_pseval(cf2,rsus).*rm2;
237+
238+
cf1 = cf1(:).*(fac(:)-2); cf1 = cf1(2:end);
239+
cf2 = cf2(:).*(fac(:)-2); cf2 = cf2(2:end);
240+
j0m1d5 = chnk.helm2d.even_pseval(cf1,rsus).*rm1;
241+
fd5 = chnk.helm2d.even_pseval(cf2,rsus).*rm1;
242+
243+
% combine to get derivative of i/4 H + log/(2*pi)
244+
r2fac = -(1-r2logrfac)*k*k*0.25;
245+
g0(isus) = const1*(j0m1+1+r2fac*rsus.*rsus) - o2p*(f + logr.*j0m1);
246+
g1(isus) = const1*(j0m1d1+2*r2fac*rsus) - o2p*(fd1 + logr.*j0m1d1 + j0m1.*rm1);
247+
g21(isus) = const1*(j0m1d2-j0m1d1.*rm1) - o2p*(fd21 + logr.*(j0m1d2-j0m1d1.*rm1) + 2*j0m1d1.*rm1 - 2*j0m1.*rm2);
248+
g3(isus) = const1*j0m1d3 - o2p*(fd3 + logr.*j0m1d3 + 3*j0m1d2.*rm1 - ...
249+
3*j0m1d1.*rm2 + 2*j0m1.*rm3);
250+
g4(isus) = const1*j0m1d4 - o2p*(fd4 + logr.*j0m1d4 + 4*j0m1d3.*rm1 - ...
251+
6*j0m1d2.*rm2 + 8*j0m1d1.*rm3 - 6*j0m1.*rm4);
252+
g5(isus) = const1*j0m1d5 - o2p*(fd5 + logr.*j0m1d5 + 5*j0m1d4.*rm1 - ...
253+
10*j0m1d3.*rm2 + 20*j0m1d2.*rm3 - 30*j0m1d1.*rm4 + 24*j0m1.*rm5);
254+
255+
end
256+

0 commit comments

Comments
 (0)