|
| 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