Skip to content

Commit

Permalink
Merge pull request #57 from fastalgorithms/rcip-interp
Browse files Browse the repository at this point in the history
rcip density interpolation
  • Loading branch information
mrachh authored Feb 29, 2024
2 parents 912d8df + 9fba9c3 commit 21e5dfe
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 49 deletions.
6 changes: 6 additions & 0 deletions chunkie/+chnk/+rcip/IPinit.m
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
function [IP,IPW]=IPinit(T,W)
%CHNK.RCIP.IPinit
%
% construct the prolongation matrix IP that maps function values
% on n_{gl} Gauss-Legendre nodes on [-1,1] to function values at
% 2n_{gl} Gauss-Legendre, with shifted and scaled n_{gl}
% Gauss-Legendre nodes on each subinterval [-1,0], [0,1], respectively.
%
% IPW is the weighted prolongation matrix acted on the left side.
%

% author: Johan Helsing (part of RCIP tutorial)

ngl = length(T);
A=ones(ngl);
AA=ones(2*ngl,ngl);
Expand Down
99 changes: 80 additions & 19 deletions chunkie/+chnk/+rcip/Rcompchunk.m
Original file line number Diff line number Diff line change
@@ -1,46 +1,73 @@
function [R]=Rcompchunk(chnkr,iedgechunks,fkern,ndim, ...
Pbc,PWbc,nsub,starL,circL,starS,circS,ilist,...
glxs,sbcmat,lvmat,u,opts)
function [R,rcipsav]=Rcompchunk(chnkr,iedgechunks,fkern,ndim, ...
Pbc,PWbc,nsub,starL,circL,starS,circS,ilist,starL1,circL1,...
sbclmat,sbcrmat,lvmat,rvmat,u,opts)
%CHNK.RCIP.Rcompchunk carry out the forward recursion for computing
% the preconditioner R where geometry is described as a chunker
%
% This routine is not intended to be user-callable
%
% Adapted from Shidong Jiang's RCIP implementation
%
% Function is passed as a handle, number of equations is given by
% ndim
%
% Kernel on input takes in arguments (chnkrlocal,ilistl);
%
% Note that matrix must be scaled to have identity on the diagonal,
% will not work with scaled version of identity

%

% author: Shidong Jiang
% modified: Jeremy Hoskins, Manas Rachh


k = chnkr.k;
dim = chnkr.dim;
nedge = size(iedgechunks,2);

glxs = chnkr.tstor;
glws = chnkr.wstor;

if nargin < 14
% return what's needed to interpolate from coarse

rcipsav = [];
rcipsav.k = k;
rcipsav.ndim = ndim;
rcipsav.nedge = nedge;
rcipsav.Pbc = Pbc;
rcipsav.PWbc = PWbc;
rcipsav.starL = starL;
rcipsav.starL1 = starL1;
rcipsav.starS = starS;
rcipsav.circL = circL;
rcipsav.circL1 = circL1;
rcipsav.circS = circS;
rcipsav.ilist = ilist;
rcipsav.nsub = nsub;

if (nargin < 15 || isempty(sbclmat) || isempty(sbcrmat) || ...
isempty(lvmat) || isempty(rvmat) || isempty(u))
[sbclmat,sbcrmat,lvmat,rvmat,u] = chnk.rcip.shiftedlegbasismats(k);
end

if nargin < 17
if nargin < 20
opts = [];
end

nedge = size(iedgechunks,2);
savedeep = false;
if isfield(opts,'savedeep')
savedeep = opts.savedeep;
end

ileftright = zeros(nedge,1);
nextchunk = zeros(nedge,1);
rcipsav.savedeep = savedeep;

if savedeep
rcipsav.R = cell(nsub+1,1);
rcipsav.MAT = cell(nsub,1);
rcipsav.chnkrlocals = cell(nsub,1);
end


% grab only those kernels relevant to this vertex

km1 = k-1;
rcs = zeros(km1,dim,nedge);
dcs = zeros(k,dim,nedge);
d2cs = zeros(k,dim,nedge);
dscal = zeros(nedge,1);
d2scal = zeros(nedge,1);
ctr = zeros(dim,nedge);
if(size(fkern)==1)
fkernlocal = fkern;
else
Expand All @@ -55,6 +82,20 @@

end

rcipsav.fkernlocal = fkernlocal;

% get coefficients of recentered edge chunks and figure out orientation

km1 = k-1;
rcs = zeros(km1,dim,nedge);
dcs = zeros(k,dim,nedge);
d2cs = zeros(k,dim,nedge);
dscal = zeros(nedge,1);
d2scal = zeros(nedge,1);
ctr = zeros(dim,nedge);

ileftright = zeros(nedge,1);
nextchunk = zeros(nedge,1);

for i = 1:nedge
ic = iedgechunks(1,i);
Expand Down Expand Up @@ -92,10 +133,19 @@
end
end

rcipsav.ctr = ctr;
rcipsav.rcs = rcs;
rcipsav.dcs = dcs;
rcipsav.d2cs = d2cs;
rcipsav.dscal = dscal;
rcipsav.d2scal = d2scal;
rcipsav.ileftright = ileftright;
rcipsav.glxs = glxs;
rcipsav.glws = glws;

pref = [];
pref.k = k;
pref.nchmax = 5;
pref.nchstor = 5;

R = [];

Expand All @@ -108,6 +158,9 @@
ts = cell(nedge,1);
chnkrlocal(1,nedge) = chunker();

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% begin recursion proper

h0=ones(nedge,1);
for level=1:nsub
h = h0/2^(nsub-level);
Expand Down Expand Up @@ -176,8 +229,16 @@
if level==1 % Dumb and lazy initializer for R, for now
%R=eye(nR);
R = inv(MAT(starL,starL));
if savedeep
rcipsav.R{1} = R;
end
end
R=chnk.rcip.SchurBana(Pbc,PWbc,MAT,R,starL,circL,starS,circS);
if savedeep
rcipsav.R{level+1} = R;
rcipsav.MAT{level} = MAT(starL,circL);
rcipsav.chnkrlocals{level} = merge(chnkrlocal);
end
end

end
Expand Down
35 changes: 32 additions & 3 deletions chunkie/+chnk/+rcip/SchurBana.m
Original file line number Diff line number Diff line change
@@ -1,10 +1,36 @@
function A=SchurBana(P,PW,K,A,starL,circL,starS,circS)
% use matrix block inversion formula to recursively compute the
%CHNK.RCIP.SCHURBANA block inverse used in RCIP
%
% uses a matrix block inversion formula to recursively compute the
% preconditioner R.
%
% R_{i} = [PW^T 0] [A^(-1) U]^(-1) [P 0]
% [ 0 I] [V D] [0 I]
%
% 2N x 3N 3N x 3N 3N x 2N
%
% where A = R_{i-1}, U = K(bad,good), V = K(good,bad), D = K(good,good)
% and bad refers to the two close panels on a type b mesh and good the
% larger far panel.
%
% This routine uses the Schur-Banachiewicz speedup as suggested by
% Helsing (see e.g. the RCIP Tutorial eq 31):
%
% R_{i} = [M1 M2]
% [M3 M4]
%
% M1 = PW^T A P + PW^T A U (D - VAU)^(-1) VAP
% M2 = -PW^TAU(D-VAU)^(-1)
% M3 = -(D-VAU)^(-1)VAP
% M4 = (D-VAU)^(-1)
%
% this reduces a 3Nx3N matrix inverse to a NxN matrix inverse and
% several mat-mats
%
% inputs:
% P, PW - nontrivial part (i.e., other than the identity matrices)
% prolongation and weighted prolongation matrices
% prolongation and weighted prolongation matrices from type c to
% type b meshes
% K - the system matrix on a type-b mesh along each edge.
% the type-b mesh contains three chunks, with two small chunks
% close to the corner and one big chunk (twice of the small chunk
Expand Down Expand Up @@ -34,10 +60,13 @@
% output:
% A - R_{i}, the ith iteration of R.
%

% author: Johan Helsing (part of the RCIP tutorial)

VA=K(circL,starL)*A;
PTA=PW'*A;
PTAU=PTA*K(starL,circL);
DVAUI=chnk.rcip.myinv(K(circL,circL)-VA*K(starL,circL));
DVAUI=inv(K(circL,circL)-VA*K(starL,circL));
DVAUIVAP=DVAUI*(VA*P);
A(starS,starS)=PTA*P+PTAU*DVAUIVAP;
A(circS,circS)=DVAUI;
Expand Down
1 change: 1 addition & 0 deletions chunkie/+chnk/+rcip/myinv.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
function Mi=myinv(M)
% *** equation (9) in Henderson & Searle ***

np=length(M)/2;
A=M(1:np,1:np);
U=M(1:np,np+1:2*np);
Expand Down
140 changes: 140 additions & 0 deletions chunkie/+chnk/+rcip/rhohatInterp.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
function [rhohatinterp,srcinfo,wts] = rhohatInterp(rhohat,rcipsav,ndepth)
%CHNK.RCIP.RHOHATINTERP interpolate the (weight-corrected) coarse level
% density rhohat to the requested depth using the backward recursion
%
% When using an RCIP preconditioner (in the style of eq 34 of the RCIP
% tutorial), the resulting coarse level density is
% accurate for interactions separated from the vertex
% *at the coarse scale*.
% By running the recursion for the RCIP preconditioner backwards, an
% equivalent density can be reconstructed on the fine mesh which is
% appropriate for closer interactions (at a distance well-separated from
% the vertex *at the finest level in the mesh*).
%
% - Let Gamma_i be the portion of the boundary in the vicinity of
% the vertex at level i (with level nsub the coarse level portion of the
% boundary and level 1 the lowest level).
% - Let rhohat_i be the weight corrected density on a type c mesh on
% Gamma_i
% - Let the matrix I+K_i be a discretization of the integral operator on a
% type b mesh on Gamma_i
% - Let starL denote the "bad indices" of K_i and circL the "good indices";
% the bad correspond to the pairs of small close panels on a type b mesh
% - Let starS denote the "bad indices" of R_i and circS the "good indices";
% the bad correspond to the close panels on a type c mesh
% - Let P be the non-trivial part of an interpolator from type c to type b
% meshes.
%
% Then, to high precision
%
% rhohat_{i-1} = R_{i-1}[ [P 0] R_i^(-1) rhohat_i -
% (I+K_i)(starL,circL)rhohat_i(circS)]
%
% INPUT
%
% rhohat - entries of density rhohat corresponding to RCIP block in matrix.
% These come from the two nearest chunks to the corner and
% should be ordered so that rhohat(starS) and rhohat(circS)
% correspond to the density at the bad and good points (near and
% far chunk) in the correct order (accounting for chunk
% orientation)
% rcipsav - the quantities obtained from a previous call to Rcompchunk
% ndepth - (default: rcip.nsub) compute up to rhohat_{nsub-ndepth+1}
%
% OUTPUT
%
% rhohatinterp - array of interpolated values,
% [rhohat_nsub(circS); rhohat_{nsub-1}(circS); rhohat_{nsub-2}(circS) ...
% rhohat_1(circS); rhohat_1(starS)]
% note that these are mostly the "good" indices except at
% the lowest level (naturally)
% srcinfo - struct, containing points (srcinfo.r), normals (srcinfo.n), etc
% in the same order as rhohatinterp.
% wts - a set of weights for integrating functions sampled at these
% points


rhohatinterp = [];
srcinfo = [];
wts = [];

k = rcipsav.k;
ndim = rcipsav.ndim;
nedge = rcipsav.nedge;
Pbc = rcipsav.Pbc;
PWbc = rcipsav.PWbc;
starL = rcipsav.starL;
starL1 = rcipsav.starL1;
starS = rcipsav.starS;
circL = rcipsav.circL;
circL1 = rcipsav.circL1;
circS = rcipsav.circS;
ilist = rcipsav.ilist;
nsub = rcipsav.nsub;

if nargin < 3
ndepth = nsub;
end

if ndepth > nsub
msg = "depth requested deeper than RCIP recursion performed\n " + ...
"going to depth %d instead";
warning(msg,nsub);
ndepth = nsub;
end

savedeep = rcipsav.savedeep;

if savedeep

% all relevant quantities are stored, just run backward recursion

rhohat0 = rhohat;
rhohatinterp = [rhohatinterp; rhohat0(circS)];
r = [];
d = [];
d2 = [];
n = [];
h = [];
cl = rcipsav.chnkrlocals{nsub};
wt = weights(cl);
r = [r, cl.rstor(:,circL1)];
d = [d, cl.dstor(:,circL1)];
d2 = [d2, cl.d2stor(:,circL1)];
n = [n, cl.nstor(:,circL1)];
wts = [wts; wt(circL1(:))];

R0 = rcipsav.R{nsub+1};
for i = 1:ndepth
R1 = rcipsav.R{nsub-i+1};
MAT = rcipsav.MAT{nsub-i+1};
rhotemp = R0\rhohat0;
rhohat0 = R1*(Pbc*rhotemp(starS) - MAT*rhohat0(circS));
if i == ndepth
rhohatinterp = [rhohatinterp; rhohat0];
r = [r, cl.rstor(:,starL1)];
d = [d, cl.dstor(:,starL1)];
d2 = [d2, cl.d2stor(:,starL1)];
n = [n, cl.nstor(:,starL1)];
wt = weights(cl);

wts = [wts; wt(starL1(:))];
else
cl = rcipsav.chnkrlocals{nsub-i};
rhohatinterp = [rhohatinterp; rhohat0(circS)];
r = [r, cl.rstor(:,circL1)];
d = [d, cl.dstor(:,circL1)];
d2 = [d2, cl.d2stor(:,circL1)];
n = [n, cl.nstor(:,circL1)];
wt = weights(cl);
wts = [wts; wt(circL1(:))];
end
R0 = R1;
end

srcinfo.r = r;
srcinfo.d = d;
srcinfo.d2 = d2;
srcinfo.n = n;

end
Loading

0 comments on commit 21e5dfe

Please sign in to comment.