📄 gridfit.m
字号:
if length(xnodes)==1 xnodes = linspace(xmin,xmax,xnodes)'; xnodes(end) = xmax; % make sure it hits the maxendif length(ynodes)==1 ynodes = linspace(ymin,ymax,ynodes)'; ynodes(end) = ymax; % make sure it hits the maxendxnodes=xnodes(:);ynodes=ynodes(:);dx = diff(xnodes);dy = diff(ynodes);nx = length(xnodes);ny = length(ynodes);ngrid = nx*ny;% set the scaling if autoscale was onif strcmpi(params.autoscale,'on') params.xscale = mean(dx); params.yscale = mean(dy); params.autoscale = 'off';end% check to see if any tiling is necessaryif (params.tilesize < max(nx,ny)) % split it into smaller tiles. compute zgrid and ygrid % at the very end if requested zgrid = tiled_gridfit(x,y,z,xnodes,ynodes,params);else % its a single tile. % mask must be either an empty array, or a boolean % aray of the same size as the final grid. nmask = size(params.mask); if ~isempty(params.mask) && ((nmask(2)~=nx) || (nmask(1)~=ny)) if ((nmask(2)==ny) || (nmask(1)==nx)) error 'Mask array is probably transposed from proper orientation.' else error 'Mask array must be the same size as the final grid.' end end if ~isempty(params.mask) params.maskflag = 1; else params.maskflag = 0; end % default for maxiter? if isempty(params.maxiter) params.maxiter = min(10000,nx*ny); end % check lengths of the data n = length(x); if (length(y)~=n) || (length(z)~=n) error 'Data vectors are incompatible in size.' end if n<3 error 'Insufficient data for surface estimation.' end % verify the nodes are distinct if any(diff(xnodes)<=0) || any(diff(ynodes)<=0) error 'xnodes and ynodes must be monotone increasing' end % do we need to tweak the first or last node in x or y? if xmin<xnodes(1) switch params.extend case 'always' xnodes(1) = xmin; case 'warning' warning(['xnodes(1) was decreased by: ',num2str(xnodes(1)-xmin),', new node = ',num2str(xmin)]) xnodes(1) = xmin; case 'never' error(['Some x (',num2str(xmin),') falls below xnodes(1) by: ',num2str(xnodes(1)-xmin)]) end end if xmax>xnodes(end) switch params.extend case 'always' xnodes(end) = xmax; case 'warning' warning(['xnodes(end) was increased by: ',num2str(xmax-xnodes(end)),', new node = ',num2str(xmax)]) xnodes(end) = xmax; case 'never' error(['Some x (',num2str(xmax),') falls above xnodes(end) by: ',num2str(xmax-xnodes(end))]) end end if ymin<ynodes(1) switch params.extend case 'always' ynodes(1) = ymin; case 'warning' warning(['ynodes(1) was decreased by: ',num2str(ynodes(1)-ymin),', new node = ',num2str(ymin)]) ynodes(1) = ymin; case 'never' error(['Some y (',num2str(ymin),') falls below ynodes(1) by: ',num2str(ynodes(1)-ymin)]) end end if ymax>ynodes(end) switch params.extend case 'always' ynodes(end) = ymax; case 'warning' warning(['ynodes(end) was increased by: ',num2str(ymax-ynodes(end)),', new node = ',num2str(ymax)]) ynodes(end) = ymax; case 'never' error(['Some y (',num2str(ymax),') falls above ynodes(end) by: ',num2str(ymax-ynodes(end))]) end end % determine which cell in the array each point lies in [junk,indx] = histc(x,xnodes); %#ok [junk,indy] = histc(y,ynodes); %#ok % any point falling at the last node is taken to be % inside the last cell in x or y. k=(indx==nx); indx(k)=indx(k)-1; k=(indy==ny); indy(k)=indy(k)-1; ind = indy + ny*(indx-1); % Do we have a mask to apply? if params.maskflag % if we do, then we need to ensure that every % cell with at least one data point also has at % least all of its corners unmasked. params.mask(ind) = 1; params.mask(ind+1) = 1; params.mask(ind+ny) = 1; params.mask(ind+ny+1) = 1; end % interpolation equations for each point tx = min(1,max(0,(x - xnodes(indx))./dx(indx))); ty = min(1,max(0,(y - ynodes(indy))./dy(indy))); % Future enhancement: add cubic interpolant switch params.interp case 'triangle' % linear interpolation inside each triangle k = (tx > ty); L = ones(n,1); L(k) = ny; t1 = min(tx,ty); t2 = max(tx,ty); A = sparse(repmat((1:n)',1,3),[ind,ind+ny+1,ind+L], ... [1-t2,t1,t2-t1],n,ngrid); case 'nearest' % nearest neighbor interpolation in a cell k = round(1-ty) + round(1-tx)*ny; A = sparse((1:n)',ind+k,ones(n,1),n,ngrid); case 'bilinear' % bilinear interpolation in a cell A = sparse(repmat((1:n)',1,4),[ind,ind+1,ind+ny,ind+ny+1], ... [(1-tx).*(1-ty), (1-tx).*ty, tx.*(1-ty), tx.*ty], ... n,ngrid); end rhs = z; % Build regularizer. Add del^4 regularizer one day. switch params.regularizer case 'springs' % zero "rest length" springs [i,j] = meshgrid(1:nx,1:(ny-1)); ind = j(:) + ny*(i(:)-1); m = nx*(ny-1); stiffness = 1./(dy/params.yscale); Areg = sparse(repmat((1:m)',1,2),[ind,ind+1], ... stiffness(j(:))*[-1 1],m,ngrid); [i,j] = meshgrid(1:(nx-1),1:ny); ind = j(:) + ny*(i(:)-1); m = (nx-1)*ny; stiffness = 1./(dx/params.xscale); Areg = [Areg;sparse(repmat((1:m)',1,2),[ind,ind+ny], ... stiffness(i(:))*[-1 1],m,ngrid)]; [i,j] = meshgrid(1:(nx-1),1:(ny-1)); ind = j(:) + ny*(i(:)-1); m = (nx-1)*(ny-1); stiffness = 1./sqrt((dx(i(:))/params.xscale).^2 + ... (dy(j(:))/params.yscale).^2); Areg = [Areg;sparse(repmat((1:m)',1,2),[ind,ind+ny+1], ... stiffness*[-1 1],m,ngrid)]; Areg = [Areg;sparse(repmat((1:m)',1,2),[ind+1,ind+ny], ... stiffness*[-1 1],m,ngrid)]; case {'diffusion' 'laplacian'} % thermal diffusion using Laplacian (del^2) [i,j] = meshgrid(1:nx,2:(ny-1)); ind = j(:) + ny*(i(:)-1); dy1 = dy(j(:)-1)/params.yscale; dy2 = dy(j(:))/params.yscale; Areg = sparse(repmat(ind,1,3),[ind-1,ind,ind+1], ... [-2./(dy1.*(dy1+dy2)), 2./(dy1.*dy2), ... -2./(dy2.*(dy1+dy2))],ngrid,ngrid); [i,j] = meshgrid(2:(nx-1),1:ny); ind = j(:) + ny*(i(:)-1); dx1 = dx(i(:)-1)/params.xscale; dx2 = dx(i(:))/params.xscale; Areg = Areg + sparse(repmat(ind,1,3),[ind-ny,ind,ind+ny], ... [-2./(dx1.*(dx1+dx2)), 2./(dx1.*dx2), ... -2./(dx2.*(dx1+dx2))],ngrid,ngrid); case 'gradient' % Subtly different from the Laplacian. A point for future % enhancement is to do it better for the triangle interpolation % case. [i,j] = meshgrid(1:nx,2:(ny-1)); ind = j(:) + ny*(i(:)-1); dy1 = dy(j(:)-1)/params.yscale; dy2 = dy(j(:))/params.yscale; Areg = sparse(repmat(ind,1,3),[ind-1,ind,ind+1], ... [-2./(dy1.*(dy1+dy2)), 2./(dy1.*dy2), ... -2./(dy2.*(dy1+dy2))],ngrid,ngrid); [i,j] = meshgrid(2:(nx-1),1:ny); ind = j(:) + ny*(i(:)-1); dx1 = dx(i(:)-1)/params.xscale; dx2 = dx(i(:))/params.xscale; Areg = [Areg;sparse(repmat(ind,1,3),[ind-ny,ind,ind+ny], ... [-2./(dx1.*(dx1+dx2)), 2./(dx1.*dx2), ... -2./(dx2.*(dx1+dx2))],ngrid,ngrid)]; end nreg = size(Areg,1); % Append the regularizer to the interpolation equations, % scaling the problem first. Use the 1-norm for speed. NA = norm(A,1); NR = norm(Areg,1); A = [A;Areg*(params.smoothness*NA/NR)]; rhs = [rhs;zeros(nreg,1)]; % do we have a mask to apply? if params.maskflag unmasked = find(params.mask); end % solve the full system, with regularizer attached switch params.solver case {'\' 'backslash'} if params.maskflag % there is a mask to use % permute for minimum fill in for R (in the QR) p = colamd(A(:,unmasked)); zgrid=nan(ny,nx); zgrid(unmasked(p)) = A(:,unmasked(p))\rhs; else % permute for minimum fill in for R (in the QR) p = colamd(A); zgrid=zeros(ny,nx); zgrid(p) = A(:,p)\rhs; end case 'normal' % The normal equations, solved with \. Can be fast % for huge numbers of data points. if params.maskflag % there is a mask to use % Permute for minimum fill-in for \ (in chol) APA = A(:,unmasked)'*A(:,unmasked); p = symamd(APA); zgrid=nan(ny,nx); zgrid(unmasked(p)) = APA(p,p)\(A(:,unmasked(p))'*rhs); else % Permute for minimum fill-in for \ (in chol) APA = A'*A; p = symamd(APA); zgrid=zeros(ny,nx); zgrid(p) = APA(p,p)\(A(:,p)'*rhs); end case 'symmlq' % iterative solver - symmlq - requires a symmetric matrix, % so use it to solve the normal equations. No preconditioner. tol = abs(max(z)-min(z))*1.e-13; if params.maskflag % there is a mask to use zgrid=nan(ny,nx); [zgrid(unmasked),flag] = symmlq(A(:,unmasked)'*A(:,unmasked), ... A(:,unmasked)'*rhs,tol,params.maxiter); else [zgrid,flag] = symmlq(A'*A,A'*rhs,tol,params.maxiter); zgrid = reshape(zgrid,ny,nx); end % display a warning if convergence problems switch flag case 0 % no problems with convergence case 1 % SYMMLQ iterated MAXIT times but did not converge. warning(['Symmlq performed ',num2str(params.maxiter), ... ' iterations but did not converge.']) case 3 % SYMMLQ stagnated, successive iterates were the same warning 'Symmlq stagnated without apparent convergence.' otherwise warning(['One of the scalar quantities calculated in',... ' symmlq was too small or too large to continue computing.']) end case 'lsqr' % iterative solver - lsqr. No preconditioner here. tol = abs(max(z)-min(z))*1.e-13; if params.maskflag % there is a mask to use zgrid=nan(ny,nx); [zgrid(unmasked),flag] = lsqr(A(:,unmasked),rhs,tol,params.maxiter); else [zgrid,flag] = lsqr(A,rhs,tol,params.maxiter); zgrid = reshape(zgrid,ny,nx); end % display a warning if convergence problems switch flag case 0 % no problems with convergence case 1 % lsqr iterated MAXIT times but did not converge. warning(['Lsqr performed ',num2str(params.maxiter), ... ' iterations but did not converge.']) case 3 % lsqr stagnated, successive iterates were the same warning 'Lsqr stagnated without apparent convergence.' case 4 warning(['One of the scalar quantities calculated in',... ' LSQR was too small or too large to continue computing.'])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -