diff --git a/ABfgPreEliminate.m b/ABfgPreEliminate.m index ac3effe0..090a87d1 100644 --- a/ABfgPreEliminate.m +++ b/ABfgPreEliminate.m @@ -1,96 +1,171 @@ -function [x,y,tolA,tolB]=ABfgPreEliminate(CtrlVar,A,B,f,g) - - - - [nA,mA]=size(A); - [nB,mB]=size(B); - [nf,mf]=size(f); - - if isempty(B) && isempty(g) && ~isempty(A) && ~isempty(f) && mA==nf - - % Possibly not needed, but check if this is not just a very simple case of B=g=[] - - x=A\f; - y=NaN; - - if nargout>2 - tolB=NaN; - tolA=norm(A*x-f)/norm(f); +function [x,y,dAtilde,tolA,tolB]=ABfgPreEliminate(CtrlVar,A,B,f,g,dAtilde) + + +narginchk(5,6) + +if nargin< 6 + dAtilde=[]; +end + +[nA,mA]=size(A); +[nB,mB]=size(B); +[nf,mf]=size(f); + + +if isempty(B) && isempty(g) && ~isempty(A) && ~isempty(f) && mA==nf + + % Possibly not needed, but check if this is not just a very simple case of B=g=[] + + x=A\f; + y=NaN; + + if nargout>3 + tolB=NaN; + tolA=norm(A*x-f)/norm(f); + end + +else + + BBT=B*B'; + + if isdiag(BBT) % the method assumes that B B' is diagonal + + + % It also assumes that B B' is a unity matrix, but if not then simple scaling can be used + % to ensure that this is the case. + % To make this a bit more general, I here check if B B' is indeed unity, and + % if not I do the requried scaling. + tolerance=eps*1000; + isBBTunity=all(abs(diag(BBT) - 1) < tolerance) ; + + if ~isBBTunity + [B,g,~,Scale]=ScaleL(CtrlVar,B,g) ; + else + Scale=1; end + + % For numerical reasons a further simple scaling of A is done to bring the + % sizes of the elements of A in line with those of B. + factor=1./(full(mean(abs(diag(A))))); + + if ~isfinite(factor) % just in case all elements along the diagonal happen to be equal to zero + factor=1; + end + + BtB=B'*B; + + A=factor*A ; f=factor*f ; % this leaves x unaffected but y is scaled + + + + Q=speye(nA,nA)-BtB ; + Atilde=Q*A+ BtB ; + btilde=(Q*f+B'*g) ; + + + if CtrlVar.Parallel.isTest + + % seq: + + % distribute + tSeq=tic ; + dAtildeSeq=decomposition(Atilde); % this might not be needed if this has been done already, but for speed comparison this is done here each time + xSeq=dAtildeSeq\btilde; + tSeq=toc(tSeq) ; + + + % distribute + tDistributed=tic ; + AtildeDist=distributed(Atilde); + btildeDist=distributed(btilde); + dAtildeDist=decomposition(AtildeDist); % this might not be needed if this has been done already, but for speed comparison this is done here each time + xDist=dAtildeDist\btildeDist; + tDistributed=toc(tDistributed) ; - else - - BBT=B*B'; - - if isdiag(BBT) % the method assumes that B B' is diagonal - - - % It also assumes that B B' is a unity matrix, but if not then simple scaling can be used - % to ensure that this is the case. - % To make this a bit more general, I here check if B B' is indeed unity, and - % if not I do the requried scaling. - tolerance=eps*1000; - isBBTunity=all(abs(diag(BBT) - 1) < tolerance) ; - - if ~isBBTunity - [B,g,~,Scale]=ScaleL(CtrlVar,B,g) ; - else - Scale=1; + [nAtilde,mAtilde]=size(Atilde); + fprintf('\n ----------------------------- Info on distributed solve performance : \n') + fprintf('%i x %i : tSeq=%f \t tDistributed=%f \t tSeq/rDistributed=%f \n',nAtilde,mAtilde,tSeq,tDistributed,tSeq/tDistributed) ; + fprintf(' norm(xSeq-xDist)/norm(xSeq)=%g \n',full(norm(xSeq-xDist)/norm(xSeq))) + fprintf(' ----------------------------- \n') + + + end + + + % https://uk.mathworks.com/help/parallel-computing/benchmarking-a-b.html + if CtrlVar.Parallel.Distribute + if ~isdistributed(Atilde) + Atilde=distributed(Atilde); end - - % For numerical reasons a further simple scaling of A is done to bring the - % sizes of the elements of A in line with those of B. - factor=1./(full(mean(abs(diag(A))))); - - if ~isfinite(factor) % just in case all elements along the diagonal happen to be equal to zero - factor=1; + if ~isdistributed(btilde) + btilde=distributed(btilde); end - - BtB=B'*B; - - A=factor*A ; f=factor*f ; % this leaves x unaffected but y is scaled - - - - Q=speye(nA,nA)-BtB ; - Atilde=Q*A+ BtB ; - btilde=(Q*f+B'*g) ; - - - %dAtilde=factorize(Atilde); % for some reason, this does make things slower - - x=Atilde\btilde; - y=B*(f-A*x); - - % Now the solution of the scaled system has been found. - - y=y/factor; - - if nargout>2 - % check if within tolerances - - A=A/factor ; - f=f/factor ; - tolA=norm(A*x+B'*y-f)/norm(f); - tolB=norm(B*x-g); - - if tolA>1e-6 || tolB>1e-6 - - fprintf('ABfgPreEliminate: Error seems too large or \t \t \t %g \t %g \n ',norm(A*x+B'*y-f)/norm(f),norm(B*x-g)) - - end + end + + % decomposition is about the same, and as expected this only speeds things up if several solves with the same matrix + % are needed. + % + tDecomposition=tic; + if isempty(dAtilde) + dAtilde=decomposition(Atilde); + end + tDecomposition=toc(tDecomposition) ; + + tSolve=tic; + x=dAtilde\btilde; + tSolve=toc(tSolve); + + % tSolve=tic; + % x=Atilde\btilde; + % tSolve=toc(tSolve); + + % [tDecomposition tSolve] + + if isdistributed(x) + x=gather(x) ; + end + % toc + + + + + + + + + + + y=B*(f-A*x); + + % Now the solution of the scaled system has been found. + + y=y/factor; + + if nargout>3 + % check if within tolerances + + A=A/factor ; + f=f/factor ; + tolA=norm(A*x+B'*y-f)/norm(f); + tolB=norm(B*x-g); + + if tolA>1e-6 || tolB>1e-6 + + fprintf('ABfgPreEliminate: Error seems too large or \t \t \t %g \t %g \n ',norm(A*x+B'*y-f)/norm(f),norm(B*x-g)) + end - - y=Scale*y; % and now scale y in case B and g were scaled above. - - else - - - error('ABfgPreEliminate:B','B*B^T not diagonal') end - + + y=Scale*y; % and now scale y in case B and g were scaled above. + + else + + + error('ABfgPreEliminate:B','B*B^T not diagonal') end - + +end + end diff --git a/ABfgPreEliminateIterative.m b/ABfgPreEliminateIterative.m index bd9b707b..cc49055b 100755 --- a/ABfgPreEliminateIterative.m +++ b/ABfgPreEliminateIterative.m @@ -1,4 +1,10 @@ -function [x,y,tolA,tolB,L,U,perm]=ABfgPreEliminateIterative(CtrlVar,A,B,f,g,x0,y0,L,U,perm) + + + + + + +function [x,y,tolA,tolB,L,U,P,perm,xtilde]=ABfgPreEliminateIterative(CtrlVar,A,B,f,g,x0,y0,L,U,P,perm,xtilde0) %% % @@ -6,6 +12,15 @@ % % +nargoutchk(9,9) +narginchk(12,12) + +persistent iFigure + +if isempty(iFigure) + iFigure=100; +end + if nargin < 8 L=[]; U=[]; @@ -26,11 +41,25 @@ x0=f*0; end +if isempty(xtilde0) + xtilde=f*0; +end + + + + -setup.type = 'nofill'; setup.milu = 'off'; -setup.type = "ilutp"; setup.milu = "off"; setup.droptol = 1e-6; setup.udiag=0 ; isReorder=true; % must be used with re-ordering +% ilutp results in much smaller residuals at fewer iterations, but ilu takes long time -tol=1e-13 ; maxit=2; restart=10; % quick for testing purposes +setup.type = "nofill"; setup.milu = "off"; +tol=1e-13 ; maxit=5; restart=50; % quick for testing purposes + +% takes forever +% setup.type = "crout"; setup.milu = "off"; setup.droptol = 1e-6 ; +% tol=1e-13 ; maxit=5; restart=5; % quick for testing purposes + +setup.type = "ilutp"; setup.milu = "off"; setup.droptol = 1e-6; setup.udiag=0 ; +tol=1e-13 ; maxit=2; restart=50; % quick for testing purposes if isempty(B) && isempty(g) && ~isempty(A) && ~isempty(f) && mA==nf @@ -52,6 +81,8 @@ if isdiag(BBT) % the method assumes that B B' is diagonal + tCPUtotal=tic; + % It also assumes that B B' is a unity matrix, but if not then simple scaling can be used % to ensure that this is the case. % To make this a bit more general, I here check if B B' is indeed unity, and @@ -84,8 +115,13 @@ tdissectAtilde=tic; - if isempty(perm) - perm=dissect(Atilde); % does not work for disstributed or gpuarrays + if isempty(perm) % If the matrix has the same sparsity structure, then I don't need to do the permutation again + perm=dissect(Atilde); % does not work for distributed or gpuarrays + + % The nested dissection algorithm produces high quality reordering and performs particularly well with finite element + % matrices compared to other reordering techniques. For more information about the nested dissection ordering + % algorithm, see https://uk.mathworks.com/help/matlab/math/sparse-matrix-operations.html + end % pAtilde=symrcm(Atilde); % ilu appears to take longer as compared to using dissect tdissectAtilde=toc(tdissectAtilde); @@ -94,49 +130,88 @@ Atilde=Atilde(perm,perm) ; btilde=btilde(perm); x0=x0(perm) ; + % If I return xtilde and the re-use the same ordering (i.e. perm) then I can take the previous xtilde as a starting point, + % and I don't need to re-order that initial guess. + % can't use setup.type = "ilutp" with distributed arrays + % but even for setup.type = "ilutp"; setup.milu = "off"; setup.droptol = 1e-6; setup.udiag=0 ; + % using distributed arrays is slower... tluinc=tic; if isempty(L) - [L,U] = ilu(Atilde,setup); + [L,U,P] = ilu(Atilde,setup); end tluinc=toc(tluinc); + if setup.type == "ilutp" + Atilde=P*Atilde ; btilde=P*btilde; + end + + %fprintf("norm(Atilde-L*U)/norm(Atilde)=%g \n",norm(Atilde-L*U,"fro")/norm(Atilde,"fro")) - %[sol,flag,relres,iter,resvec]=bicgstabl(AA,ff,tol,maxit,L1,U1,xx0); + % [sol,flag,relres,iter,resvec]=bicgstabl(Atilde,btilde,tol,maxit,L,U,xtilde0); tgmres=tic; + [xtilde,flag,relres,iter,resvec]=gmres(Atilde,btilde,restart,tol,maxit,L,U,xtilde0); + + x=xtilde(iperm) ; + tgmres=toc(tgmres); + % Important to replace zeros on diagonal, but does not converge well, much worse that using ilu + % k = 3; + % M = tril(triu(Atilde,-k),k); + % I=find(abs(diag(M))==0 ); % must make sure to replace 0 on the diagonal with 1 + % [n,m]=size(Atilde) ; + % M=M+sparse(I,I,1,n,m); + % [xtilde,flag,relres,iter,resvec]=gmres(Atilde,btilde,restart,tol,maxit,M); + % - tic - [x,flag,relres,iter,resvec]=gmres(Atilde,btilde,restart,tol,maxit,L,U,x0); - - toc + % % Not particularly fast, and less good convergence, possibly because not possible to provide L and U separately + % fprintf(" GPU \n ") + % tic + % AtildeGPU=gpuArray(Atilde) ; M=L*U ; MGPU=gpuArray(M) ; btildeGPU=gpuArray(btilde) ; + % toc + % + % tic + % [xGPU,flag,relresGPU,iter,resvecGPU]=gmres(AtildeGPU,btildeGPU,restart,tol,maxit,MGPU,[],xtilde0); + % toc + % % -% tic -% AtildeGPU=gpuArray(Atilde) ; M=L*U ; MGPU=gpuArray(M) ; btildeGPU=gpuArray(btilde) ; -% toc -% -% tic -% [xGPU,flag,relresGPU,iter,resvecGPU]=gmres(AtildeGPU,btildeGPU,restart,tol,maxit,MGPU,[],x0); -% toc - x=x(iperm) ; - tgmres=toc(tgmres); + + % For some reason, very slow + % tic + % AtildeDist=distributed(Atilde) ; Ldist=distributed(L) ; Udist=distributed(U) ; x0dist=distributed(x0) ; + % [x,flag,relres,iter,resvec]=gmres(AtildeDist,btilde,restart,tol,maxit,Ldist,Udist,x0dist); + % toc + + + % fprintf(" spmd \n ") + % For some reason, very slow + % tic + % % AtildeDist=distributed(Atilde) ; Ldist=distributed(L) ; Udist=distributed(U) ; x0dist=distributed(x0) ; + % spmd + % AtildeDist=codistributed(Atilde); + % [x,flag,relres,iter,resvec]=gmres(AtildeDist,btilde,restart,tol,maxit,L,U,x0); + % end + % toc + + + tCPUtotal=toc(tCPUtotal) ; if CtrlVar.InfoLevelLinSolve>=10 - fprintf(" dissect Atilde %f sec\n",tdissectAtilde) - fprintf(" ilu %f sec\n",tluinc) - fprintf(" gmres %f sec\n",tgmres) - fprintf("total time for nonEq with is about %f",tdissectAtilde+tluinc+tgmres) + fprintf(" dissect Atilde %f sec\n",tdissectAtilde) + fprintf(" ilu %f sec\n",tluinc) + fprintf(" gmres %f sec\n",tgmres) + fprintf("total time for iterative solution %f sec\n",tCPUtotal) - figure - fprintf("\n\n") - fprintf(' flag=%-i, iter=%-i %-i, relres=%-g \n ',flag,iter(1),iter(2),relres) + figure(iFigure) ; iFigure=iFigure+100; + + fprintf('\n flag=%-i, iter=%-i %-i, relres=%-g \n ',flag,iter(1),iter(2),relres) nnn=numel(resvec); semilogy(0:nnn-1,resvec,'-o',LineWidth=2) diff --git a/ABfgPreEliminateIterativeMethodComparision.m b/ABfgPreEliminateIterativeMethodComparision.m index 8cbb2676..74523ec0 100755 --- a/ABfgPreEliminateIterativeMethodComparision.m +++ b/ABfgPreEliminateIterativeMethodComparision.m @@ -1,4 +1,9 @@ -function [x,y,tolA,tolB,Peq,Req,Ceq]=ABfgPreEliminateIterative(CtrlVar,A,B,f,g,x0,y0,Peq,Req,Ceq) + + + + + +function [x,y,tolA,tolB,Peq,Req,Ceq,L1,U1,L1eq,U1eq]=ABfgPreEliminateIterativeMethodComparision(CtrlVar,A,B,f,g,x0,y0,Peq,Req,Ceq,L1,U1,L1eq,U1eq) %% This is a test run % @@ -11,6 +16,10 @@ Peq=[]; Req=[]; Ceq=[]; + L1=[]; + U1=[]; + L1eq=[]; + U1eq=[]; end if nargin<6 @@ -23,6 +32,18 @@ [nB,mB]=size(B); [nf,mf]=size(f); + +if ~isempty(x0) && ~isempty(y0) + + tolA=norm(A*x0+B'*y0-f)/norm(f); + tolB=norm(B*x0-g); + fprintf(" Initial normed residuals are: \n") + fprintf(" norm(A*x+B'*y-f)/norm(f) = %g \n",tolA) + fprintf(" norm(B*x-g)= %g \n",tolB) + +end + + if isempty(B) && isempty(g) && ~isempty(A) && ~isempty(f) && mA==nf % Possibly not needed, but check if this is not just a very simple case of B=g=[] @@ -45,7 +66,7 @@ % It also assumes that B B' is a unity matrix, but if not then simple scaling can be used % to ensure that this is the case. % To make this a bit more general, I here check if B B' is indeed unity, and - % if not I do the requried scaling. + % if not I do the required scaling. tolerance=eps*1000; isBBTunity=all(abs(diag(BBT) - 1) < tolerance) ; @@ -76,12 +97,12 @@ teq=tic; % c1 = condest(Atilde) - %% Equilibriate (this seems to take suprisingly long time, better to save locally when testing using same matrix) + %% Equilibriate (this seems to take surprisingly long time, better to save locally when testing using same matrix) if isempty(Peq) [Peq,Req,Ceq] = equilibrate(Atilde); end - Beq = Req*Peq*Atilde*Ceq; - deq = Req*Peq*btilde; + AtildeEquilibrated = Req*Peq*Atilde*Ceq; + btildeEquilibrated = Req*Peq*btilde; teq=toc(teq) ; @@ -91,7 +112,7 @@ setup.type = 'nofill'; setup.milu = 'off'; isReorder=false; - setup.type = "ilutp"; setup.milu = "off"; setup.droptol = 1e-6; setup.udiag=0 ; isReorder=true; % must be used with re-ordering + setup.type = "ilutp"; setup.milu = "off"; setup.droptol = 1e-8; setup.udiag=0 ; isReorder=true; % must be used with re-ordering @@ -103,18 +124,18 @@ tdissectAtilde=toc(tdissectAtilde); tdissectBeq=tic; - pBeq=dissect(Beq); + pAtildeEquilibrated=dissect(AtildeEquilibrated); % pBeq=symrcm(Beq); tdissectBeq=toc(tdissectBeq); invpAtilde(pAtilde)=1:length(pAtilde); % inverse of the permutation vector - invpBeq(pBeq)=1:length(pBeq); % inverse of the permutation vector + invpBeq(pAtildeEquilibrated)=1:length(pAtildeEquilibrated); % inverse of the permutation vector Atilde=Atilde(pAtilde,pAtilde) ; btilde=btilde(pAtilde); - Beq=Beq(pBeq,pBeq) ; - deq=deq(pBeq); + AtildeEquilibrated=AtildeEquilibrated(pAtildeEquilibrated,pAtildeEquilibrated) ; + btildeEquilibrated=btildeEquilibrated(pAtildeEquilibrated); else tdissectAtilde=0; @@ -123,17 +144,21 @@ end tluincEq=tic; - [L1eq,U1eq] = ilu(Beq,setup); + if isempty(L1eq) + [L1eq,U1eq] = ilu(AtildeEquilibrated,setup); + end tluincEq=toc(tluincEq); tluinc=tic; - [L1,U1] = ilu(Atilde,setup); + if isempty(L1) + [L1,U1] = ilu(Atilde,setup); + end tluinc=toc(tluinc); tol=1e-15 ; maxit=1; restart=300; - tol=1e-15 ; maxit=30; restart=1; % quick for testing purposes + tol=1e-15 ; restart=10; maxit=floor(15/restart) ; % quick for testing purposes @@ -143,6 +168,7 @@ x0=f*0; end + % gmres without preconditioners tgmres=tic; [x,flag,relres,iter,resvec]=gmres(Atilde,btilde,restart,tol,maxit,[],[],x0); @@ -152,6 +178,7 @@ tgmres=toc(tgmres); + % gmres with il0 preconditioners tgmresPre=tic; [xPre,flagPre,relresPre,iterPre,resvecPre]=gmres(Atilde,btilde,restart,tol,maxit,L1,U1,x0); if isReorder @@ -159,17 +186,19 @@ end tgmresPre=toc(tgmresPre); + % gmres, equilibrated matrix but no preconditioner xEq0=f*0; tgmresEq=tic; - [xeq,flagEq,relresEq,iterEq,resvecEq]=gmres(Beq,deq,restart,tol,maxit,[],[],xEq0); + [xeq,flagEq,relresEq,iterEq,resvecEq]=gmres(AtildeEquilibrated,btildeEquilibrated,restart,tol,maxit,[],[],xEq0); if isReorder xeq=xeq(invpBeq) ; end xeq=Ceq*xeq; tgmresEq=toc(tgmresEq); + % gmres, equilibrated matrix with preconditioners tgmresEqPre=tic; - [xeqPre,flagEqPre,relresEqPre,iterEqPre,resvecEqPre]=gmres(Beq,deq,restart,tol,maxit,L1eq,U1eq,xEq0); + [xeqPre,flagEqPre,relresEqPre,iterEqPre,resvecEqPre]=gmres(AtildeEquilibrated,btildeEquilibrated,restart,tol,maxit,L1eq,U1eq,xEq0); if isReorder xeqPre=xeqPre(invpBeq) ; end @@ -183,6 +212,8 @@ sol{4}=xeqPre; text(4)="xeqPre" ; + + if CtrlVar.InfoLevelLinSolve>=1 @@ -233,36 +264,53 @@ fprintf("\n\n") - for I=1:4 + TolAmin=inf; + isScaled=true; + for I=1:4 % now plug the four solutions into the system and estimate norm of residuals - x=sol{I} ; + xx=sol{I} ; % x=Atilde\btilde; - y=B*(f-A*x); - % Now the solution of the scaled system has been found. - - y=y/factor; - - - if nargout>2 - % check if within tolerances + if isScaled A=A/factor ; f=f/factor ; - tolA=norm(A*x+B'*y-f)/norm(f); - tolB=norm(B*x-g); + B=B/Scale; + g=g/Scale; + isScaled=false; + + end + + + % yy=B*(f-A*xx); % B' yy= (f-A*xx); but since B B'= 1 this is correct, but then must use the scaled B here + + yy= ( B*B') \ (B*(f-A*xx)) ; - % if tolA>1e-6 || tolB>1e-6 + tolA=norm(A*xx+B'*yy-f)/norm(f); + tolB=norm(B*xx-g); - fprintf('\t %s \t %g \t %g \n ',text(I),tolA,tolB) - % + % if tolA>1e-6 || tolB>1e-6 + + fprintf('\t %s \t %g \t %g \n ',text(I),tolA,tolB) + % + + % Select the solution with the lowers tolerance as the one returned + + % yy=Scale*yy; % and now scale y in case B and g were scaled above. + + if tolA < TolAmin + x=xx; + y=yy; + TolAmin=tolA; end + + end - y=Scale*y; % and now scale y in case B and g were scaled above. + diff --git a/AGlenVersusTemp.m b/AGlenVersusTemp.m index 8a2b86c8..88f6d55b 100755 --- a/AGlenVersusTemp.m +++ b/AGlenVersusTemp.m @@ -1,26 +1,40 @@ function [AGlen,B]=AGlenVersusTemp(T) - % Gives A as a function of temperature (degrees Celcius) in the units a^{-1} kPa^{-3} - - T=T+273.15; - - % a0= 5.3d-15 % s-1 kPa-3 - % a0= 5.3d-24 % s-1 Pa-3 = m+3 s+5 kg-3 - a0 = 5.3e-15*365.2422*24.*60.*60. ; % a-1 kPa-3 - % a0= 1.699d-61 ! m+3 a+5 kg-3 - - % dimentionless temperature factor - fa=1.2478766e-39 * exp(0.32769 * T) + 1.9463011e-10 * exp(0.07205 * T) ; %; %Smith & Morland 1982 , Keine Einheiten; fa(273.15)=1.0 - - AGlen=a0 * fa ; % - - rhog=917*9.81/1000 ; % kPa/m - B=0.5*AGlen*(rhog)^3 ; % m^{-3} a^{-1} +%% +% Gives A as a function of temperature (degrees Celsius) in the units a^{-1} kPa^{-3} +% +% $$\dot{\epsilon}=A \tau^m$$ +% +% +% Example: +% +% AGlen=AGlenVersusTemp(0) ; % Gives A in Glen's flow law for n=3 and T=0 degrees Celsius in the units kPa^{-3} yr^{-1} +% +% Based on Smith & Morland, 1982 +% +%% + + +T=T+273.15; + +% a0= 5.3d-15 ; % s-1 kPa-3 +% a0= 5.3d-24 ; % s-1 Pa-3 = m+3 s+5 kg-3 +a0 = 5.3e-15*365.2422*24.*60.*60. ; % a-1 kPa-3 +% a0= 1.699d-61 ; % m+3 a+5 kg-3 +% dimensionless temperature factor +fa=1.2478766e-39 * exp(0.32769 * T) + 1.9463011e-10 * exp(0.07205 * T) ; %; %Smith & Morland 1982 , no units, scaled such that: fa(273.15)=1.0 -% eta=10^15 Pa s = 10^13 kPa s = 10^13 /(365.25*24*60*60) kPa yr +AGlen=a0 * fa ; % + +if nargout>1 + rhog=917*9.81/1000 ; % kPa/m + B=0.5*AGlen*(rhog)^3 ; % m^{-3} a^{-1}, some publications use this definition +else + B=[]; +end end diff --git a/ActiveSetInitialisation.m b/ActiveSetInitialisation.m index 3f10af58..c04a36c6 100755 --- a/ActiveSetInitialisation.m +++ b/ActiveSetInitialisation.m @@ -2,11 +2,21 @@ -function [UserVar,RunInfo,F1,l1,BCs1,isActiveSetModified,Activated,Released]=ActiveSetInitialisation(UserVar,RunInfo,CtrlVar,MUA,F0,F1,l0,l1,BCs1) +function [UserVar,RunInfo,F1,l1,BCs1,isActiveSetModified,Activated,DeActivated]=ActiveSetInitialisation(UserVar,RunInfo,CtrlVar,MUA,F0,F1,l0,l1,BCs1) - BCs1Input=BCs1 ; +BCs1Input=BCs1 ; + + + +%% Make sure that no thickness constraints have been added to nodes with user-defined boundary conditions +% or because the user-defined boundary conditions have changed the last active set was updated/created. + +BCs1.hPosNode=setdiff(BCs1.hPosNode,BCs1.hFixedNode) ; + + +%% LastActiveSet=BCs1.hPosNode; @@ -14,12 +24,12 @@ fprintf(CtrlVar.fidlog,' Enforcing min thickness of %-g using active-set method \n',CtrlVar.ThickMin); end -%% Special case: Check if all thicknesses are positive, in which case all thickness constraints should be deactiated +%% Special case: Check if all thicknesses are positive, in which case all thickness constraints should be deactivated if min(F1.h) > 1.1*CtrlVar.ThickMin if CtrlVar.ThicknessConstraintsInfoLevel>=10 fprintf(CtrlVar.fidlog,' Eliminating any possible previous thickness constraints as min(h1)=%-g>1.1*CtrlVar.ThickMin=%-g \n',min(F0.h),CtrlVar.ThickMin); end - BCs1.hPosNode=[] ; BCs1.hPosValue=[]; + BCs1.hPosNode=[] ; end %% Special case: Check if there are no previous thickness constraints, in which case new should be introduced based on ice thickness @@ -29,10 +39,14 @@ %!if isempty(Lhpos) if isempty(BCs1.hPosNode) - Active=find(F1.h<=CtrlVar.ThickMin); - BCs1.hPosNode=Active ; BCs1.hPosValue=BCs1.hPosNode*0+CtrlVar.ThickMin; - % F1.ub(BCs1.hPosNode)=0 ; F1.vb(BCs1.hPosNode)=0; - F1.h(BCs1.hPosNode)=CtrlVar.ThickMin; % + Active=find(F1.h<=CtrlVar.ThickMin); % Although I might only want to add nodes to the active set if thickness is somewhat less than MinThick, I might here + % have a situation where this is a restart run where the active set has been set to empty, or a run after re-meshing, and I + % want the initial active sets to be similar to previous active set. + % + Active=setdiff(Active,BCs1.hFixedNode) ; % do not add active thickness constraints for nodes that already are included in the user-defined thickness boundary conditions, + % even if this means that thicknesses at those nodes are less then MinThick + BCs1.hPosNode=Active ; + if numel(BCs1.hPosNode)>0 if CtrlVar.ThicknessConstraintsInfoLevel>=1 fprintf(CtrlVar.fidlog,' Introducing %-i new initial active constraints based on h0 \n', numel(BCs1.hPosNode)); @@ -41,9 +55,9 @@ end -II= (F0.h<=CtrlVar.ThickMin) | (F1.h<=CtrlVar.ThickMin) ; - -F1.h(II)=CtrlVar.ThickMin; F1.ub(II)=F0.ub(II) ; F1.vb(II)=F0.vb(II) ; % modify initial guess for h1, POSSIBLY important for convergence +% II= (F0.h<=CtrlVar.ThickMin) | (F1.h<=CtrlVar.ThickMin) ; +% F1.h(II)=CtrlVar.ThickMin; F1.ub(II)=F0.ub(II) ; F1.vb(II)=F0.vb(II) ; % modify initial guess for h1, POSSIBLY important for convergence + % this is now done as ahead of uvh solve as iterate is made feasible % However, I concluded (17 Dec, 2018) that it was better not to do this, as this can significantly increase the number of NR iterations. % Better to do this only if the iteration does not converge. @@ -71,16 +85,16 @@ end BCs1.hPosNode=union(BCs1.hPosNode,LSFhPosNode); - BCs1.hPosValue=BCs1.hPosNode*0+CtrlVar.ThickMin; + end - -Released=setdiff(LastActiveSet,BCs1.hPosNode) ; % nodes in last active set that are no longer in the new one +% I think the way LastActiveSet is initialized, both Released will always be empty by construction +DeActivated=setdiff(LastActiveSet,BCs1.hPosNode) ; % nodes in last active set that are no longer in the new one Activated=setdiff(BCs1.hPosNode,LastActiveSet) ; % nodes in new active set that were not in the previous one -nReleased=numel(Released); +nReleased=numel(DeActivated); nActivated=numel(Activated); %% @@ -94,7 +108,7 @@ BCs1=BCs1Input; Activated=[]; - Released=[]; + DeActivated=[]; nReleased=0; nActivated=0; end @@ -112,7 +126,9 @@ - +%% Set the hPosValues, only need to do this once at the end +BCs1.hPosValue=BCs1.hPosNode*0+CtrlVar.ThickMin; +%% diff --git a/ActiveSetUpdate.m b/ActiveSetUpdate.m index 5f6577ff..9edee1be 100755 --- a/ActiveSetUpdate.m +++ b/ActiveSetUpdate.m @@ -2,7 +2,7 @@ -function [UserVar,RunInfo,BCs1,lambdahpos,isActiveSetModified,isActiveSetCyclical,Activated,Released]=ActiveSetUpdate(UserVar,RunInfo,CtrlVar,MUA,F1,l1,BCs1,iActiveSetIteration,LastReleased,LastActivated) +function [UserVar,RunInfo,BCs1,lambdahpos,isActiveSetModified,isActiveSetCyclical,Activated,DeActivated]=ActiveSetUpdate(UserVar,RunInfo,CtrlVar,MUA,F1,l1,BCs1,iActiveSetIteration,LastReleased,LastActivated) narginchk(10,10) @@ -21,7 +21,7 @@ % Thickness constraints used -% NodesFixed: holdes the nodal numbers nodes in the active set +% NodesFixed: holds the nodal numbers nodes in the active set % ihactive: number nodes in active set % % -If min thickness is significantly greater than CtrlVar.ThickMin, eliminate all thickness constraints @@ -46,10 +46,11 @@ -%% - +%% Make sure that no thickness constraints have been added to nodes with user-defined boundary conditions +BCs1.hPosNode=setdiff(BCs1.hPosNode,BCs1.hFixedNode) ; +%% if CtrlVar.ThicknessConstraintsInfoLevel>=1 if numel(BCs1.hPosNode)>0 || CtrlVar.ThicknessConstraintsInfoLevel>=10 @@ -61,7 +62,7 @@ % keep a copy of the old active set LastActiveSet=BCs1.hPosNode; -%must now find the lambda values corresponding to nodes that where constrainted to pos thickness +%must now find the lambda values corresponding to nodes that where constrained to positive thickness % hLambda=l1.h; % lambdahpos=hLambda(numel(BCs1.hFixedNode)+numel(BCs1.hTiedNodeA)+1:end) ;% I always put the hPos constraints at end of all other h constraints @@ -72,16 +73,19 @@ % remember lambdahpos=hLambda(numel(BCs1.hFixedNode)+numel(BCs1.hTiedNodeA)+1:end) % actually most likely only need to do this if numel(hPosNode)>0 % If the L matrix was not in the FE basis, I simply calculate the reactions. -% The Reactions are calculated correctly irrespectivly of how the +% The Reactions are calculated correctly irrespective of how the % if ~CtrlVar.LinFEbasis if numel(BCs1.hPosNode) >0 Reactions=CalculateReactions(CtrlVar,MUA,BCs1,l1); + ah=-Reactions.h./(F1.rho.*F1.dt) ; + ah=ah(BCs1.hPosNode); lambdahpos=Reactions.h(BCs1.hPosNode); else lambdahpos=[]; + ah=[]; end end %% @@ -96,10 +100,17 @@ if CtrlVar.ThicknessConstraintsInfoLevel>=10 [~,I]=sort(lambdahpos); % print out fixed nodes in the order of increasing lambda values - fprintf(CtrlVar.fidlog,' Nodes fixed: ') ; + fprintf(CtrlVar.fidlog,' Pos. thick. contraints: ') ; fprintf(CtrlVar.fidlog,' \t %9i \t %9i \t %9i \t %9i \t %9i \t %9i \t %9i \t %9i \t %9i \t %9i \n \t \t \t \t \t \t',BCs1.hPosNode(I)); fprintf(CtrlVar.fidlog,'\n Lagrange multipliers: ') ; - fprintf(CtrlVar.fidlog,' \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \n \t \t \t \t \t \t',lambdahpos(I)) ; + fprintf(CtrlVar.fidlog,' \t %+9.0g \t %+9.0g \t %+9.0g \t %+9.0g \t %+9.0g \t %+9.0g \t %+9.0g \t %+9.0g \t %+9.0f \t %+9.0f \n \t \t \t \t \t \t',lambdahpos(I)) ; + + + fprintf(CtrlVar.fidlog,'\n mass flux: ') ; + + fprintf(CtrlVar.fidlog,' \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \t %+9.0f \n \t \t \t \t \t \t',ah(I)) ; + + fprintf(CtrlVar.fidlog,'\n'); end @@ -109,7 +120,7 @@ % Now I've solved for h1 and if needed a new active set must be defined % % The new active set contains all nodes where h1 less than hmin that were not in the previous active set -% Those of the nodes in the previous active set with positve slack values +% Those of the nodes in the previous active set with positive slack values % Nodes in the previous set with negative slack values must be taken out of the set % if the active-set method is selected, update active set % The active set is created/modified and the problem solved again if the active set has changed @@ -120,14 +131,26 @@ if numel(BCs1.hPosNode)>0 % are there any thickness constraints? If so see if some should be in-activated - % I divide here with rho for this to have the same units as the mass balance + % I divide here with rho and dt for this to have the same units as the mass balance % (distance/time) - I=lambdahpos>CtrlVar.ThicknessConstraintsLambdaPosThreshold./F1.rho(BCs1.hPosNode); % if any of the Lagrange multipliers `lambdahpos' are positive, then these should be in-activated - NewInActiveConstraints=find(I); + % + % isNegavtiveMassFluxSmall=lambdahpos>CtrlVar.ThicknessConstraintsLambdaPosThreshold./(F1.rho(BCs1.hPosNode).*F1.dt); % if any of the Lagrange multipliers `lambdahpos' are positive, then these should be in-activated + + % Clearly only inactivate if the mass flux needed to keep them active (ah) is negative. + % But to also consider only inactivate if the negative flux is + % + % ah < 0.01 hMin /dt + % + % that is, if one were to stop subtracting this mass balance, then the thickness would increase to 0.01 above the minimum + % thickness value over a time interval corresponding to one time unit. + + isNegavtiveMassFluxSmall=ah < -0.001*CtrlVar.ThickMin/F1.dt ; + + NewInActiveConstraints=find(isNegavtiveMassFluxSmall); iNewInActiveConstraints=numel(NewInActiveConstraints); if iNewInActiveConstraints>0 % have any become inactive? - BCs1.hPosNode(I)=[]; BCs1.hPosValue(I)=[]; - + BCs1.hPosNode(isNegavtiveMassFluxSmall)=[]; + end else @@ -139,11 +162,13 @@ % Do I need to activate some new thickness constraints? %I=h1<=CtrlVar.ThickMin; % if thickness is less than ThickMin then further new thickness constraints must be introduced -I=F1.h<=(CtrlVar.ThickMin-100*eps); % if thickness is less than ThickMin then further new thickness constraints must be introduced +I=F1.h=1 fprintf(CtrlVar.fidlog,' %i new active constraints \n',iNewActiveConstraints); end - - BCs1.hPosNode=[BCs1.hPosNode;NewActive] ; BCs1.hPosValue=BCs1.hPosNode*0+CtrlVar.ThickMin; + + BCs1.hPosNode=[BCs1.hPosNode;NewActive] ; end @@ -173,49 +198,32 @@ if CtrlVar.LevelSetMethod && CtrlVar.LevelSetMethodThicknessConstraints - if isempty(F1.LSFMask) % + if isempty(F1.LSFMask) % F1.LSFMask=CalcMeshMask(CtrlVar,MUA,F1.LSF,0); end LSFhPosNode=find(F1.LSFMask.NodesOut); - LSFhAdditionalPosNodes=setdiff(LSFhPosNode,BCs1.hPosNode) ; + LSFhAdditionalPosNodes=setdiff(LSFhPosNode,BCs1.hPosNode) ; - if CtrlVar.ThicknessConstraintsInfoLevel>=1 + if CtrlVar.ThicknessConstraintsInfoLevel>=1 fprintf(' %i additional LSF active constraints \n',numel(LSFhAdditionalPosNodes)) end - BCs1.hPosNode=union(BCs1.hPosNode,LSFhPosNode); - BCs1.hPosValue=BCs1.hPosNode*0+CtrlVar.ThickMin; + BCs1.hPosNode=union(BCs1.hPosNode,LSFhPosNode); + end -Released=setdiff(LastActiveSet,BCs1.hPosNode) ; % nodes in last active set that are no longer in the new one +% LastActiveSet is simply a copy of hPosNode at the beginning of the call +DeActivated=setdiff(LastActiveSet,BCs1.hPosNode) ; % nodes in last active set that are no longer in the new one Activated=setdiff(BCs1.hPosNode,LastActiveSet) ; % nodes in new active set that were not in the previous one -nReleased=numel(Released); +nReleased=numel(DeActivated); nActivated=numel(Activated); -% modify initial guess for h1, important for convergence -%h1(NewActive)=ThickMin; - - -% %% print information on new active set -% if CtrlVar.ThicknessConstraintsInfoLevel>=1 -% if iNewInActiveConstraints> 0 || iNewActiveConstraints> 0 -% fprintf(CtrlVar.fidlog,' Updating pos. thickness constraints: in-activated: %-i, activated: %-i, total number of thickness constrains: %-i \n',... -% iNewInActiveConstraints,iNewActiveConstraints,numel(BCs1.hPosNode)); -% fprintf(CtrlVar.fidlog,' Nodes inactivated: ') ; -% fprintf(CtrlVar.fidlog,' \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \n \t \t \t \t \t',NodesReleased); -% -% fprintf(CtrlVar.fidlog,'\n Nodes activated: ') ; -% fprintf(CtrlVar.fidlog,' \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \n \t \t \t \t \t',NewActive); -% fprintf(CtrlVar.fidlog,'\n ') ; -% else -% fprintf(CtrlVar.fidlog,'No pos.-thickness constraints activated or deactivated. \n') ; -% end -% -% end +BCs1.hPosNodeDeActivated=DeActivated; % I'm not really using this at the moment, but in the future it might be best to use this to determine if set has become cyclical +BCs1.hPosNodeActivated=Activated; %% print information on new active set if CtrlVar.ThicknessConstraintsInfoLevel>=1 @@ -223,7 +231,7 @@ fprintf(CtrlVar.fidlog,'\n Updating pos. thickness constraints: in-activated: %-i, activated: %-i, total number of thickness constrains: %-i \n',... nReleased,nActivated,numel(BCs1.hPosNode)); fprintf(CtrlVar.fidlog,' Nodes inactivated: ') ; - fprintf(CtrlVar.fidlog,' \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \n \t \t \t \t \t',Released); + fprintf(CtrlVar.fidlog,' \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \n \t \t \t \t \t',DeActivated); fprintf(CtrlVar.fidlog,'\n Nodes activated: ') ; fprintf(CtrlVar.fidlog,' \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \t %7i \n \t \t \t \t \t',Activated); @@ -245,7 +253,7 @@ ActivatedAndPreviouslyReleasedDifference=setxor(Activated,LastReleased); % if empty then the sets of activated and previously de-activated nodes are identical -ReleasedAndPreviouslyActivatedDifference=setxor(Released,LastActivated); % if empty then the sets of de-activated and previously activated nodes are identical +ReleasedAndPreviouslyActivatedDifference=setxor(DeActivated,LastActivated); % if empty then the sets of de-activated and previously activated nodes are identical if CtrlVar.ThicknessConstraintsInfoLevel>=1 if ~isempty(LastReleased) @@ -262,24 +270,26 @@ end end -if isempty(ActivatedAndPreviouslyReleasedDifference) && isempty(ReleasedAndPreviouslyActivatedDifference) - isActiveSetCyclical=true ; - fprintf(' Active-set is cyclical. \n') +if ~(isempty(Activated) && isempty(DeActivated)) + if isempty(ActivatedAndPreviouslyReleasedDifference) && isempty(ReleasedAndPreviouslyActivatedDifference) + isActiveSetCyclical=true ; + fprintf(' Active-set is cyclical. \n') + end end % I now have a dilemma, since the set has become cyclical it is % clear that if I deactivate any new nodes the thickness at % those nodes will become too small in the next active-set -% interation. A solution is simply not to deactivate and to add +% interaction. A solution is simply not to deactivate and to add % the cyclically deactivated nodes to the active set. if isActiveSetCyclical - BCs1.hPosNode=[BCs1.hPosNode;Released] ; - BCs1.hPosValue=BCs1.hPosNode*0+CtrlVar.ThickMin; + BCs1.hPosNode=[BCs1.hPosNode;DeActivated] ; end - - +%% Set the hPosValues, only need to do this once at the end +BCs1.hPosValue=BCs1.hPosNode*0+CtrlVar.ThickMin; +%% if nReleased> 0 || nActivated>0 if nReleased= 0. +% +% +% if on input slop0 is empty, slope information is not used also if on input fa and/or fb are empty they are calculated using +% a=0 and b=1 the function F must return as a first argument the (scalar) value which is to be minimized if nOut is given +% then further nOut-1 outputs from F are collected in varargout and returned, (nOut is then the total number of output +% variables collected from F) the first input to F is the step variable gamma, varargin is then in addition given over to F +% +% F can be called several times. If the output from F are needed as input in a later call to F then that can be deal with by +% defining listInf and litOutF. When F is called additional nOut-1 outputs are collected, i.e. the total number of outputs +% collected from F in nOut These additional outputs are then given as additional inputs to F: % % % [fa,varargout{1:nOut-1}]=F(a,varargin{:}) ; @@ -25,16 +28,11 @@ % when extrapolating: c=gamma ; b is the previous extrapolation value % b < c=gamma , fb> fc=fgamma % -% -% % Example: -% % %% % -% -% -% c1=0 ; c2=0.5 ; c3=1.1 ; Func=@(x) -(x-c1).* (x-c2).*(x-c3) ; slope0=-(c1*c2+c1*c3+c2*c3); f0=Func(0) ; f1=Func(1) ; +% c1=0 ; c2=0.5 ; c3=1.1 ; Func=@(x) -(x-c1).* (x-c2).*(x-c3) +1 ; slope0=-(c1*c2+c1*c3+c2*c3); f0=Func(0) ; f1=Func(1) ; % % [gmin,fmin,BackTrackInfo]=BackTracking(slope0,1,f0,f1,Func); % @@ -42,8 +40,12 @@ % figure % plot(xvector,yvector) ; hold on % plot(gmin,fmin,'or') -% plot(BackTrackInfo.Infovector(:,1),BackTrackInfo.Infovector(:,2),'+b') -% +% plot(BackTrackInfo.Infovector(:,1),BackTrackInfo.Infovector(:,2),'*r') +% ylabel("$f(\gamma)$",Interpreter="latex") ; xlabel("$\gamma$",interpreter="latex") +% hold on ; g=linspace(0,1) ; Armijo=Func(0)+slope0*0.1*g; plot(g,am) +% plot([0 0.1],[Func(0) Func(0)+slope0*0.1],'k') +% legend("function","returned value","function evaluations","Armijo criterion","slope at zero") +% %% BackTrackInfo.Converged=0; BackTrackInfo.Direction=" " ; @@ -184,6 +186,7 @@ if Fargcollect [fa,varargout{1:nOut-1}]=Func(a,varargin{:}) ; + fa=full(fa); nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) @@ -191,6 +194,7 @@ end else fa=Func(a); + fa=full(fa); nFuncEval=nFuncEval+1; end @@ -204,6 +208,7 @@ end if Fargcollect [fb,varargout{1:nOut-1}]=Func(b,varargin{:}) ; + fb=full(fb); nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) @@ -211,6 +216,7 @@ end else fb=Func(b); + fb=full(fb); nFuncEval=nFuncEval+1; end end @@ -238,11 +244,12 @@ if ~isempty(nOut) && nOut> 0 [fmin,varargout{1:nOut-1}]=Func(gmin,varargin{:}) ; + fmin=full(fmin); end % now fmin < ftarget % I can now return % The only exception is if the user requests information about the - % backtracking and some pltos + % backtracking and some plots if ~(CtrlVar.InfoLevelBackTrack>=100 && CtrlVar.doplots==1 ) return @@ -271,12 +278,14 @@ iarm=1 ; BackTrackInfo.iarm=iarm; if Fargcollect [fgamma,varargout{1:nOut-1}]=Func(gamma,varargin{:}) ; + fgamma=full(fgamma); nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) [varargin{listInF}]=varargout{listOutF-1} ; end else fgamma=Func(gamma); + fgamma=full(fgamma); nFuncEval=nFuncEval+1; end @@ -326,12 +335,14 @@ if Fargcollect [fgamma,varargout{1:nOut-1}]=Func(gamma,varargin{1:end}) ; + fgamma=full(fgamma); nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) [varargin{listInF}]=varargout{listOutF-1} ; end else - fgamma=Func(gamma); + fgamma=Func(gamma); + fgamma=full(fgamma); nFuncEval=nFuncEval+1; end iq=iq+1 ; Infovector(iq,1)=gamma ; Infovector(iq,2)=fgamma ; [fmin,I]=min(Infovector(:,2)) ; gmin=Infovector(I,1) ; @@ -374,6 +385,7 @@ NoSlopeInformation=1; if Fargcollect [fb,varargout{1:nOut-1}]=Func(b,varargin{1:end}) ; + fb=full(fb); nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) @@ -381,6 +393,7 @@ end else fb=Func(b); + fb=full(fb); nFuncEval=nFuncEval+1; end iq=iq+1 ; Infovector(iq,1)=b ; Infovector(iq,2)=fb ; [fmin,I]=min(Infovector(:,2)) ; gmin=Infovector(I,1) ; @@ -423,6 +436,7 @@ if Fargcollect [fgamma,varargout{1:nOut-1}]=Func(gamma,varargin{1:end}) ; + fgamma=full(fgamma) ; nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) @@ -430,6 +444,7 @@ end else fgamma=Func(gamma); + fgamma=full(fgamma) ; nFuncEval=nFuncEval+1; end @@ -437,7 +452,7 @@ % Jan 2020: Just changed the limits on gamma so now gamma is somewhere between a and c % But I do not know if gamma is greater or less than b - % I want the minimum to be bracked by a and b + % I want the minimum to be bracketed by a and b % b=c ; fb=fc ; if gamma < b && fgamma< fb % min is between a and b @@ -468,6 +483,7 @@ if Fargcollect [fgamma,varargout{1:nOut-1}]=Func(gamma,varargin{1:end}) ; + fgamma=full(fgamma) ; nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) @@ -475,6 +491,7 @@ end else fgamma=Func(gamma); + fgamma=full(fgamma) ; nFuncEval=nFuncEval+1; end b=gamma ; fb=fgamma ; % this shifts b to the right @@ -493,6 +510,7 @@ if Fargcollect [fgamma,varargout{1:nOut-1}]=Func(gamma,varargin{1:end}) ; + fgamma=full(fgamma) ; nFuncEval=nFuncEval+1; if ~isempty(listOutF) && ~isempty(listInF) @@ -503,6 +521,7 @@ error("BackTrack:nan","nan in gamma") end fgamma=Func(gamma); + fgamma=full(fgamma) ; nFuncEval=nFuncEval+1; end @@ -647,9 +666,10 @@ gammaTestVector=linspace(Lower,Upper,nnn) ; dx=min(Infovector(2:end,1)/10) ; gammaTestVector=[Lower,dx/1000,dx/50,dx,2*dx,gammaTestVector(2:end)]; - parfor I=1:numel(gammaTestVector) + for I=1:numel(gammaTestVector) % parfor does not work if using MUA.Workers as composites not supported within a parfor loop gammaTest=gammaTestVector(I); rTest=Func(gammaTest); + rTest=full(rTest); gammaTestVector(I)=gammaTest ; rTestVector(I)=rTest; end diff --git a/BasalDrag.m b/BasalDrag.m index 85a4334b..2b60ffe7 100755 --- a/BasalDrag.m +++ b/BasalDrag.m @@ -1,7 +1,15 @@ + + + + + + + + function [taubx,tauby,dtaubxdu,dtaubxdv,dtaubydu,dtaubydv,dtaubxdh,dtaubydh,taubxo,taubyo,taubxa,taubya] = ... - BasalDrag(CtrlVar,MUA,He,delta,h,B,H,rho,rhow,ub,vb,C,m,uo,vo,Co,mo,ua,va,Ca,ma,q,g,muk) + BasalDrag(CtrlVar,MUA,He,delta,h,B,H,rho,rhow,ub,vb,C,m,uo,vo,Co,mo,ua,va,Ca,ma,q,g,muk,V0) - narginchk(24,24) + narginchk(25,25) %% % Returns basal drag and the directional derivatives of basal drag with respect to u, @@ -94,7 +102,7 @@ % % (U^(1/m - 1)*He(h - hf))/(m*(C + C0)^(1/m + 1)) - dFuvdC = He.* (1./m).*(C+C0).^(-1./m-1) .*Um; + dFuvdC = He.* (1./m).*(C+C0).^(-1./m-1) .*Um; % Um=speed.^(1./m-1) ; case {"B","Budd","W-N0"} @@ -119,13 +127,13 @@ U=speed; N=N0(CtrlVar,h,H,rho,rhow,g) ; - dFuvdC=(U.^(1.0./m-1.0).*muk.^(m+1.0).*N.^(m+1.0).*He.*(muk.^m.*N.^m+U.*(He.*(C+C0).^(-1.0./m)).^m).^(-1.0./m-1.0).*(C+C0).^(-1.0./m-1.0))./m; + dFuvdC=(U.^(1./m-1).*muk.^(m+1).*N.^(m+1).*He.*(muk.^m.*N.^m+U.*(He.*(C+C0).^(-1./m)).^m).^(-1./m-1).*(C+C0).^(-1./m-1))./m; case {"rCW-N0","Umbi"} % reciprocal Coulumb-Weertman with zeroth-order hydrology U=speed; N=N0(CtrlVar,h,H,rho,rhow,g) ; - dFuvdC=(U.^(1.0./m).*muk.^2.*N.^2.*He.*1.0./(U.^(1.0./m).*He+muk.*N.*(C+C0).^(1.0./m)).^2.*(C+C0).^(1.0./m-1.0))./(U.*m) ; + dFuvdC=(U.^(1./m).*muk.^2.*N.^2.*He.*1./(U.^(1./m).*He+muk.*N.*(C+C0).^(1./m)).^2.*(C+C0).^(1./m-1))./(U.*m) ; case {"Tsai","minCW-N0"} @@ -147,6 +155,12 @@ fprintf("Inversion using Coulomb sliding law not implemented. \n") error("BasalDrag:InvalidCase","Inversion using Tsai sliding law not implemented.") + + case {"Joughin","rCW-v0"} + + U=speed; + dFuvdC= (U.^(1./m-1).*He.*(U+V0).^(-1./m).*(C+C0).^(-1./m-1))./m ; + otherwise @@ -210,25 +224,37 @@ dtaubydui=dtaubxdvi; % just symmetry, always true, both Weertman and Coulom dtaubxdhi(isCoulomb)=dtaubxdhiC(isCoulomb); dtaubydhi(isCoulomb)=dtaubydhiC(isCoulomb); - - + + case {"rpCW-N0","Cornford"} - + [N,dNdh]=N0(CtrlVar,h,H,rho,rhow,g) ; [taubxi,taubyi,dtaubxdui,dtaubydvi,dtaubxdvi,dtaubydui,dtaubxdhi,dtaubydhi] = rpCWN0(C,CtrlVar.Czero,N,dNdh,He,delta,m,muk,ub,vb,CtrlVar.SpeedZero) ; - + case {"rCW-N0","Umbi"} % reciprocal Coulumb-Weertman with zeroth-order hydrology - + [N,dNdh]=N0(CtrlVar,h,H,rho,rhow,g) ; [taubxi,taubyi,dtaubxdui,dtaubydvi,dtaubxdvi,dtaubydui,dtaubxdhi,dtaubydhi] = rCWN0(C,CtrlVar.Czero,N,dNdh,He,delta,m,muk,ub,vb,CtrlVar.SpeedZero) ; - - + + case {"Joughin","rCW-v0"} + + C0=CtrlVar.Czero; + u0=CtrlVar.SpeedZero; + + + [taubxi,taubyi,dtaubxdui,dtaubydvi,dtaubxdvi,dtaubydui,dtaubxdhi,dtaubydhi] = rCWV0(C,C0,V0,He,delta,m,ub,vb,u0) ; + + % [taubxiW,taubyiW,dtaubxduiW,dtaubxdviW,dtaubyduiW,dtaubydviW,dtaubxdhiW,dtaubydhiW] = Weertman(CtrlVar,He,delta,ub,vb,beta2i,Dbeta2i) ; + % + % norm(taubxi-taubxiW) + % norm(taubyi-taubyiW) + otherwise - + error("BasalDrag:CaseNotFound","what sliding law?") end - - + + %% Sea ice drag term : ocean if CtrlVar.IncludeMelangeModelPhysics diff --git a/BoundaryConditions.m b/BoundaryConditions.m index c03d5bf7..0711d2fc 100755 --- a/BoundaryConditions.m +++ b/BoundaryConditions.m @@ -48,6 +48,9 @@ hPosNode=[]; hPosValue=[]; + hPosNodeActivated=[]; + hPosNodeDeActivated=[] ; + % Boundary conditions for the level set field % Only need when using the level-set method (currenlty under development, so don't % use!) diff --git a/BuildMuaWorkers.m b/BuildMuaWorkers.m new file mode 100755 index 00000000..1953758d --- /dev/null +++ b/BuildMuaWorkers.m @@ -0,0 +1,148 @@ + + + + +function MUAworkers=BuildMuaWorkers(CtrlVar,MUA,MUAworkers) + + +if ~CtrlVar.Parallel.BuildWorkers % Somtimes building workers is suppressed. + % For example when adapting the mesh repeatedly, there is no need to build workers for each + % mesh. Generally, only build workers ahead of a uv of uvh solve + + + return + +end + + + +if isempty(CtrlVar.Parallel.uvhAssembly.spmd.nWorkers) + poolobj = gcp ; + CtrlVar.Parallel.uvhAssembly.spmd.nWorkers=poolobj.NumWorkers; +end + +nW=CtrlVar.Parallel.uvhAssembly.spmd.nWorkers; + + +%% create element lists for each partition +% Use round to make sure that there are exactly nW partitions +% and ensure that all elements are included. + +Partition=cell(nW,1); +N=round(MUA.Nele/nW) ; i1=1 ; i2=N; +for iWorker=1:(nW-1) + Partition{iWorker}=i1:i2 ; + i1=i2+1 ; + i2=i2+N ; +end + +i2=MUA.Nele; +Partition{nW}=i1:i2 ; + +% outside of spmd M is composite +% inside of spmd M is struct on each worker + +MUA.dM=[] ; + +% Have I already build the workers for this mesh? +% I test this by seeing if the previous partition is the same + +% Not clear to me how to check if composite is in correct state. +% The only option seems to be just to try to access it and see if it produces an error. + +BuildWorkers= false ; + + +if isempty(MUAworkers) || numel(MUAworkers)==0 % if all empty, rebuild + + BuildWorkers= true; + +else + + try + isCompoositeInCorrectState=MUAworkers{1}.Nnodes==MUA.Nnodes ; + catch + isCompoositeInCorrectState=false; % if not in correct state, rebuild + + end + + if ~isCompoositeInCorrectState + BuildWorkers=true; + end + + % check if all partitions already contain the correct elements, if so then there is no need to build the workers anew + spmd (0,nW) + + T=all(MUAworkers.Partition==Partition{spmdIndex}) ; + Tand=spmdReduce(@and,T,1) ; + + end + + if ~Tand{1} + BuildWorkers=true; + end + + + % Turns out the spmd version above is much faster + % if isCompoositeInCorrectState + % + % areWorkersAlreadyBuild=true; + % for iWorker=1:nW + % + % % % do a simple test first + % % if numel(MUAworkers{iWorker}.Partition)~=numel(Partition{iWorker}) + % % areWorkersAlreadyBuild=false ; + % % break + % % end + % + % % now check if exacly the same elements are part of each partition + % if ~all(MUAworkers{iWorker}.Partition==Partition{iWorker}) + % % if sum(MUAworkers{iWorker}.Partition)~=sum(Partition{iWorker}) + % areWorkersAlreadyBuild=false ; % if new partition is not equal to previous one, rebuild + % + % break + % end + % + % end + % + % if ~areWorkersAlreadyBuild + % BuildWorkers=true; + % end + % + % end + +end + + + + + + +if BuildWorkers + spmd (0,nW) + + % Build M directly on the workers to avoid communication + + MUAworkers.nod=MUA.nod; + MUAworkers.nip=MUA.nip; + + MUAworkers.Nnodes=MUA.Nnodes; + MUAworkers.points=MUA.points; + MUAworkers.weights=MUA.weights; + + MUAworkers.coordinates=MUA.coordinates; + % + MUAworkers.Partition=Partition{spmdIndex} ; + MUAworkers.connectivity=MUA.connectivity(Partition{spmdIndex},:); + MUAworkers.Nele=numel(Partition{spmdIndex}); + MUAworkers.Deriv=MUA.Deriv(Partition{spmdIndex},:,:,:); + MUAworkers.DetJ=MUA.DetJ(Partition{spmdIndex},:); + MUAworkers.EleAreas=MUA.EleAreas(Partition{spmdIndex}) ; + + + end +end + + + +end \ No newline at end of file diff --git a/CalcBasalTraction.m b/CalcBasalTraction.m index 282c9c7a..0db87378 100755 --- a/CalcBasalTraction.m +++ b/CalcBasalTraction.m @@ -47,7 +47,7 @@ delta = DiracDelta(CtrlVar.kH,F.h-hf,CtrlVar.Hh0) ; [tbx,tby] = ... - BasalDrag(CtrlVar,MUA,He,delta,F.h,F.B,F.S-F.B,F.rho,F.rhow,F.ub,F.vb,F.C,F.m,F.uo,F.vo,F.Co,F.mo,F.ua,F.va,F.Ca,F.ma,F.q,F.g,F.muk); + BasalDrag(CtrlVar,MUA,He,delta,F.h,F.B,F.S-F.B,F.rho,F.rhow,F.ub,F.vb,F.C,F.m,F.uo,F.vo,F.Co,F.mo,F.ua,F.va,F.Ca,F.ma,F.q,F.g,F.muk,F.V0); tb=sqrt(tbx.^2+tby.^2); diff --git a/CalcCFLdt2D.m b/CalcCFLdt2D.m index f70b3c43..1047226f 100755 --- a/CalcCFLdt2D.m +++ b/CalcCFLdt2D.m @@ -1,43 +1,47 @@ -function dtcritical=CalcCFLdt2D(UserVar,RunInfo,CtrlVar,MUA,F) +function dtcritical=CalcCFLdt2D(UserVar,RunInfo,CtrlVar,MUA,F,u,v) % % CFL : dt < l/v % % +if nargin ==5 + + + switch lower(CtrlVar.FlowApproximation) + + + case 'sstream' + + u=F.ub; + v=F.vb; + + + case 'ssheet' + + u=F.ud ; + v=F.vd ; + + + case 'hybrid' + + u=F.ub+F.ud ; + v=F.vb+F.vd ; + + + otherwise + + error('what case') + + end -switch lower(CtrlVar.FlowApproximation) - - - case 'sstream' - - u=F.ub; - v=F.vb; - - - case 'ssheet' - - u=F.ud ; - v=F.vd ; - - - case 'hybrid' - - u=F.ub+F.ud ; - v=F.vb+F.vd ; - - - otherwise - - error('what case') - end speed=sqrt(u.*u+v.*v) ; -speed=Nodes2EleMean(MUA.connectivity,speed); +speed=Nodes2EleMean(MUA.connectivity,speed); + +l=sqrt(2*MUA.EleAreas); -l=sqrt(2*MUA.EleAreas); - dtcritical=min(l./(speed+eps)); diff --git a/CalcCostFunctionNR.m b/CalcCostFunctionNR.m index f899da9d..418f9ea8 100755 --- a/CalcCostFunctionNR.m +++ b/CalcCostFunctionNR.m @@ -1,3 +1,8 @@ + + + + + function [r,UserVar,RunInfo,rForce,rWork,D2,frhs,grhs,Normalisation] = CalcCostFunctionNR(UserVar,RunInfo,CtrlVar,MUA,gamma,F,fext0,L,l,cuv,dub,dvb,dl) nargoutchk(1,9) @@ -10,7 +15,10 @@ F.vb=F.vb+gamma*dvb; l.ubvb=l.ubvb+gamma*dl; - Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); + + CtrlVar.uvMatrixAssembly.Ronly=true; + % Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); + [RunInfo,Ruv]=uvMatrixAssembly(RunInfo,CtrlVar,MUA,F); if ~isempty(L) frhs=-Ruv-L'*l.ubvb; diff --git a/CalcCostFunctionNRuvh.m b/CalcCostFunctionNRuvh.m index 2419c581..84cb2a8f 100755 --- a/CalcCostFunctionNRuvh.m +++ b/CalcCostFunctionNRuvh.m @@ -1,3 +1,14 @@ + + + + + + + + + + + function [r,UserVar,RunInfo,rForce,rWork,D2]=CalcCostFunctionNRuvh(UserVar,RunInfo,CtrlVar,MUA,F1,F0,dub,dvb,dh,dl,L,luvh,cuvh,gamma,fext0) diff --git a/CalcIceVolume.m b/CalcIceVolume.m index 41ba3a8c..d8e40007 100755 --- a/CalcIceVolume.m +++ b/CalcIceVolume.m @@ -2,7 +2,7 @@ % [TotalIceVolume,ElementIceVolume]=CalcIceVolume(CtrlVar,MUA,h) % calculates ice volume over the whole FE mesh -% h is ice thickenss +% h is ice thickness ElementIceVolume=FEintegrate2D(CtrlVar,MUA,h) ; diff --git a/CalcMeshDerivatives.m b/CalcMeshDerivatives.m index 30e28eb3..7010a017 100755 --- a/CalcMeshDerivatives.m +++ b/CalcMeshDerivatives.m @@ -21,7 +21,7 @@ % ndim=2; points=sample('triangle',nip,ndim); -parfor Iint=1:nip +for Iint=1:nip [Deriv,detJ]=derivVector(coordinates,connectivity,nip,points,Iint); MeshDeriv(:,:,:,Iint)=Deriv; MeshDetJ(:,Iint)=detJ; diff --git a/CalculateReactions.m b/CalculateReactions.m index bb078b8c..0a74dd46 100755 --- a/CalculateReactions.m +++ b/CalculateReactions.m @@ -1,54 +1,123 @@ -function [Reactions,lStar]=CalculateReactions(CtrlVar,MUA,BCs,l) +function [Reactions,lStar]=CalculateReactions(CtrlVar,MUA,BCs,l,options) + -% save TestSaveCalculateReactions -narginchk(4,4) %% % + +% Calculates nodal reactions. +% % Reactions=CalculateReactions(MLC,l) % -% calculates nodal reactions -% Reactions=CalculateReactions(MLC,l) +% Nodal reactions are due to boundary conditions. They are here calculated from the values of the Lagrange parameters (l) introduced +% when enforcing Dirichlet boundary conditions. +% +% Reactions is a structure with the fields: +% +% Reactions.ubvb +% Reactions.udvd +% Reactions.h +% +% By setting the optional argument +% +% hReactionsExcludeActiveSet=true +% +% +% any positive thickness constraints that were added automatically, ie not by the user, during the run are excluded. +% +% Note that, for example, the h reactions are related to the additional mass per area required to keep the thickness at +% prescribed values. This fictitious mass flux (a_h) can be calculated as +% +% ah=Reactions.h/(F.rho*F.time) % -% MLC : muliple-linear-constraint matrix -% l : Lagrange variables +% So if, for example, rho and time are in IS units, the units of the reactions are kg/m^2, and that of ah is m/yr. % -% l is one of the outputs of Ua available in DefineOutputs +% *Sign Convention:* Same sign convention is used as when introducing the Lagrange parameters. It follows that if, for +% example, ADDITONAL mass flux is needed to keep the thickness at a given value, the resulting thickness reactions +% (Reactions.h) are NEGATIVE. This sign convention makes sense if active constraints are identified by the sign of the +% corresponding Lagrange parameters being negative. But this sign is presumably the opposite of what one might otherwise +% expect. So if the thickness reactions are NEGATIVE, then one needs to add a POSITIVE surface mass balance equal to +% +% -Reactions.h/(F.rho*F.time) +% +% to keep the thickness at desired value. +% +% +% +% l : Lagrange variables +% +% l is one of the outputs of Ua available in DefineOutputs % -% If MLC is not available, calculate MLC using MLC=BCs2MLC(MUA,BCs) % % Example: -% To calculate and plot reactions from within DefineOutputs -% MLC=BCs2MLC(MUA,BCs) ; -% Reactions=CalculateReactions(CtrlVar,MLC,l) -% PlotReactions(CtrlVar,MUA,Reactions); +% +% To calculate and plot reactions from within DefineOutputs +% +% Reactions=CalculateReactions(CtrlVar,MUA,BCs,l); +% PlotReactions(CtrlVar,MUA,F,Reactions); % % Reactions are defined for all the nodes, but for nodes where no BCs have been applied, % they will automatically be equal to zero. However, in the special case where no essential % BCs are applied, reactions are returned as an empty matrix. % -% If the multi-linear contraint matrix L was assembled in the FE basis, then the reactions +% If the multi-linear constraint matrix L was assembled in the FE basis, then the reactions % are already physically correct and I only need to split them up in uv and h reactions. % -% If L is a point-contraint matrix (default) then I need to map these into physical space -% usuing +% If L is a point-constraint matrix (default) then I need to map these into physical space +% using % % lambda^* = M^{-1} L' lambda % -% This gives lamnda over all nodes. +% This gives lambda over all nodes. % -% To restrict it to the nodes over which the constrants were applied use: +% To restrict it to the nodes over which the constraints were applied use: % % lambda^* = (L L')^{-1} L M^{-1} L' lambda % % +% +% Note: If the active set has only been updated, but never applied, the dimensions of the Lagrange vector (l.h) will be inconsistent with +% the number of positive thickness constraints (BCs.hFixeNode). +% +% Also: To plot reactions use: +% +% PlotReactions(CtrlVar,MUA,F,Reactions) +% %% + +arguments + + CtrlVar struct + MUA struct + BCs BoundaryConditions + l struct + options.hReactionsExcludeActiveSet logical = false % this allows for h reactions to exclude those of the active thickness constraints + % only the reactions due to the user-defined thickness constraints are then calculated + +end + +if ~isfield(MUA,"M") || isempty(MUA.M) + MUA.M=MassMatrix2D1dof(MUA); + MUA.dM=decomposition(MUA.M,'chol','upper') ; +end + +if ~isfield(MUA,"dM") || isempty(MUA.dM) + MUA.dM=decomposition(MUA.M,'chol','upper') ; +end + + Reactions.ubvb=[]; Reactions.udvd=[]; Reactions.h=[]; lStar.h=[]; % only calculating physical lambdas for thickness constraints +% getting rid of all positive thickness constraints as part of the active set +if options.hReactionsExcludeActiveSet + BCs.hPosNode=[]; BCs.hPosValue=[]; lh=l.h(1:numel(BCs.hFixedNode)) ; l.h=lh ; +end + + MLC=BCs2MLC(CtrlVar,MUA,BCs) ; if ~CtrlVar.LinFEbasis @@ -58,13 +127,21 @@ end if ~isempty(l.ubvb) - - luv=MLC.ubvbL'*l.ubvb; - Rx=MUA.M\luv(1:MUA.Nnodes); - Ry=MUA.M\luv(MUA.Nnodes+1:end); - Reactions.ubvb=full([Rx;Ry]); - - + + luv=MLC.ubvbL'*l.ubvb; + + try + Rx=MUA.dM\luv(1:MUA.Nnodes); % I can't see how I can know if the decomposition is in a valid state without just trying + catch + MUA.dM=decomposition(MUA.M,'chol','upper') ; + Rx=MUA.dM\luv(1:MUA.Nnodes); + end + + + Ry=MUA.dM\luv(MUA.Nnodes+1:end); + Reactions.ubvb=full([Rx;Ry]); + + end if ~isempty(l.udvd) @@ -75,13 +152,13 @@ end if ~isempty(l.h) - M=MUA.M; - L=MLC.hL; - lambda=l.h ; - Reactions.h=full(M\(L'*lambda)); + + Lh=MLC.hL; + + Reactions.h=full(MUA.dM\(Lh'*l.h)); if nargout>1 - lStar.h=full((L*L')\(L*Reactions.h)); + lStar.h=full((Lh*Lh')\(Lh*Reactions.h)); end end diff --git a/CalvingFrontLevelSetGeometricalInitialisation.m b/CalvingFrontLevelSetGeometricalInitialisation.m index c2fb7f7f..959b95ad 100755 --- a/CalvingFrontLevelSetGeometricalInitialisation.m +++ b/CalvingFrontLevelSetGeometricalInitialisation.m @@ -2,7 +2,7 @@ % % Takes initial calving front data (Xc,Yc) and a level set function LSF, which on input only must have the correct sign, and -% initializes the level set based on gemetrical distance from the (Xc,Yc) calving front. Then recomputes the calving front +% initializes the level set based on geometrical distance from the (Xc,Yc) calving front. Then recomputes the calving front % from the level set. % % The level-set provided on input is initialized based on the (Xc,Yc) values, and the LSF provided on input will be @@ -13,7 +13,7 @@ % % The returned calving front, (xc,yc), may not be identical to the calving front (Xc,Yc) provided as input. There are a % number of (subtle) reasons for this. The (xc,yc) calving front is (re) calculated from the nodal values of level set field -% (LSF), calculated (ie initialized) using the (Xc,Yc) values. Despite best atempts, this operation, ie calculating c=(xc,yc) +% (LSF), calculated (ie initialized) using the (Xc,Yc) values. Despite best attempts, this operation, ie calculating c=(xc,yc) % from LSF, which we can write c=c(LSF), is not an exact inverse of the function LSF=LSF(c). % % This can be understood as being related to lack degrees-of-freedom when calculating LSF nodal values, as a single LSF nodal @@ -22,10 +22,10 @@ % identical to the calving front as given on input. % % -% If the calving front is provided on input as (Xc,Yc), it can optionally be subsampled within elements. Generally this is a -% must if one is performing a re-initialisation during a run, as otherwise the geometric re-initialzation can shift the level -% set. But for the first initialisation this is hardly requried as it only impacts the initial location of the calving front, -% and if the calving front is alread known at a high resolution as (Xc,Yc) from some observations, such resampling is +% If the calving front is provided on input as (Xc,Yc), it can optionally be sub-sampled within elements. Generally this is a +% must if one is performing a re-initialization during a run, as otherwise the geometric re-initialization can shift the level +% set. But for the first initialization this is hardly required as it only impacts the initial location of the calving front, +% and if the calving front is already known at a high resolution as (Xc,Yc) from some observations, such re-sampling is % superfluous. % % There is a special case when Xc and Yc are entered as empty arrays, in which case Xc and Yc are simply determined by @@ -34,7 +34,7 @@ % (Xc,Yc) is known, the return calving front (xc,yc) is much more likely to cut across the elements similar as (Xc,Yc). % % -% On input only the sign of LSF must be correct. This is, for nodes inside/upstream of calving fronts LSF must be positive, +% On input only the sign of LSF must be correct. That is, for nodes inside/upstream of calving fronts, LSF must be positive, % and for nodes outside/downstream of calving fronts, negative. % % On return LSF has be initialized geometrically based on the distance from nodes to the (xcEdges,ycEdges) intersections @@ -47,7 +47,7 @@ % The "EleEdges" method is slower than "InputPoints" method, and possibly in practice the resulting differences are not that % significant. % -% When using the "InputPoints" method, it might be good to resample the calving front at equal intervals by setting +% When using the "InputPoints" method, it might be good to re-sample the calving front at equal intervals by setting % % % ResampleCalvingFront=true @@ -120,14 +120,14 @@ % To speed up the calculation consider to: % 1) get rid of any sections of the calving front outside of the computational boundary -% 2) subsample points along the calving front. +% 2) sub-sample points along the calving front. % % But presumably all such manipulations with the input data are better done ahead of % the call. if options.GetRidOfCalvingFrontOutsideComputationalDomain % 1) Get rid of any points of the calving profile outside the mesh domain - % But be carfulle with this as it does not deal with more than one calving front! + % But be careful with this as it does not deal with more than one calving front! io=inpoly2(P1, [MUA.Boundary.x MUA.Boundary.y]); P1=P1(io,:) ; end @@ -139,7 +139,7 @@ nPoints=size(P1,1); - % Check if there are several seperate calving fronts, and resample each individually + % Check if there are several separate calving fronts, and re-sample each individually iNaN=find(isnan(P1(:,1))); ii=[0;iNaN;nPoints+1] ; @@ -174,34 +174,32 @@ case "EleEdges" % - % Here the intersections between individual ele edges and the calving front profile as defined by (Xc,Yc) + % Here the intersections between individual element edges and the calving front profile as defined by (Xc,Yc) % are determined, and the LSF is then initialized as the distance to those intersection points switch MUA.nod case 3 - EleEdges=con(:,[1 2 3 1]); % These are element edges, this is only for 3-node elements. + EleEdges=con(:,[1 2 3 1]); % These are element edges, for 3-node elements. % In general, these should be the nodal numbers of the corner nodes % so that this traces a closed loop for every element. case 6 - EleEdges=con(:,[1 3 5 1]); % These are element edges + EleEdges=con(:,[1 3 5 1]); % These are element edges, for 6-node elements. % This does not make it any more accurate, only slower %con=TriFE(MUA.connectivity); - %EleEdges=con(:,[1 2 3 1]); % These are element edges, this is only for 3-node elements. - - + case 10 - EleEdges=con(:,[1 4 7 1]); % These are element edges + EleEdges=con(:,[1 4 7 1]); % These are element edges, for 10-node elements % This does not make it any more accurate, only slower %con=TriFE(MUA.connectivity); - %EleEdges=con(:,[1 2 3 1]); % These are element edges, this is only for 3-node elements. + otherwise @@ -220,13 +218,13 @@ end P2(end,:)=[] ; - % Now calculate the intersection points using this matlab function + % Now calculate the intersection points using this MATLAB function [xcEdges,ycEdges]=polyxpoly(P1(:,1),P1(:,2),P2(:,1),P2(:,2)); case "InputPoints" % Here I simply take the input calving profile. - % But this may above have been resampled already, in which case this + % But this may above have been re-sampled already, in which case this % is potentially a finer subdivision xcEdges=P1(:,1); ycEdges=P1(:,2); @@ -249,7 +247,7 @@ CtrlVar.PlotNodes=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; - PlotMuaMesh(CtrlVar,MUA,[],"w"); + PlotMuaMesh(CtrlVar,MUA,nan,"w"); %tt=axis; plot(xcOnInput/CtrlVar.PlotXYscale,ycOnInput/CtrlVar.PlotXYscale,'-go',LineWidth=1,MarkerSize=6,DisplayName="Calving fronts before re-initialisation") hold on @@ -265,7 +263,7 @@ [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,LSFonInput/CtrlVar.PlotXYscale); hold on CtrlVar.PlotNodes=0; - PlotMuaMesh(CtrlVar,MUA,[],"w"); + PlotMuaMesh(CtrlVar,MUA,nan,"w"); %tt=axis; plot(Xc/CtrlVar.PlotXYscale,Yc/CtrlVar.PlotXYscale,'-g.',LineWidth=1) hold on @@ -277,7 +275,7 @@ [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,(LSF-LSFonInput)/CtrlVar.PlotXYscale); hold on - PlotMuaMesh(CtrlVar,MUA,[],"w"); + PlotMuaMesh(CtrlVar,MUA,nan,"w"); %tt=axis; plot(xc/CtrlVar.PlotXYscale,yc/CtrlVar.PlotXYscale,'-g.',LineWidth=1) hold on diff --git a/ClearPersistentUaVariables.m b/ClearPersistentUaVariables.m index 5a263be1..c5755670 100644 --- a/ClearPersistentUaVariables.m +++ b/ClearPersistentUaVariables.m @@ -32,5 +32,7 @@ function ClearPersistentUaVariables() clear PlotFEmesh clear FindOrCreateFigure clear LevelSetEquation +clear p2F + end diff --git a/CreateFEmeshTriRep.m b/CreateFEmeshTriRep.m index 7a0412c7..c0dae571 100755 --- a/CreateFEmeshTriRep.m +++ b/CreateFEmeshTriRep.m @@ -1,3 +1,9 @@ + + + + + + function FEmeshTriRep=CreateFEmeshTriRep(connectivity,coordinates) % [FEmeshTriRep]=CreateFEmeshTriRep(connectivity,coordinates) diff --git a/CreateMUA.m b/CreateMUA.m index 6a7f6302..04d87768 100755 --- a/CreateMUA.m +++ b/CreateMUA.m @@ -2,8 +2,8 @@ % MUA=CreateMUA(CtrlVar,connectivity,coordinates,CalcMUA_Derivatives,FindMUA_Boundary) % -% Creates the Úa mesh structure containing all information about the FE mesh -% such as coordinates, connectivity, boundary nodes, etc Also (optionally) +% Creates the Ua mesh structure containing all information about the FE mesh +% such as coordinates, connectivity, boundary nodes, etc. Also (optionally) % calculates element derivatives used in the matrix assembly. % % Example: MUA=CreateMUA(CtrlVar,connectivity,coordinates); @@ -21,7 +21,7 @@ connectivity=reshape(J,size(connectivity)); coordinates=coordinates(K,:); -% First check if element type on input is as reqested by user, and if not change +% First check if element type on input is as requested by user, and if not change [MUA.coordinates,MUA.connectivity]=ChangeElementType(coordinates,connectivity,CtrlVar.TriNodes); MUA.Nnodes=size(MUA.coordinates,1); MUA.Nele=size(MUA.connectivity,1); @@ -29,7 +29,7 @@ if CtrlVar.QuadRules2021 % This uses the new quad rules implemented in 2021 - % The old ones are there for comparision and compatability + % The old ones are there for comparison and compatibility Degree=QuadratureRuleDegree(CtrlVar); MUA.QuadratureRuleDegree=Degree; Q=quadtriangle(Degree,'Type','nonproduct','Points','inside','Domain',[0 0 ; 1 0 ; 0 1]) ; @@ -92,6 +92,13 @@ MUA.Area=sum(MUA.EleAreas); % total FE mesh area +MUA.workers=[]; + +if CtrlVar.Parallel.uvAssembly.spmd.isOn || CtrlVar.Parallel.uvhAssembly.spmd.isOn + + MUA.workers=BuildMuaWorkers(CtrlVar,MUA,MUA.workers) ; + +end diff --git a/CreateOutputs.m b/CreateOutputs.m index 0e632d77..4cd0f60c 100644 --- a/CreateOutputs.m +++ b/CreateOutputs.m @@ -3,7 +3,7 @@ warning('off','MATLAB:structOnObject') % convert objects to structures. Otherwise it will not be possible to save/re-use these -% objects outside of Úa. +% objects outside of �a. % l=struct(l); BCs=struct(BCs) ; @@ -16,32 +16,40 @@ if exist('UaOutputs.m','file')==2 && ~(exist('DefineOutputs.m','file')==2) - warning("OldInputFormat:UaOutputs","UaOutputs.m no longer used. Rename that file to DefineOutputs.m") - + warning("OldInputFormat:UaOutputs","UaOutputs.m no longer used. Rename that file to DefineOutputs.m") + end % To reduce the size of output files, I delete some of the MUA fields -% If requred this can always be recreated by the call: +% If required this can always be recreated by the call: % % MUA=UpdateMUA(CtrlVar,MUA); % % -MUA.DetJ=[] ; MUA.Deriv=[] ; MUA.dM=[] ; MUA.M=[] ; MUA.TR=[] ; +MUA.DetJ=[] ; MUA.Deriv=[] ; MUA.dM=[] ; MUA.M=[] ; MUA.TR=[] ; MUA.workers=[]; + +Nouts=nargout('DefineOutputs'); +Nins=nargin('DefineOutputs'); -N=nargout('DefineOutputs'); +switch Nouts -switch N - case 0 - - DefineOutputs(UserVar,CtrlVar,MUA,BCs,F,l,F.GF); - + + if Nins==6 + DefineOutputs(UserVar,CtrlVar,MUA,BCs,F,l); + else + UserVar=DefineOutputs(UserVar,CtrlVar,MUA,BCs,F,l,F.GF,InvStartValues,InvFinalValues,Priors,Meas,BCsAdjoint,RunInfo); + end + case 1 - - UserVar=DefineOutputs(UserVar,CtrlVar,MUA,BCs,F,l,F.GF,InvStartValues,InvFinalValues,Priors,Meas,BCsAdjoint,RunInfo); - + if Nins==6 + DefineOutputs(UserVar,CtrlVar,MUA,BCs,F,l); + else + UserVar=DefineOutputs(UserVar,CtrlVar,MUA,BCs,F,l,F.GF,InvStartValues,InvFinalValues,Priors,Meas,BCsAdjoint,RunInfo); + end + end end \ No newline at end of file diff --git a/CtrlVarValidityCheck.m b/CtrlVarValidityCheck.m index a5f039d2..55bd12f6 100755 --- a/CtrlVarValidityCheck.m +++ b/CtrlVarValidityCheck.m @@ -255,6 +255,15 @@ end +if CtrlVar.Inverse.MinimisationMethod=="MatlabOptimization-HessianBased" && CtrlVar.TriNodes>3 + + + fprintf("Using CtrlVar.Inverse.MinimisationMethod=%s for other then linear elements (ie for CtrlVar.TriNodes>3) is not recommended. \n",CtrlVar.Inverse.MinimisationMethod) + fprintf('Consider setting CtrlVar.Inverse.MinimisationMethod="MatlabOptimization-GradientBased" or using linear elements. \n') + warning("UaInputs:ParameterCombinationNotRecommented","ParameterCombinationNotRecommented") + +end + if contains(CtrlVar.Inverse.MinimisationMethod,'Hessian') @@ -265,7 +274,7 @@ end - +%% if isfield(CtrlVar,'AdaptMeshInterval') diff --git a/CubicFit.m b/CubicFit.m index e27a3ead..cc2985cc 100755 --- a/CubicFit.m +++ b/CubicFit.m @@ -66,7 +66,7 @@ if ab(1) == 0 || ~isreal(xmin) || isnan(xmin) - if ~isnan(Slope0) + if ~isnan(Slope) D=((y1-y0)/x1-Slope) ; xmin=-x1*Slope/2/D; if ~isnan(xmin) diff --git a/Data/AntarcticaVelocities.png b/Data/AntarcticaVelocities.png new file mode 100755 index 00000000..e2a37d43 Binary files /dev/null and b/Data/AntarcticaVelocities.png differ diff --git a/DeactivateMUAelements.m b/DeactivateMUAelements.m index ef014e54..3a2f1b9e 100644 --- a/DeactivateMUAelements.m +++ b/DeactivateMUAelements.m @@ -1,11 +1,27 @@ -function [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated) +function [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated,kIn,lIn) +%% % -% Deactivates elements in the list iDeactivatedElements +% Deactivates elements in the list +% +% ElementsToBeDeactivated +% +% The variable ElementsToBeDeactivated can be either a logical or an index array. +% +% kIn and lIn are optional inputs. % % Nodes that are no longer part of the FE mesh are deleted and the connectivity updated accordingly % -% +% Set +% +% CtrlVar.UpdateMUAafterDeactivating=true +% +% ahead of call, if the MUA should be updated. This will typically involve re-calculating various MUA-related quantities required +% for the FE solver. Often this is not needed if, for example, several element deactivations are performed in a sequence, or if this +% is one of several modifications to the mesh. MUA is always updated in Ua automatically ahead of a solve, so this updated may not be +% needed at all. +% +% % If CtrlVar.sweep is true, elements and nodes are then renumbered. % % k gives me the mapping between new and old node numbers, that is: @@ -30,7 +46,9 @@ % % gives the new node number i for the old node number j. % -% l(j) is nan where there is no node in the new mesh corresponding to the old node j, ie for all deleted nodes. +% l(j)=nan +% +% if no node in the new mesh corresponds to the old node j, ie for all deleted nodes. % % To get a list of deleted old node numbers use: % @@ -40,7 +58,26 @@ % % ~isnan(l) ; % logical list of nodes in the old mesh used/kept in the new mesh. % +% If elements are deactivated repeatedly and one needs to know the mapping between the original and the final mesh do: +% +% +% k=k1(k2(k3)) % where k1 results from the first, k2 from the second, etc, deactivations +% +% and then: +% +% l=1:nNodesIn ; l=l(:)+nan; +% l(k(1:numel(k)))=1:numel(k); +% +% where nNodesIn is the number of nodes in the initial mesh, i.e. before the first round of deactivations. Alternatively, provide +% k and l from the previous deactivation as an input. These are the optional input variables kIn and lIn. The k and l will then be +% updated as k=kIn(k), providing the mapping with respect to the original mesh. +% +%% + +narginchk(3,5) + +% This works equally for both logical and index arrays. if ~any(ElementsToBeDeactivated) k=1:MUA.Nnodes; l=1:MUA.Nnodes; @@ -49,6 +86,9 @@ nNodesIn=MUA.Nnodes; + + + MUA.connectivity(ElementsToBeDeactivated,:)=[]; % eliminate MUA.coordinates that are no longer part of mesh, and update MUA.connectivity accordingly @@ -65,21 +105,46 @@ if CtrlVar.sweep [MUA.coordinates,MUA.connectivity,p] = NodalSweep(MUA.coordinates,MUA.connectivity,CtrlVar.SweepAngle); [MUA.coordinates,MUA.connectivity] = ElementSweep(MUA.coordinates,MUA.connectivity,CtrlVar.SweepAngle); - k=k(p) ; + k=k(p) ; % keep track of how k changes end if CtrlVar.UpdateMUAafterDeactivating MUA=UpdateMUA(CtrlVar,MUA); +else + MUA.M=[]; + MUA.Deriv=[]; + MUA.DetJ=[]; + MUA.TR=[]; + MUA.Boundary=[]; + MUA.dM=[]; + MUA.xEle=[]; + MUA.yEle=[]; + MUA.Nnodes=size(MUA.coordinates,1); + MUA.Nele=size(MUA.connectivity,1); + MUA.EleAreas=TriAreaFE(MUA.coordinates,MUA.connectivity); % areas for each element + MUA.Area=sum(MUA.EleAreas); + +end + +if nargin>4 && ~isempty(kIn) + k=kIn(k); end + + if nargout==3 % create a mapping from old to new node numbers - l=1:nNodesIn ; l=l(:)+nan; + if nargin==5 && ~isempty(lIn) + l=lIn+nan; + else + %l=1:nNodesIn ; l=l(:)+nan; + l=nan(nNodesIn,1) ; + end l(k(1:numel(k)))=1:numel(k); end % MUA.RefineMesh=[] ; % As I now have a new mesh I need to reset the newest vertex bisection data structure. -% % Therefore no further unrefinement over the previous mesh can be done. +% % Therefore no further un-refinement over the previous mesh can be done. diff --git a/DefineAGlenDistribution.m b/DefineAGlenDistribution.m index 4034b109..e5aa89ed 100755 --- a/DefineAGlenDistribution.m +++ b/DefineAGlenDistribution.m @@ -10,12 +10,17 @@ % % [UserVar,AGlen,n]=DefineAGlenDistribution(UserVar,CtrlVar,MUA,time,s,b,h,S,B,rho,rhow,GF) % -% +% Note: Use +% +% [AGlen,B]=AGlenVersusTemp(T) +% +% to get A in the units kPa^{-3} yr^{-1} for some temperature T (degrees Celsius) +% %% n=3 ; -A=6.338e-25; -AGlen=A*1e9*365.2422*24*60*60+zeros(MUA.Nnodes,1); +A=6.338e-25; % A in SI units for temperate ice ; +AGlen=A*1e9*365.2422*24*60*60+zeros(MUA.Nnodes,1); % A in the units kPa^{-3} yr^{-1} end diff --git a/DefineBoundaryConditions.m b/DefineBoundaryConditions.m index a7e2aa00..8c72afeb 100755 --- a/DefineBoundaryConditions.m +++ b/DefineBoundaryConditions.m @@ -4,7 +4,7 @@ %% % BCs=DefineBoundaryConditions(UserVar,CtrlVar,MUA,BCs,time,s,b,h,S,B,ub,vb,ud,vd,GF) % -% BC is a matlab object with the following fields +% BC is a MATLAB object with the following fields % % BCs = % @@ -56,18 +56,18 @@ xd=max(F.x) ; xu=min(F.x); yl=max(F.y) ; yr=min(F.y); -% find nodes along boundary, simple approach +% Find nodes along boundary, simple approach % nodesd=find(abs(x-xd)<1e-5); [~,ind]=sort(MUA.coordinates(nodesd,2)); nodesd=nodesd(ind); % nodesu=find(abs(x-xu)<1e-5); [~,ind]=sort(MUA.coordinates(nodesu,2)); nodesu=nodesu(ind); % nodesl=find(abs(y-yl)<1e-5); [~,ind]=sort(MUA.coordinates(nodesl,1)); nodesl=nodesl(ind); % nodesr=find(abs(y-yr)<1e-5); [~,ind]=sort(MUA.coordinates(nodesr,1)); nodesr=nodesr(ind); -% find nodes along boundary, more robust approach. -% Here we are using the fact that all nodes along the boundary in the list: +% Find nodes along boundary, more robust approach. +% Here we are using the fact that all nodes along the boundary are in the list: % % MUA.Boundary.Nodes % -% And we only limit the search to those nodes along the boundary. +% And we only limit the search to those nodes. % L=min(sqrt(MUA.EleAreas)/1000); % set a distance tolerance which is a fraction of smallest element size nodesd=MUA.Boundary.Nodes(abs(MUA.coordinates(MUA.Boundary.Nodes,1)-xd)0 where the ice is grounded, and <0 otherwise + if contains(UserVar.RunType,"-c0isGL0-") % -> Initial calving front (c0) is set a initial grounding line position (GL0) LSF=-ones(MUA.Nnodes,1) ; - LSF(F.GF.node>0.5)=+1; - Xc=[] ; % If Xc and Yc are left empty, the Xc and Yc will be calculated as the zero contorl of the LSF field + LSF(F.GF.node>0.5)=+1; % LSF set dependent on the values grounded-floating mask + Xc=[] ; % If Xc and Yc are left empty, the Xc and Yc will be calculated as the zero control of the LSF field Yc=[] ; else - Xc=UserVar.CalvingFront0.Xc; + Xc=UserVar.CalvingFront0.Xc; % Here is is assumed that the user has defined the desired initial location of the calving front, and stored those in UserVar Yc=UserVar.CalvingFront0.Yc; - % A rough sign-correct initialisation for the LSF + % A rough sign-correct initialization for the LSF io=inpoly2([F.x F.y],[Xc(:) Yc(:)]); LSF=-ones(MUA.Nnodes,1) ; LSF(io)=+1; + end % figure ; PlotMuaMesh(CtrlVar,MUA); hold on ; plot(F.x(io)/1000,F.y(io)/1000,'or') + % Not really needed, but it might then be good to initialize the level set so that LSF is approximately a signed distance + % function. + % [xc,yc,LSF]=CalvingFrontLevelSetGeometricalInitialisation(CtrlVar,MUA,Xc,Yc,LSF,plot=true,ResampleCalvingFront=true); @@ -77,21 +86,30 @@ elseif CtrlVar.CalvingLaw.Evaluation=="-int-" - % c=0; % Must not be nan or otherwise the LSF will not be evolved. - % But otherwise these c values are of no importance and the c defined at int points is the one used - - % This value for the calving rate will actually not be used directly by the code - % because the calving rate is here defined at integration points. - % But for plotting purposes it is good to define the calving at nodal points as well - % so here a call is made to define c at the nodes. - % c=DefineCalvingAtIntegrationPoints(UserVar,CtrlVar,nan,nan,F.ub,F.vb,F.h,F.s,F.S,F.x,F.y) ; + % Generally, one would define the calving rate at the nodes, unless the calving rate is a function of the level-set itself. + % + % It the calving rate, c, depends on the level set function, LSF, then various derivatives involving c and LSF (phi) need to be + % calculated as well for the Newton-Raphson methods to achieve second-order convergence + + % If the calving law is defined at nodes, you still need to use DefineCalving.m as well to define LSF. + + % Generally there is no need to call 'DefineCalvingAtIntegrationPoints' from within DefineCalving.m and the calving rate, c, + % returned by DefineCalving.m is not used. + % + % However, one might find it convenient to define c here as otherwise c is not defined at nodes and can not be plotted at a + % nodal variable. + % + % + % c=DefineCalvingAtIntegrationPoints(UserVar,CtrlVar,nan,nan,F) ; else - % It's assumed that the calving is defined at integration points only, or prescribed directly. - % Anything else is deemed an error. - error("Define calving rate at integration points") + % Here the calving rate is defined at the nodes. This is presumably the most typical case + + CliffHeight=min((F.s-F.S),F.h) ; + c=10*CliffHeight ; % an example of calving law which depends linearly on the freeboard height. + end diff --git a/DefineCalvingAtIntegrationPoints.m b/DefineCalvingAtIntegrationPoints.m index 614d14ff..21f97b4b 100755 --- a/DefineCalvingAtIntegrationPoints.m +++ b/DefineCalvingAtIntegrationPoints.m @@ -27,9 +27,9 @@ % % [c,dcddphidx,dcddphidy]=DefineCalvingAtIntegrationPoints(UserVar,CtrlVar,dphidx,dphidy,F) % -% which provies dphi/dx and dphi/dy where phi is the level-set function +% which provides dphi/dx and dphi/dy where phi is the level-set function % -% This option is activated by the usuer by setting +% This option is activated by the user by setting % % % CtrlVar.CalvingLaw.Evaluation="-int-" ; @@ -82,7 +82,7 @@ fI=3.2e-17*365.25 ; c=fI*CliffHeight.^(7.2) ; % Now set calving rate to zero for cliff less than 135meters c(CliffHeight<135)=0 ; - % and set maximum at at cliff height equalt to 450m + % and set maximum at at cliff height equal to 450m cMax=fI*450.^(7.2) ; c(c>cMax)=cMax ; diff --git a/DefineDesiredEleSize.m b/DefineDesiredEleSize.m index 2186a6bf..b07e96c7 100755 --- a/DefineDesiredEleSize.m +++ b/DefineDesiredEleSize.m @@ -24,7 +24,7 @@ % * ElementsToBeRefined and ElementsToBeCoarsened when using local mesh refinement with the the newest vertex bisection % % -% On input EleSize are desired ele sizes at (x,y) as +% On input EleSize are desired element sizes at (x,y) as % calculated by Úa based on some user-defined criteria. % % On output EleSize are user-modified values. @@ -32,7 +32,7 @@ % Do not modify the size of the (nodal) vector `EleSizeDesired' or the logical (element) % vector 'ElementsToBeRefine', only the values. % -% When using the gobal remeshing option x,y are the locations where new element sizes are specifed (these are the coordinates of the mesh) +% When using the global remeshing option x,y are the locations where new element sizes are specified (these are the coordinates of the mesh) % % *Note: When using the local remeshing option, x and y as given on input are not relevant. % In this case use MUA.xEle and MUA.yEle as the x, y locations where the elements are to be refined or coarsened.* @@ -57,7 +57,7 @@ % I=inpoly([x y],Boundary) ; % EleSizeDesired(I)=1000; % -% Here Boundary doese not have to be just a simple square, it can be a polygon of any shape. +% Here Boundary does not have to be just a simple square, it can be a polygon of any shape. % % *Example:* To set all ele size of all floating elements (i.e. ice shelves) % to 1000: diff --git a/DefineGeometryAndDensities.m b/DefineGeometryAndDensities.m index 421373ba..60d25881 100644 --- a/DefineGeometryAndDensities.m +++ b/DefineGeometryAndDensities.m @@ -34,10 +34,12 @@ % F.g : gravitational acceleration % F.x : x nodal coordinates % F.y : y nodal coordinates +% F.time : time (i.e. model time) % F.GF : The nodal grounded/floating mask (has other subfields) % -% These fields need to be returned at the nodal coordinates. The nodal -% x and y coordinates are stored in MUA.coordinates, and also in F as F.x and F.y +% These fields need to be returned at the nodal coordinates. +% +% The nodal x and y coordinates are also stored in MUA.coordinates in addition to F.x and F.y. % %% diff --git a/DefineInputsForInverseRun.m b/DefineInputsForInverseRun.m index d9045495..829ed6bc 100755 --- a/DefineInputsForInverseRun.m +++ b/DefineInputsForInverseRun.m @@ -7,7 +7,7 @@ % What you need to define are: % % -% # Measurments and data errors (data errors are specified as diagonal covariance matrices.) +% # Measurements and data errors (data errors are specified as diagonal covariance matrices.) % # Start values for inversion. (These are some values for the model parameters that you want to invert for.) % # Priors for the inverted fields. (Currently the only priors that are used the the priors for C and AGlen.) % @@ -18,14 +18,14 @@ persistent FuMeas FvMeas FerrMeas % keep scattered interpolants for the data in memory. -%% get measurments and define error covariance matrices +%% get measurements and define error covariance matrices if isempty(FuMeas) % Here I'm assuming the user has defined the field % % UserVar.SurfaceVelocityInterpolant % - % which is the name of a mat file containint surface velocity data interpolants. + % which is the name of a mat file containing surface velocity data interpolants. % % diff --git a/DefineMassBalance.m b/DefineMassBalance.m index b8766b44..1eea8d4a 100755 --- a/DefineMassBalance.m +++ b/DefineMassBalance.m @@ -2,6 +2,7 @@ %% +% % Defines mass balance along upper and lower ice surfaces. % % [UserVar,as,ab]=DefineMassBalance(UserVar,CtrlVar,MUA,time,s,b,h,S,B,rho,rhow,GF) @@ -10,18 +11,45 @@ % % [UserVar,as,ab,dasdh,dabdh]=DefineMassBalance(UserVar,CtrlVar,MUA,CtrlVar.time,s,b,h,S,B,rho,rhow,GF); % +% [UserVar,as,ab,dasdh,dabdh]=DefineMassBalance(UserVar,CtrlVar,MUA,F); +% % as mass balance along upper surface % ab mass balance along lower ice surface -% dasdh upper surface mass balance gradient with respect to ice thickness -% dabdh lower surface mass balance gradient with respect to ice thickness +% dasdh upper surface mass balance gradient with respect to ice thickness (optional) +% dabdh lower surface mass balance gradient with respect to ice thickness (optional) % -% dasdh and dabdh only need to be specified if the mass-balance feedback option is -% being used. +% dasdh and dabdh only need to be specified if the implicit mass-balance feedback option is +% being used. To use the implicit mass-balance feedback option you must set +% +% CtrlVar.MassBalanceGeometryFeedback=3; +% +% in DefineInitialInputs.m. Otherwise, the default value of +% +% CtrlVar.MassBalanceGeometryFeedback=0; +% +% is used, which does not include the implicit mass-balance feedback. +% +% +% IMPORTANT: In Ua the mass balance, as returned by this m-file, is multiplied internally by the local ice density. +% +% The units of as and ab are the same units as those of velocity (something like m/yr or m/day). +% +% IMPORTANT: Often surface mass balance is provided my climate models as mass flux and in the units kg/(m^2 yr). This is as +% if we prescribe the value of the product of density and accumulation rate, ie rho a, which has the units kg/(m^2 yr). In Ua +% this translation to mass flux is done internally, i.e. the rho is included in the mass conservation equation. The surface +% mass balance (as and ab) prescribed here as an input to Ua MUST BE IN THE UNITS distance/time, e.g. m/yr. +% +% If you have external data sets providing the mass flux in the units kg/(m^2 yr) you must divide those values here by the +% density, and this density must be the same density as is given in DefineGeometryAndDensities.m +% +% Also, if an external data sets provides the surface mass balance in the units of water equivalent, you must modify this +% value by the ratio between the density of water and the density of ice that you prescribe in DefineGeometryAndDensities.m, +% for example as 1000/rho, assuming rho is given in the units kg/m^3. +% +% For example, if you use a constant density for ice of 920 kg/m^3 and the surface mass balance is given as 1 m/yr of water +% equivalent (ie 1000 kg/(m^2 yr) ), the surface mass balance you need here is 1000/920 m/yr. % -% In Úa the mass balance, as returned by this m-file, is multiplied internally by the local ice density. % -% The units of as and ab are water equivalent per time, i.e. usually -% as and ab will have the same units as velocity (something like m/yr or m/day). % % As in all other calls: % @@ -29,9 +57,9 @@ % F.b : lower ice surface % F.B : bedrock % F.S : ocean surface -% F.rhow : ocean density (scalar variable) -% F.rho : ice density (nodal variable) -% F.g : gravitational acceleration +% F.rhow : ocean density (scalar variable) +% F.rho : ice density (nodal variable) +% F.g : gravitational acceleration % F.x : x nodal coordinates % F.y : y nodal coordinates % F.GF : The nodal grounded/floating mask (has other subfields) @@ -59,10 +87,20 @@ % ab=F.s*0; % dabdh=zeros(MUA.Nnodes,1); % +% Note: To use the implicit mass-balance feedback option you must set +% +% CtrlVar.MassBalanceGeometryFeedback=3; +% +% in DefineInitialInputs.m. Otherwise, the default value of +% +% CtrlVar.MassBalanceGeometryFeedback=0; +% +% is used, which does not include the implicit mass-balance feedback. +% % *To add basal melt due to sliding as a mass-balance term:* % % [tbx,tby,tb,beta2] = CalcBasalTraction(CtrlVar,MUA,F.ub,F.vb,F.C,F.m,F.GF); -% L=333.44 ; % Enthalpy of fusion = L = [J/gramm = kJ/kg] Make sure that the units are correct. +% L=333.44 ; % Enthalpy of fusion = L = [J/gram = kJ/kg] Make sure that the units are correct. % F.ab=-(tbx.*F.ub+tby.*F.vb)./(F.rho.*L); % Ablation (Melt) is always negative, accumulation is positive % % diff --git a/DefineMeshModifications.m b/DefineMeshModifications.m index 59631ebb..68095159 100755 --- a/DefineMeshModifications.m +++ b/DefineMeshModifications.m @@ -1,10 +1,12 @@ -function [coordinates,connectivity]=DefineMeshModifications(CtrlVar,coordinates,connectivity) +function [UserVar,coordinates,connectivity]=DefineMeshModifications(UserVar,CtrlVar,coordinates,connectivity); + + %% % This m-file is called directly after each meshing step to allow for % further modifications of the FE mesh. % -% [coordinates,connectivity]=UserMeshModifications(CtrlVar,coordinates,connectivity) +% [UserVar,coordinates,connectivity]=DefineMeshModifications(UserVar,CtrlVar,coordinates,connectivity); % % A typical use is to deactivate some elements. % When deactivating elements, use the m-file @@ -16,7 +18,7 @@ % DeactivatedElements=[10 ; 11] ; % list of elements to be deactivated % [coordinates,connectivity]=DeactivateElements(CtrlVar,iDeactivatedElements,coordinates,connectivity); % -% Example: Deactivate elements whose centrepoints are within a given polygon: +% Example: Deactivate elements whose center-points are within a given polygon: % % load('NameOfFileWithPolygonEdges',xPoly,yPoly); % xEle=Nodes2EleMean(connectivity,coordinates(:,1)); diff --git a/DefineOutsideValues.m b/DefineOutsideValues.m index ace67c8d..03f77312 100644 --- a/DefineOutsideValues.m +++ b/DefineOutsideValues.m @@ -9,17 +9,17 @@ % These values are used in a transient run when mapping % (interpolating/extrapolating) from one mesh to another whenever some nodes of % the new mesh are outside of the previous mesh. That is, when the new mesh has -% some nodes that are not witin any of the elements of the previous mesh. +% some nodes that are not within any of the elements of the previous mesh. % % This situation can arise when using, for example, manual deactivation of -% elements. If the domain increases in size, then some intial velocites and +% elements. If the domain increases in size, then some initial velocities and % thicknesses must be defined over these new areas. % % Typically, some minimum thickness will be defined over the new areas and the -% velocites set to zero. The velocity values are only used as a start values for -% a diagnostic uv solution. Hence, the exact velocites prescibed are not +% velocities set to zero. The velocity values are only used as a start values for +% a diagnostic uv solution. Hence, the exact velocities prescribed are not % important (provided the uv solution converges). However, the thickness -% prescibed over the new areas is important as it defines the new start values +% prescribed over the new areas is important as it defines the new start values % over any outside areas. Note that in a diagnostic (time-independent run) the % thickness is always prescribed using DefineGeometry.m. For that reason this % routine is never used in a diagnostic run. @@ -31,7 +31,7 @@ % Prescribe here outside thickness values of twice the minimum ice thickness. OutsideValue.h=2*CtrlVar.ThickMin ; -% Make sure the s and b correspondes to flotation. However this is not essential +% Make sure the s and b corresponds to flotation. However this is not essential % as s and b are always adjusted internally based on h, S and B given rho and % rhow. OutsideValue.s=mean(F.S)+OutsideValue.h*(1-mean(F.rho)/F.rhow); diff --git a/DefineStartVelValues.m b/DefineStartVelValues.m index a69cf294..6b88575b 100755 --- a/DefineStartVelValues.m +++ b/DefineStartVelValues.m @@ -2,16 +2,13 @@ - - - -function [UserVar,ub,vb,ud,vd]=DefineStartVelValues(UserVar,CtrlVar,MUA,BCs,ub,vb,ud,vd,time,s,b,h,S,B,rho,rhow,GF,AGlen,n,C,m) +function [UserVar,ub,vb,ud,vd,l]=DefineStartVelValues(UserVar,CtrlVar,MUA,BCs,F,l) %% % Define start values for velocities % -% [UserVar,ub,vb,ud,vd]=DefineStartVelValues(UserVar,CtrlVar,MUA,BCs,ub,vb,ud,vd,time,s,b,h,S,B,rho,rhow,GF,AGlen,n,C,m) +% [UserVar,F.ub,F.vb,F.ud,F.vd]=DefineStartVelValues(UserVar,CtrlVar,MUA,BCs,F) % % This user m-file defines the starting values for the velocities. This is just % the initial estimate of the solution and, provided the solver converges, it has @@ -21,8 +18,17 @@ % default approach. So generally this m-file is not required to obtain a solution, % but it may speed things up. % +% l are Lagrange parameters related to boundary conditions % +% If you have those from a previous solve, these can be specified here. +% +%% + +ub=F.ub; +vb=F.vb; +ud=F.ud; +vd=F.vd; end diff --git a/ExamplesOfMeshGeneration.m b/ExamplesOfMeshGeneration.m index 51f9afa1..a6c2b8bb 100755 --- a/ExamplesOfMeshGeneration.m +++ b/ExamplesOfMeshGeneration.m @@ -121,6 +121,7 @@ %str=input('Next example? y/n [y] ? ','s'); if strcmpi(str,'n') ; return ; end %% Example: periodic boundary conditions CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; % When using �a only the following lines are needed in the input file % Ua2D_InitialUserInput.m @@ -159,6 +160,7 @@ %% Example: sinusoidal bed CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; UserVar=[]; xL=-20e3 ; xR=20e3 ; yB=0 ; yT=2e3; @@ -194,6 +196,7 @@ CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; L=20e3; h0=250; @@ -222,6 +225,7 @@ %% Example: house without a window CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; CtrlVar.MeshSizeMax=0.1; CtrlVar.MeshSizeMin=0.1; CtrlVar.MeshSize=0.1; @@ -237,6 +241,7 @@ % when creating holes within a mesh, separate boundaries by NaN NaN % CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; CtrlVar.MeshSizeMax=0.1; CtrlVar.MeshSizeMin=0.1; CtrlVar.MeshSize=0.1; @@ -253,6 +258,7 @@ % When generating separate meshed domains, label each domain with a number. % The label is the specified by putting `Label NaN' ahead of the corresponding boundary CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; CtrlVar.MeshSizeMax=0.1; CtrlVar.MeshSizeMin=0.1; CtrlVar.MeshSize=0.1; @@ -322,6 +328,7 @@ % when creating holes within a mesh, separate boundaries by NaN NaN % CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; CtrlVar.MeshSizeMax=1e3; @@ -359,6 +366,7 @@ % the 'plane surface' (gmsh terminology) separatly. This is done in CtrlVar.GmshPlaneSurface CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; CtrlVar.MeshSizeMax=0.1; CtrlVar.MeshSizeMin=0.1; CtrlVar.MeshSize=0.1; @@ -382,10 +390,11 @@ % This can be done using both gmsh and mesh2d, but the format for MeshBoundaryCoordinates is different! CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; CtrlVar.MeshSizeMax=0.1; CtrlVar.MeshSizeMin=0.1; CtrlVar.MeshSize=0.1; -CtrlVar.MeshGenerator="gmsh"; % this option only works with gmsh... +CtrlVar.MeshGenerator="gmsh"; CtrlVar.MeshGenerator="mesh2d"; UserVar=[]; @@ -402,11 +411,36 @@ %str=input('Next example? y/n [y] ? ','s'); if strcmpi(str,'n') ; return ; end + + +%% Two meshes connected at just one node + + +CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; +CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; + +CtrlVar.MeshSizeMax=0.1; CtrlVar.MeshSizeMin=0.1; CtrlVar.MeshSize=0.1; +CtrlVar.MeshGenerator="mesh2d"; +UserVar=[]; + + +CtrlVar.MeshBoundaryCoordinates=[0 0 ; 0 1 ; 1 1 ; 1 0 ; ... + 0 0 ; -1 0 ; -1 1 ; 0 0 ] ; + + +[UserVar,MUA]=genmesh2d(UserVar,CtrlVar); +figure ; PlotMuaMesh(CtrlVar,MUA); drawnow + + + + %% Example: Internal boundaries # 1 CtrlVar.MeshGenerator='gmsh'; CtrlVar.MeshGenerator='mesh2d'; CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=1; CtrlVar.PlotXYscale=1; @@ -449,6 +483,7 @@ % For example internal calving front CtrlVar=Ua2D_DefaultParameters(); +CtrlVar.PlotXYscale=1; CtrlVar.MeshGenerator='gmsh'; CtrlVar.MeshGenerator='mesh2d'; CtrlVar.PlotXYscale=1; @@ -860,5 +895,11 @@ FindOrCreateFigure("ele sizes histogram") ; histogram( sqrt(2*MUA.EleAreas)) ; xlabel("Element size") +MUA.dM=[]; +MUA.coordinates(:,2)=-(MUA.coordinates(:,2)) ; +MUA.coordinates=MUA.coordinates-mean(MUA.coordinates); +FindOrCreateFigure("Ua Logo Mesh") ; PlotMuaMesh([],MUA) ; axis xy +save("UaLogoMUA.mat","MUA") + diff --git a/GetBoundaryConditions.m b/GetBoundaryConditions.m index 0956fa93..72590c3d 100755 --- a/GetBoundaryConditions.m +++ b/GetBoundaryConditions.m @@ -1,4 +1,8 @@ + + + + function [UserVar,BCs]=GetBoundaryConditions(UserVar,CtrlVar,MUA,BCs,F) diff --git a/GetInputsForForwardRun.m b/GetInputsForForwardRun.m index b79c32bd..ba00efed 100755 --- a/GetInputsForForwardRun.m +++ b/GetInputsForForwardRun.m @@ -58,6 +58,7 @@ PrintInfoAboutElementsSizes(CtrlVar,MUA); if ~isempty(CtrlVar.SaveInitialMeshFileName) + MUA.workers=[]; % saving composites not supported, MATLAB2024a save(CtrlVar.SaveInitialMeshFileName,'MUA') ; fprintf(CtrlVar.fidlog,' MUA was saved in %s .\n',CtrlVar.SaveInitialMeshFileName); end @@ -112,10 +113,12 @@ [UserVar,F]=GetSeaIceParameters(UserVar,CtrlVar,MUA,BCs,F); -[UserVar,F]=GetStartVelValues(UserVar,CtrlVar,MUA,BCs,F); +l=UaLagrangeVariables; + +[UserVar,F,l]=GetStartVelValues(UserVar,CtrlVar,MUA,BCs,F,l); + -l=UaLagrangeVariables; F.dubdt=zeros(MUA.Nnodes,1) ; diff --git a/GetInputsForInverseRestartRun.m b/GetInputsForInverseRestartRun.m index a5706a63..b2b46bdc 100755 --- a/GetInputsForInverseRestartRun.m +++ b/GetInputsForInverseRestartRun.m @@ -28,7 +28,7 @@ [InvStartValues.AGlen,InvStartValues.n]=TestAGlenInputValues(CtrlVar,MUA,InvStartValues.AGlen,InvStartValues.n); -[InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk]=TestSlipperinessInputValues(CtrlVar,MUA,InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk); +[InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk,InvStartValues.V0]=TestSlipperinessInputValues(CtrlVar,MUA,InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk,InvStartValues.V0); %[Priors.AGlen,Priors.n]=TestAGlenInputValues(CtrlVar,MUA,Priors.AGlen,Priors.n); %[Priors.C,Priors.m]=TestSlipperinessInputValues(CtrlVar,MUA,Priors.C,Priors.m); diff --git a/GetInputsForInverseRun.m b/GetInputsForInverseRun.m index 2eae77d2..0fb5e7b8 100755 --- a/GetInputsForInverseRun.m +++ b/GetInputsForInverseRun.m @@ -24,7 +24,7 @@ [InvStartValues.AGlen,InvStartValues.n]=TestAGlenInputValues(CtrlVar,MUA,InvStartValues.AGlen,InvStartValues.n); %[Priors.AGlen,Priors.n]=TestAGlenInputValues(CtrlVar,MUA,Priors.AGlen,Priors.n); -[InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk]=TestSlipperinessInputValues(CtrlVar,MUA,InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk); +[InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk,InvStartValues.V0]=TestSlipperinessInputValues(CtrlVar,MUA,InvStartValues.C,InvStartValues.m,InvStartValues.q,InvStartValues.muk,InvStartValues.V0); %[Priors.C,Priors.m]=TestSlipperinessInputValues(CtrlVar,MUA,Priors.C,Priors.m); %[Priors.rho,Priors.rhow]=TestDensityInputValues(CtrlVar,MUA,Priors.rho,Priors.rhow); diff --git a/GetMassBalance.m b/GetMassBalance.m index c07ec0c6..14e136a4 100755 --- a/GetMassBalance.m +++ b/GetMassBalance.m @@ -8,7 +8,7 @@ -N=nargout('DefineMassBalance'); +N=nargout(InputFile); NargInputFile=nargin(InputFile); switch N @@ -77,19 +77,19 @@ error(errorStruct) end -if numel(F.as)==1 +if isscalar(F.as) F.as=F.as+zeros(MUA.Nnodes,1); end -if numel(F.ab)==1 +if isscalar(F.ab) F.ab=F.ab+zeros(MUA.Nnodes,1); end -if numel(F.dasdh)==1 +if isscalar(F.dasdh) F.dasdh=F.dasdh+zeros(MUA.Nnodes,1); end -if numel(F.dabdh)==1 +if isscalar(F.dabdh) F.dabdh=F.dabdh+zeros(MUA.Nnodes,1); end diff --git a/GetSlipperyDistribution.m b/GetSlipperyDistribution.m index 92ed0fcd..ba1790ea 100755 --- a/GetSlipperyDistribution.m +++ b/GetSlipperyDistribution.m @@ -42,6 +42,7 @@ else [UserVar,F.C,F.m,F.q]=DefineSlipperyDistribution(UserVar,CtrlVar,MUA,F); end + case 5 if NargInputFile>4 @@ -53,7 +54,19 @@ [UserVar,F.C,F.m,F.q,F.muk]=DefineSlipperyDistribution(UserVar,CtrlVar,MUA,F); end - + + case 6 + + if NargInputFile>4 + + [UserVar,F.C,F.m,F.q,F.muk,F.V0]=DefineSlipperyDistribution(UserVar,CtrlVar,MUA,CtrlVar.time,F.s,F.b,F.h,F.S,F.B,F.rho,F.rhow,F.GF); + + else + + [UserVar,F.C,F.m,F.q,F.muk,F.V0]=DefineSlipperyDistribution(UserVar,CtrlVar,MUA,F); + + end + otherwise error('Ua:GetSlipperyDistribution','DefineSlipperyDistribution must return between 3 and 5 arguments') @@ -63,7 +76,7 @@ F.Cmax=CtrlVar.Cmax; F.Cmin=CtrlVar.Cmin; -[F.C,F.m,F.q,F.muk]=TestSlipperinessInputValues(CtrlVar,MUA,F.C,F.m,F.q,F.muk); +[F.C,F.m,F.q,F.muk,F.V0]=TestSlipperinessInputValues(CtrlVar,MUA,F.C,F.m,F.q,F.muk,F.V0); diff --git a/GetStartVelValues.m b/GetStartVelValues.m index fe322b77..35a79213 100755 --- a/GetStartVelValues.m +++ b/GetStartVelValues.m @@ -1,10 +1,24 @@ -function [UserVar,F]=GetStartVelValues(UserVar,CtrlVar,MUA,BCs,F) +function [UserVar,F,l]=GetStartVelValues(UserVar,CtrlVar,MUA,BCs,F,l) -narginchk(5,5) -nargoutchk(2,2) +narginchk(6,6) +nargoutchk(3,3) +InputFile="DefineStartVelValues.m" ; -[UserVar,F.ub,F.vb,F.ud,F.vd]=DefineStartVelValues(UserVar,CtrlVar,MUA,BCs,F.ub,F.vb,F.ud,F.vd,CtrlVar.time,F.s,F.b,F.h,F.S,F.B,F.rho,F.rhow,F.GF,F.AGlen,F.n,F.C,F.m); +% TestIfInputFileInWorkingDirectory(InputFile) ; + + + +N=nargout(InputFile); +NargInputFile=nargin(InputFile); + +if NargInputFile>6 + + [UserVar,F.ub,F.vb,F.ud,F.vd]=DefineStartVelValues(UserVar,CtrlVar,MUA,BCs,F.ub,F.vb,F.ud,F.vd,CtrlVar.time,F.s,F.b,F.h,F.S,F.B,F.rho,F.rhow,F.GF,F.AGlen,F.n,F.C,F.m); + +else + + [UserVar,F.ub,F.vb,F.ud,F.vd,l]=DefineStartVelValues(UserVar,CtrlVar,MUA,BCs,F,l) ; end diff --git a/HessianAC.m b/HessianAC.m index dbfacb62..270c0c10 100644 --- a/HessianAC.m +++ b/HessianAC.m @@ -1,3 +1,8 @@ + + + + + function Hessian=HessianAC(p,lambda,plb,pub,UserVar,CtrlVar,MUA,BCs,F,l,InvStartValues,Priors,Meas,BCsAdjoint,RunInfo) diff --git a/ITS-LIVE-ANT-G0120-0000-AntarticIceSheetBoundary-nStride5.mat b/ITS-LIVE-ANT-G0120-0000-AntarticIceSheetBoundary-nStride5.mat new file mode 100755 index 00000000..226d5eef Binary files /dev/null and b/ITS-LIVE-ANT-G0120-0000-AntarticIceSheetBoundary-nStride5.mat differ diff --git a/InversionUsingMatlabOptimizationToolbox3.m b/InversionUsingMatlabOptimizationToolbox3.m index 923bdcd1..b1aa7d4a 100755 --- a/InversionUsingMatlabOptimizationToolbox3.m +++ b/InversionUsingMatlabOptimizationToolbox3.m @@ -1,8 +1,19 @@ function [p,RunInfo]=InversionUsingMatlabOptimizationToolbox3(UserVar,CtrlVar,RunInfo,MUA,func,p0,plb,pub,Hfunc) -CtrlVar.Inverse.MatlabOptimisationGradientParameters= optimoptions(CtrlVar.Inverse.MatlabOptimisationGradientParameters,'MaxIterations',CtrlVar.Inverse.Iterations); +CtrlVar.Inverse.MatlabOptimisationGradientParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationGradientParameters,'MaxIterations',CtrlVar.Inverse.Iterations); +CtrlVar.Inverse.MatlabOptimisationGradientParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationGradientParameters,'OptimalityTolerance',CtrlVar.Inverse.OptimalityTolerance); +CtrlVar.Inverse.MatlabOptimisationGradientParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationGradientParameters,'FunctionTolerance',CtrlVar.Inverse.FunctionTolerance); +CtrlVar.Inverse.MatlabOptimisationGradientParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationGradientParameters,'StepTolerance',CtrlVar.Inverse.StepTolerance); + + CtrlVar.Inverse.MatlabOptimisationHessianParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationHessianParameters,'MaxIterations',CtrlVar.Inverse.Iterations); +CtrlVar.Inverse.MatlabOptimisationHessianParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationHessianParameters,'OptimalityTolerance',CtrlVar.Inverse.OptimalityTolerance); +CtrlVar.Inverse.MatlabOptimisationHessianParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationHessianParameters,'FunctionTolerance',CtrlVar.Inverse.FunctionTolerance); +CtrlVar.Inverse.MatlabOptimisationHessianParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationHessianParameters,'StepTolerance',CtrlVar.Inverse.StepTolerance); + + + CtrlVar.Inverse.MatlabOptimisationHessianParameters = optimoptions(CtrlVar.Inverse.MatlabOptimisationHessianParameters,'HessianFcn',Hfunc); Test=CtrlVar.Inverse.MatlabOptimisationGradientParameters; diff --git a/InversionValues.m b/InversionValues.m index 63165f30..62464874 100755 --- a/InversionValues.m +++ b/InversionValues.m @@ -8,6 +8,7 @@ n=[]; q=[]; muk=[]; + V0=[]; C=[]; AGlen=[]; B=[]; diff --git a/InvertForModelParameters.m b/InvertForModelParameters.m index c8dcf218..879f4cba 100755 --- a/InvertForModelParameters.m +++ b/InvertForModelParameters.m @@ -16,6 +16,8 @@ %% Define inverse parameters and anonymous function returning objective function, directional derivative, and Hessian % +MUAworkers=[]; % replace later with MUA field + F=InvStartValues2F(CtrlVar,MUA,F,InvStartValues,Priors,Meas) ; [F.b,F.s,F.h,F.GF]=Calc_bs_From_hBS(CtrlVar,MUA,F.h,F.S,F.B,F.rho,F.rhow); @@ -35,6 +37,9 @@ CtrlVar.Inverse.ResetPersistentVariables=1; + + + [J0,dJdp,Hessian,JGHouts,F,RunInfo]=JGH(p0,plb,pub,UserVar,CtrlVar,MUA,BCs,F,l,InvStartValues,Priors,Meas,BCsAdjoint,RunInfo); CtrlVar.Inverse.ResetPersistentVariables=0; % The parameters passed in the anonymous function are those that exist at the time the anonymous function is created. @@ -111,8 +116,10 @@ error('what case? ') end + F=p2F(CtrlVar,MUA,p,F,Meas,Priors); - [J,dJdp,Hessian,JGHouts,F]=JGH(p,plb,pub,UserVar,CtrlVar,MUA,BCs,F,l,InvStartValues,Priors,Meas,BCsAdjoint,RunInfo); + + [J,dJdp,Hessian,JGHouts,F,RunInfo]=JGH(p,plb,pub,UserVar,CtrlVar,MUA,BCs,F,l,InvStartValues,Priors,Meas,BCsAdjoint,RunInfo); fprintf('\n +++++++++++ At end of inversion: \t J=%-g \t I=%-g \t R=%-g |grad|=%g \n \n',J,JGHouts.MisfitOuts.I,JGHouts.RegOuts.R,norm(dJdp)) diff --git a/JGH.m b/JGH.m index 2943dc49..4382110f 100755 --- a/JGH.m +++ b/JGH.m @@ -1,3 +1,8 @@ + + + + + function [J,dJdp,Hessian,JGHouts,F,RunInfo]=JGH(p,plb,pub,UserVar,CtrlVar,MUA,BCs,F,l,InvStartValues,Priors,Meas,BCsAdjoint,RunInfo) diff --git a/Juv.m b/Juv.m index bf55c3f5..d9a892e4 100644 --- a/Juv.m +++ b/Juv.m @@ -11,11 +11,17 @@ if nargout>2 - [Ruv,Kuv]=KRTFgeneralBCs(CtrlVar,MUA,F); + % [Ruv,Kuv]=KRTFgeneralBCs(CtrlVar,MUA,F); + CtrlVar.uvMatrixAssembly.Ronly=false; + [RunInfo,Ruv,Kuv]=uvMatrixAssembly(RunInfo,CtrlVar,MUA,F); else - Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); + + % Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); + + CtrlVar.uvMatrixAssembly.Ronly=true; + [RunInfo,Ruv]=uvMatrixAssembly(RunInfo,CtrlVar,MUA,F); Kuv=[]; end diff --git a/KRTFgeneralBCs.m b/KRTFgeneralBCs.m index cf36da09..9fbcfea8 100755 --- a/KRTFgeneralBCs.m +++ b/KRTFgeneralBCs.m @@ -1,4 +1,4 @@ -function [Ruv,Kuv,Tint,Fext]=KRTFgeneralBCs(CtrlVar,MUA,F,ZeroFields) +function [Ruv,Kuv,Tint,Fext]=KRTFgeneralBCs(CtrlVar,MUA,F) %% % @@ -10,57 +10,33 @@ % %% -if nargin<4 - CtrlVar.uvAssembly.ZeroFields=false; -else - CtrlVar.uvAssembly.ZeroFields=ZeroFields; -end +error("KRTF:NoLongerUSed","replace with a call to uvMatrixAssembly") + + +narginchk(3,3) -if nargout==1 - - CtrlVar.uvMatrixAssembly.Ronly=1; -else - CtrlVar.uvMatrixAssembly.Ronly=0; -end +% Make sure that the info about zero fields is always in the CtrlVar on input, and not implied by the number of input +% arguments. +% if nargin<5 +% CtrlVar.uvAssembly.ZeroFields=false; +% else +% CtrlVar.uvAssembly.ZeroFields=ZeroFields; +% end -%[Ruv,Kuv,Tint,Fext]=uvMatrixAssembly(CtrlVar,MUA,F,ZeroFields); -%tAssembly=tic; -if CtrlVar.Parallel.uvAssembly.spmd.isOn && ~CtrlVar.uvMatrixAssembly.Ronly - [Ruv,Kuv,Tint,Fext]=uvAssemblySPMD(CtrlVar,MUA,F); -else - [Ruv,Kuv,Tint,Fext]=uvMatrixAssembly(CtrlVar,MUA,F); +if nargout==1 && ~CtrlVar.uvMatrixAssembly.Ronly + error("KRTFgeneralBCs: More than one output, but assembly only required for R. ") end -%RunInfo.CPU.Assembly.uv=toc(tAssembly)+RunInfo.CPU.Assembly.uv; +[Ruv,Kuv,Tint,Fext]=uvMatrixAssembly(CtrlVar,MUA,F); + -%% - -if CtrlVar.Parallel.isTest && CtrlVar.Parallel.uvAssembly.spmd.isOn && ~CtrlVar.uvMatrixAssembly.Ronly - - tSeq=tic; - [Ruv,Kuv,Tint,Fext]=uvMatrixAssembly(CtrlVar,MUA,F); - tSeq=toc(tSeq) ; - - tSPMD=tic; - [Ruv2,Kuv,Tint,Fext]=uvAssemblySPMD(CtrlVar,MUA,F); - tSPMD=toc(tSPMD); - - if ~CtrlVar.uvMatrixAssembly.Ronly - - fprintf('\n \n ----------------------------- \n') - fprintf(' tSeq=%f \t tSPMD=%f \t MUA.Nele=%i \t norm(Ruv-Ruv2)/norm(Ruv)=%g \n',tSeq,tSPMD,MUA.Nele,norm(full(Ruv-Ruv2))/norm(full(Ruv))) - %fprintf(RunInfo.File.fid,' tSeq=%f \t tSPMD=%f \t MUA.Nele=%i \t %f \n',tSeq,tSPMD,MUA.Nele,norm(full(Ruv-Ruv2))/norm(full(Ruv))); - end - -end -% end diff --git a/LevelSetEquation.m b/LevelSetEquation.m index 498d85d7..ab6fc98f 100644 --- a/LevelSetEquation.m +++ b/LevelSetEquation.m @@ -142,7 +142,7 @@ PSR(F0.LSFMask.NodesOut,:)=NaN; FindOrCreateFigure("P1") ; PlotMeshScalarVariable(CtrlVar,MUA,PSR(:,1)) ; CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; - hold on ; PlotMuaMesh(CtrlVar,MUA,[],'w') ; + hold on ; PlotMuaMesh(CtrlVar,MUA,nan,'w') ; hold on ; PlotCalvingFronts(CtrlVar,MUA,F0,'r'); FindOrCreateFigure("P2") ; PlotMeshScalarVariable(CtrlVar,MUA,PSR(:,2)) ; diff --git a/LevelSetEquationNewtonRaphson.m b/LevelSetEquationNewtonRaphson.m index 731d564f..20ea5fc8 100644 --- a/LevelSetEquationNewtonRaphson.m +++ b/LevelSetEquationNewtonRaphson.m @@ -209,7 +209,7 @@ Lower=-0.5 ; if gamma>0.7*Upper ; Upper=2*gamma; end parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:genericError'); - parfor I=1:nnn + for I=1:nnn gammaTest=(Upper-Lower)*(I-1)/(nnn-1)+Lower [rTest,~,~,rForceTest,rWorkTest,D2Test]=Func(gammaTest); gammaTestVector(I)=gammaTest ; rForceTestvector(I)=rForceTest; rWorkTestvector(I)=rWorkTest; rD2Testvector(I)=D2Test; @@ -267,11 +267,11 @@ -RunInfo.LevelSet.time(RunInfo.LevelSet.iCount)=CtrlVar.time; -RunInfo.LevelSet.Iterations(RunInfo.LevelSet.iCount)=iteration ; -RunInfo.LevelSet.Residual(RunInfo.LevelSet.iCount)=r; -RunInfo.LevelSet.BackTrackSteps( RunInfo.LevelSet.iCount)=BackTrackInfo.iarm ; -RunInfo.LevelSet.Phase(RunInfo.LevelSet.iCount)=CtrlVar.LevelSetPhase; +RunInfo.LevelSet.time(RunInfo.LevelSet.iCount,1)=CtrlVar.time; +RunInfo.LevelSet.Iterations(RunInfo.LevelSet.iCount,1)=iteration ; +RunInfo.LevelSet.Residual(RunInfo.LevelSet.iCount,1)=r; +RunInfo.LevelSet.BackTrackSteps( RunInfo.LevelSet.iCount,1)=BackTrackInfo.iarm ; +RunInfo.LevelSet.Phase(RunInfo.LevelSet.iCount,1)=CtrlVar.LevelSetPhase; diff --git a/LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly.m b/LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly.m new file mode 100755 index 00000000..cc1c390e --- /dev/null +++ b/LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly.m @@ -0,0 +1,255 @@ + + + + + +function [Islands]=LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly(CtrlVar,MUA) + + + +%% +% +% [Islands]=LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly(CtrlVar,MUA) +% +% Identifies elements that are detached from the main part of the mesh. The `main part' being defined as the isolated region with +% the largest number of elements. +% +% Also can identify boundary nodes that are parts of two boundaries or more, ie are contained more than once in the list of +% boundary nodes tracing the boundary. In most cases, this situation arises when an element group is connected to another group of +% elements by just one node. But this can also happen if there is a hole in the mesh (ie internal boundary) and a node is also on +% the boundary of another hole, or an external boundary. +% +% +% If only isolated islands are to be identified set: +% +% CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly="-Islands-"; +% +% If regions connected by one node are to be identified, set +% +% CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly="-OneNodeOrLessConnections-" ; +% +% Note that one-node-or-less always includes isolated element islands as well. +% +% This routine is typically used to get rid of separate islands and regions just connected by one node. Keeping such regions in +% the mesh can lead to numerical difficulties, especially if those elements are floating elements. +% +% Outputs: +% +% Islands.Free logical list of element islands, ie groups of elements not connected to the largest group of elements +% in the mesh. +% +% Islands.OneNode logical list of elements connected to the rest by one node or less. (This will include the elements +% islands as well) +% +% +% CtrlVar: +% +% CtrlVar.MinNumberOfNodesPerIslands : A seperated mesh region (i.e. an island) will only be contained if it contains at least this +% number of nodes +% +% CtrlVar.MaxNumberOfIslands : A maximum number of seperated mesh regions to be kept in the computational mesh +% +% +% My defauls an mesh island must contain at least one node and only one region is kept. +% +% +% The m-file TestLocateEleIslands.m provides an example of the use of this routine. +% +% +%% + + + + +if ~isfield(CtrlVar,"MinNumberOfNodesPerIslands") + + CtrlVar.MinNumberOfNodesPerIslands=1; + +end + + +if ~isfield(CtrlVar,"MaxNumberOfIslands") + + CtrlVar.MaxNumberOfIslands=1 ; + +end + + +%% + + +NumberOfElementsConnectedToTheMainMeshByJustOneNode=0; +NumberOfElementsNotConnectedToTheMainMesh=0; + +if ~isfield(CtrlVar,"LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly") + + CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly="-Islands-OneNodeOrLessConnections-" ; + +end + +% This works for all element types, but the `implementation' for 6 and 10 nodes is simply based on creating a new 3-node mesh +% with the same element numbering +if CtrlVar.TriNodes~=3 + CtrlVar.TriNodes=3 ; + CtrlVar.CalcMUA_Derivatives=false; + CtrlVar.MUA.MassMatrix=false; + CtrlVar.MUA.DecomposeMassMatrix=false; + CtrlVar.MUA.StiffnessMatrix=false; + CtrlVar.FindMUA_Boundary=true; + MUA=UpdateMUA(CtrlVar,MUA) ; +end + +if ~contains(CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly,"-OneNodeOrLessConnections-") + + TRI=MUA.connectivity; + G=graph(TRI,TRI(:,[2 3 1])); + + + + % FindOrCreateFigure("Graph") ; plot(G) + + + % calculate the connected components of the graph + [bin,binsize]=conncomp(G) ; + % size of bin is equal length to the number of nodes + % bin(i) is the bin number to which node i belongs + + BinSizeSorted=sort(binsize,'descend') ; + + if numel(BinSizeSorted) > CtrlVar.MaxNumberOfIslands + MinNodesPerIsland=max(BinSizeSorted(CtrlVar.MaxNumberOfIslands),CtrlVar.MinNumberOfNodesPerIslands) ; + else + MinNodesPerIsland=CtrlVar.MinNumberOfNodesPerIslands ; + end + + idx= binsize(bin) >= MinNodesPerIsland; + + % idx = binsize(bin) == max(binsize); + nodes=find(~idx); % all nodes not belonging to the subgraph with the largest number of nodes + + ElementsToBeDeleted=AllElementsContainingGivenNodes(MUA.connectivity,nodes) ; + + Islands.Free=ElementsToBeDeleted ; + Islands.OneNode=[]; + + NumberOfElementsNotConnectedToTheMainMesh=numel(find(Islands.Free)) ; + fprintf("Number of elements not connected to the main mesh %i \n",NumberOfElementsNotConnectedToTheMainMesh) + +else + + + % 2) Get rid of elements only connected by one node, or less, to the main part of the mesh + % + % The key idea is to identify boundary nodes that appear twice or more. At those node the freeBoundary of the triangulation + % `crosses over'. Each such node is then split up in several new nodes by giving new nodal labels to the duplicates (keeping + % the first instance unchanged). This changes the topology of the mesh. Only the connectivity is affected, not the + % coordinates. The effect is that the mesh, as a graph, is now split up at this node. A graph is created for this new + % connectivity and islands detected in the usual way. + % + % Note that this will always include all the original islands as well. So if we want to get rid of all islands and all small + % regions connected by just one node to the remaining part, we only need to to this step. + % + % Within MUA we have the field + % + % MUA.Boundary.EdgeCornerNodes + % + % which is calculated as + % + % TR=CreateFEmeshTriRep(connectivity,coordinates); Boundary.Edges=freeBoundary(TR) ; + % Boundary.EdgeCornerNodes=Boundary.Edges(:,1); + % + % Find boundary node that appears more than once along the boundary edges + + % Find duplicates + + if isempty(MUA.Boundary) + %[MUA.Boundary,MUA.TR]=FindBoundary(MUA.connectivity,MUA.coordinates); + MUA.TR=CreateFEmeshTriRep(MUA.connectivity,MUA.coordinates); + MUA.Boundary.Edges=freeBoundary(MUA.TR) ; % misses the interior nodes for higher order tri + MUA.Boundary.EdgeCornerNodes=MUA.Boundary.Edges(:,1); + end + + V=MUA.Boundary.EdgeCornerNodes ; + sV=sort(V) ; + BoundaryNodeDuplicates=unique(sV(diff(sV)==0)) ; + + % Replace each occurrence of those duplicates with new node numbers + + + TempConnectivity=MUA.connectivity ; + NodeMax=MUA.Nnodes; + for I=1:numel(BoundaryNodeDuplicates) + + ind=find(TempConnectivity==BoundaryNodeDuplicates(I)) ; + ind=ind(2:end) ; % do not relabel the first instance of the node + n=numel(ind); + + NewNodeLables=(1:n)+NodeMax ; + TempConnectivity(ind)=NewNodeLables; + NodeMax=NodeMax+n; + + % I only need this for plotting purposes + %for J=1:numel(NewNodeLables) + % MUA.coordinates(NewNodeLables(J),:)=MUA.coordinates(BoundaryNodeDuplicates(I),:); + %end + + end + + % Now the connectivity has changed, but the number of elements is the same + + + G=graph(TempConnectivity,TempConnectivity(:,[2 3 1])); + + + % FindOrCreateFigure("Graph 2") ; plot(G) + + [bin,binsize]=conncomp(G) ; + + + BinSizeSorted=sort(binsize,'descend') ; + + if numel(BinSizeSorted) > CtrlVar.MaxNumberOfIslands + MinNodesPerIsland=max(BinSizeSorted(CtrlVar.MaxNumberOfIslands),CtrlVar.MinNumberOfNodesPerIslands) ; + else + MinNodesPerIsland=CtrlVar.MinNumberOfNodesPerIslands ; + end + + idx= binsize(bin) >= MinNodesPerIsland; + + % idx = binsize(bin) == max(binsize); + nodes=find(~idx); % all nodes not belonging to the subgraph with the largest number of nodes + + + FurtherElementsToBeDeleted=AllElementsContainingGivenNodes(TempConnectivity,nodes) ; + + Islands.Free=[]; + Islands.OneNode=FurtherElementsToBeDeleted ; + + NumberOfElementsConnectedToTheMainMeshByJustOneNode=numel(find(Islands.OneNode)) ; + fprintf("Number of elements connected to the main mesh by just one node %i \n",NumberOfElementsConnectedToTheMainMeshByJustOneNode) + + % Since the element labels and number of elements is the same, I can now simply use the original MUA + + %% + +end + + +if CtrlVar.InfoLevelAdaptiveMeshing>=10 && CtrlVar.doplots + + if NumberOfElementsConnectedToTheMainMeshByJustOneNode>0 || NumberOfElementsNotConnectedToTheMainMesh> 0 + FindOrCreateFigure("Islands") ; + CtrlVar.PlotNodalLabels=0; + PlotMuaMesh(CtrlVar,MUA); + hold on + PlotMuaMesh(CtrlVar,MUA,Islands.Free,color="r",LineWidth=2); + PlotMuaMesh(CtrlVar,MUA,Islands.OneNode,color="b",LineStyle="--",LineWidth=2); + title("Islands (red) and one-node or less connection (blue)") + end + +end + + +end + +%% \ No newline at end of file diff --git a/MapFbetweenMeshes.m b/MapFbetweenMeshes.m index 938529a9..9559477e 100755 --- a/MapFbetweenMeshes.m +++ b/MapFbetweenMeshes.m @@ -1,6 +1,6 @@ function [UserVar,RunInfo,Fnew,BCsNew,lnew]=MapFbetweenMeshes(UserVar,RunInfo,CtrlVar,MUAold,MUAnew,Fold,BCsOld,lold,OutsideValue) -% �a + narginchk(8,9) diff --git a/MapNodalVariablesFromMesh1ToMesh2UsingShapeAndScattered.m b/MapNodalVariablesFromMesh1ToMesh2UsingShapeAndScattered.m index be296725..3fe38d72 100755 --- a/MapNodalVariablesFromMesh1ToMesh2UsingShapeAndScattered.m +++ b/MapNodalVariablesFromMesh1ToMesh2UsingShapeAndScattered.m @@ -165,10 +165,10 @@ tt=axis; hold off - p0=PlotMuaMesh(CtrlVar,MUAnew,[],'b'); + p0=PlotMuaMesh(CtrlVar,MUAnew,nan,'b'); hold on - p1=PlotMuaMesh(CtrlVar,MUAold,[],'k'); + p1=PlotMuaMesh(CtrlVar,MUAold,nan,'k'); if ~isequal(tt,[0 1 0 1]) axis(tt) end @@ -184,16 +184,19 @@ elseif ~isempty(p2) legend([p0 p1 p2 p4],'New Mesh','Old Mesh','New and outside','Identical','Location','northeastoutside') end - - + + axis equal hold off - - + + % fprintf('#Outside=%i \t #Inside and not same=%i \n',numel(NodesOutside),numel(NodesInsideAndNotSame)) - FigTitle=sprintf(' #Nodes in new mesh=%i \t #Nodes in old mesh=%i \t \n #Same Nodes=%i \t #~Same Nodes=%i \t #Nodes inside and new=%i \t #Outside nodes=%i ',... - nNewNodes,nOldNodes,nIdenticalNodes,nNotIdendicalNodes,numel(NodesInsideAndNotSame),numel(NodesOutside)) ; - title(FigTitle) + + FigTitle=sprintf("Nodes in new mesh=%i, Nodes in old mesh=%i",nNewNodes,nOldNodes) ; + + FigSubTitle=sprintf("Same Nodes=%i, Not same Nodes=%i, Nodes inside and new=%i, Nodes outside=%i ",nIdenticalNodes,nNotIdendicalNodes,numel(NodesInsideAndNotSame),numel(NodesOutside)) ; + title(FigTitle,Interpreter="latex") + subtitle(FigSubTitle,Interpreter="latex") end %% Form-function interpolation for inside nodes diff --git a/MassContinuityEquationNewtonRaphson.m b/MassContinuityEquationNewtonRaphson.m index 46e5d31c..718538e7 100644 --- a/MassContinuityEquationNewtonRaphson.m +++ b/MassContinuityEquationNewtonRaphson.m @@ -151,7 +151,7 @@ Lower=-0.5 ; if gamma>0.7*Upper ; Upper=2*gamma; end parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:genericError'); - parfor I=1:nnn + for I=1:nnn gammaTest=(Upper-Lower)*(I-1)/(nnn-1)+Lower [rTest,~,~,rForceTest,rWorkTest,D2Test]=Func(gammaTest); gammaTestVector(I)=gammaTest ; rForceTestvector(I)=rForceTest; rWorkTestvector(I)=rWorkTest; rD2Testvector(I)=D2Test; diff --git a/Matern.m b/Matern.m index 3fe4b6d6..10fcc537 100755 --- a/Matern.m +++ b/Matern.m @@ -1,3 +1,9 @@ + + + + + + function [r,nu,kappa,sigma2Helmholtz,Cov,Realisation]=Matern(alpha,rho,d,x,sigma2,DoPlots) %% @@ -67,17 +73,18 @@ Cov=[] ; Realisation=[] ; % this gives a correlation of about 0.1 at the distance r -nu=alpha-d/2; % ie nu=1 for alpha=2 and dimention=2 +nu=alpha-d/2; % ie nu=1 for alpha=2 and dimension=2 kappa=sqrt(8*nu)/rho; sigma2Helmholtz=gamma(nu) / ( gamma(nu+d/2)*(4*pi)^(d/2)*kappa^(2*nu)); -if nargin<5 +if nargin<5 || isempty(sigma2) % Eq 1 sigma2=sigma2Helmholtz ; end +dist=x ; % for plotting purposes x=kappa * x ; % this sigma2 should be referred to as sigma^2 @@ -87,8 +94,16 @@ % My notation is based on: % Lindgren, F., Rue, H., & Lindström, J. (2011). % An explicit link between Gaussian fields and Gaussian Markov random fields: the stochastic partial differential equation approach. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 73(4), 423–498. https://doi.org/10.1111/j.1467-9868.2011.00777.x + r = real(sigma2 * x.^nu .* besselk(nu,x) / (2^(nu-1)*gamma(nu)) ); +% the expression above for r fails for x=0, although the limit x^nu beselk(nu,x) for x to 0 is well defined, in fact +% +% lim x to 0 of x^nu besselk(nu,x) = 1 +% + +Ix0=x==0 ; +r(Ix0) = real(sigma2 / (2^(nu-1)*gamma(nu)) ); %% @@ -105,7 +120,7 @@ figure; for I=1:3 y=R*randn(numel(x),1) ; - plot(x/1000,y) ; ylabel('Matern realisation') ; xlabel('distance (km)') + plot(dist/1000,y) ; ylabel('Matern realisation') ; xlabel('distance (km)') hold on fprintf(' Expected variance %f \t estimated variance %f \n ',sigma2,var(y)) end diff --git a/Mesh2d/refine2.m b/Mesh2d/refine2.m index f110dbee..63a9b4bb 100755 --- a/Mesh2d/refine2.m +++ b/Mesh2d/refine2.m @@ -1090,13 +1090,20 @@ tcpu.filt + toc(ttic) ; %------------------------------------- split constraints - idx1 = ... - (1:size(new1))'+size(vert,1) ; + % idx1 = ... + % (1:size(new1))'+size(vert,1) ; % 2024a not happy about this, I think this should be changed to (1:size(new1,1))'+size(vert,1) ; + % + % idx2 = ... + % (1:size(new2))'+size(new1,1) ... + % +size(vert,1) ; + % + idx1 = ... + (1:size(new1,1))'+size(vert,1) ; % 2024a not happy about this, I think this should be changed to (1:size(new1,1))'+size(vert,1) ; idx2 = ... - (1:size(new2))'+size(new1,1) ... + (1:size(new2,1))'+size(new1,1) ... +size(vert,1) ; - + cnew = [conn( ref1,1), idx1 conn( ref1,2), idx1]; conn = [conn(~ref1,:); cnew]; diff --git a/NewDesiredEleSizesAndElementsToRefineOrCoarsen2.m b/NewDesiredEleSizesAndElementsToRefineOrCoarsen2.m index 24bd15bb..60be7865 100755 --- a/NewDesiredEleSizesAndElementsToRefineOrCoarsen2.m +++ b/NewDesiredEleSizesAndElementsToRefineOrCoarsen2.m @@ -5,6 +5,7 @@ % Estimates optimal element sizes based on number of explicit error estimators % The estimates are given at the nodal points of the current FE mesh % + % Scales element sizes to fit within the range of CtrlVar.MeshSizeMin to CtrlVar.MeshSizeMax % @@ -12,9 +13,10 @@ % Calculate current element sizes EleArea=TriAreaFE(MUA.coordinates,MUA.connectivity); + M= Ele2Nodes(MUA.connectivity,MUA.Nnodes); EleSizeCurrent=sqrt(M*EleArea); % Elesizes around nodes - + xNod=MUA.coordinates(:,1) ; yNod=MUA.coordinates(:,2); @@ -72,6 +74,7 @@ u=F.ub+F.ud ; v=F.vb+F.vd; if (RunInfo.MeshAdapt.isChanged && ~isCalculated) || (all(u==0) && all(v==0)) + [UserVar,RunInfo,F,l,~,Ruv,Lubvb]= uv(UserVar,RunInfo,CtrlVar,MUA,BCs,F,l); isCalculated=true; RunInfo.Forward.ubvbRecalculatedOnNewMesh=isCalculated; @@ -387,7 +390,7 @@ clf(fig) CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; - PlotMuaMesh(CtrlVar,MUA,[],'k'); + PlotMuaMesh(CtrlVar,MUA,nan,'k'); hold on PlotMuaMesh(CtrlVar,MUA,ElementsToBeRefined,'b'); PlotMuaMesh(CtrlVar,MUA,ElementsToBeCoarsened,'r'); diff --git a/PlotReactions.m b/PlotReactions.m index 8369d473..7e41e345 100755 --- a/PlotReactions.m +++ b/PlotReactions.m @@ -1,42 +1,55 @@ -function PlotReactions(CtrlVar,MUA,Reactions) +function PlotReactions(CtrlVar,MUA,F,Reactions) +narginchk(4,4) % % To calculate Reactions, use CalculateReactions.m -% +% x=MUA.coordinates(:,1); y=MUA.coordinates(:,2); Two= numel(Reactions.ubvb)>0 && numel(Reactions.h)>0; if numel(Reactions.ubvb)>0 - + if Two - subplot(1,2,1) + subplot(1,2,1) end - PlotFEmesh(MUA.coordinates,MUA.connectivity,CtrlVar) ; + PlotFEmesh(MUA.coordinates,MUA.connectivity,CtrlVar) ; QuiverColorGHG(x,y,Reactions.ubvb(1:MUA.Nnodes),Reactions.ubvb(MUA.Nnodes+1:end),CtrlVar); - title('uv Reactions') ; + title('uv Reactions') ; end if numel(Reactions.h)>0 - + if Two subplot(1,2,2) - PlotFEmesh(MUA.coordinates,MUA.connectivity,CtrlVar) ; - axis tight end - + PlotFEmesh(MUA.coordinates,MUA.connectivity,CtrlVar) ; + axis tight + + [AreaTri]=TriAreaFE(MUA.coordinates,MUA.connectivity); - Reactions.h= 3*Reactions.h*min(AreaTri)/max(abs(Reactions.h))/CtrlVar.PlotXYscale^2; - - I=Reactions.h>0; scatter(x(I)/CtrlVar.PlotXYscale,y(I)/CtrlVar.PlotXYscale,Reactions.h(I),'b','d','filled') - I=Reactions.h<0; scatter(x(I)/CtrlVar.PlotXYscale,y(I)/CtrlVar.PlotXYscale,-Reactions.h(I),'r','c','filled') - title('h Reactions') ; + Rh= 3*Reactions.h*min(AreaTri)/max(abs(Reactions.h))/CtrlVar.PlotXYscale^2; + + I=Rh>0; scatter(x(I)/CtrlVar.PlotXYscale,y(I)/CtrlVar.PlotXYscale,Rh(I),'b','d','filled') + I=Rh<0; scatter(x(I)/CtrlVar.PlotXYscale,y(I)/CtrlVar.PlotXYscale,-Rh(I),'r','c','filled') + title("$h$-reactions",Interpreter="latex") ; + subtitle("negative reactions in red, positive in blue",interpreter="latex") + + + if nargin> 3 + ah=Reactions.h./F.rho/F.dt; + UaPlots(CtrlVar,MUA,F,ah,FigureTitle=" Reactions.h/(F.rho F.dt) Reactions ") + title("$h$-reactions/($\rho \, \Delta t)$",Interpreter="latex") ; + subtitle(sprintf("t=%g",F.time),Interpreter="latex") ; + + end + end -xlabel(CtrlVar.PlotsXaxisLabel) ; ylabel(CtrlVar.PlotsYaxisLabel); +xlabel(CtrlVar.PlotsXaxisLabel) ; ylabel(CtrlVar.PlotsYaxisLabel); end \ No newline at end of file diff --git a/PrintInfoAboutElementsSizes.m b/PrintInfoAboutElementsSizes.m index 7863d8aa..585af4af 100755 --- a/PrintInfoAboutElementsSizes.m +++ b/PrintInfoAboutElementsSizes.m @@ -1,16 +1,41 @@ -function [Emin,Emax,Emean,Emedian]=PrintInfoAboutElementsSizes(CtrlVar,MUA,options) +function [Emin,Emax,Emean,Emedian,Tlength]=PrintInfoAboutElementsSizes(CtrlVar,MUA,options) +%% +% +% Calculates equivalent element lengths +% +% Equivalent length can be defined in two ways: +% +% # as the leg of an isosceles right triangle with the same area as the triangular element, or +% # as the length of a perfect square that has the same area as the triangular element. +% +% Option 1) is the default, however after some thought it now feels to me that option 2) should be the default. +% +% +% Example: +% +% [Emin,Emax,Emean,Emedian]=PrintInfoAboutElementsSizes(CtrlVar,MUA,print=true,plot=true,LengthMeasure="-side of a perfect square of equal area-"); +% +%% arguments CtrlVar struct MUA struct options.print logical = true ; - + options.LengthMeasure string="-leg of an isosceles right triangle-" ; % "-side of a perfect square of equal area-"; + options.plot logical = false ; end Tarea=TriAreaFE(MUA.coordinates,MUA.connectivity); -Tlength=sqrt(2*Tarea) ; + +if options.LengthMeasure=="-side of a perfect square of equal area-" + Tlength=sqrt(Tarea) ; % this is the length of the sides of a perfect square of equal area. +else + Tlength=sqrt(2*Tarea) ; % Default option: this is the length of the legs of an isosceles right triangle. +end + + Emax=max(Tlength); Emean=mean(Tlength); @@ -23,4 +48,40 @@ MUA.Nele,MUA.nod,MUA.Nnodes,Emax,Emean,Emedian,Emin); end +if options.plot + + cbar=UaPlots(CtrlVar,MUA,[],Tlength/CtrlVar.PlotXYscale) ; + title(cbar,"$l$",Interpreter="latex") + title("Equivalent element lengths",Interpreter="latex") + + if CtrlVar.PlotXYscale~=1 + + StAdd="(/"+num2str(CtrlVar.PlotXYscale)+")" ; + title(cbar,["$l$",StAdd],Interpreter="latex") + title("Equivalent element lengths "+StAdd,Interpreter="latex") + + + end + + + FindOrCreateFigure("histogram of element sizes") + histogram(Tlength/CtrlVar.PlotXYscale) + + title("Histogram of element sizes",Interpreter="latex") + + + xlabel("Effective element size",Interpreter="latex") + ylabel("Number of elements",Interpreter="latex") + + if CtrlVar.PlotXYscale~=1 + + StAdd="(/"+num2str(CtrlVar.PlotXYscale)+")" ; + title("Histogram of element sizes "+StAdd,Interpreter="latex") + xlabel("Effective element size "+StAdd,Interpreter="latex") + + end + +end + + end diff --git a/PriorProbabilityDistribution.m b/PriorProbabilityDistribution.m index e1d54352..afe4b0b6 100755 --- a/PriorProbabilityDistribution.m +++ b/PriorProbabilityDistribution.m @@ -16,6 +16,7 @@ n=[]; q=[]; muk=[]; + V0=[]; AGlen=[]; CovAGlen=[] diff --git a/QuadratureRuleDegree.m b/QuadratureRuleDegree.m index 7640a72e..6d8b6d96 100644 --- a/QuadratureRuleDegree.m +++ b/QuadratureRuleDegree.m @@ -13,6 +13,7 @@ case 3 Degree=4; + Degree=25; case 6 @@ -20,10 +21,12 @@ Degree=8; % Degree=12; % Degree=20; + % Degree=25; case 10 Degree=8 ; + % Degree=25; otherwise diff --git a/QuiverColorGHG.m b/QuiverColorGHG.m index b5b84e45..c6bc7ef5 100755 --- a/QuiverColorGHG.m +++ b/QuiverColorGHG.m @@ -7,7 +7,7 @@ % [cbar,QuiverHandel,Par]=QuiverColorGHG(x,y,u,v,Par,varargin) % % x , y , u , v : vectors of same length. But if using regular velocity grid, x and y can -% be grid vectors. (In matlab speak grid vectors xg and yg are a set of vectors that serve +% be grid vectors. (In MATLAB speak grid vectors xg and yg are a set of vectors that serve % as a compact representation of a grid in ndgrid format. For example, [X,Y] = % ndgrid(xg,yg) ) % @@ -34,12 +34,12 @@ % Default is min(speed(:)). % However, if using log10 the minimum plotted speed is never smaller than 10^QshouldiverColorPowRange times MaxPlottedSpeed % Par.SpeedTickLabels : numerical array of values -% Par.QuiverColorPowRange : when using log10 velocity bar, this is the greates possible range of magnitudes shown in colobar. +% Par.QuiverColorPowRange : when using log10 velocity bar, this is the creates possible range of magnitudes shown in colobar. % Default is % Par.QuiverColorPowRange=3, i.e. % the smallest colored speed is % 10^3 smaller than the largest speed -% Par.QuiverSameVelocityScalingsAsBefore : set to true (ie 1) to get same velocity scalings as in previous call. +% Par.QuiverSameVelocityScalingsAsBefore : set to true (ie 1) to get same velocity scaling as in previous call. % % % varargin is passed on to quiver @@ -50,7 +50,7 @@ % load('CrackRestartfileExample.mat','CtrlVarInRestartFile','MUA','F','BCs','GF') % QuiverColorGHG(MUA.coordinates(:,1),MUA.coordinates(:,2),F.ub,F.vb); % -% Plot all velocites with arrows of equal length: +% Plot all velocities with arrows of equal length: % % load('CrackRestartfileExample.mat','CtrlVarInRestartFile','MUA','F','BCs','GF') % CtrlVar=CtrlVarInRestartFile; @@ -97,12 +97,12 @@ % % Two calls with same velocity scaling: % -% [cbar,~,Par]=QuiverColorGHG(x,y,u,v,Par) ; % first call, here Par is not strickly needed as an input +% [cbar,~,Par]=QuiverColorGHG(x,y,u,v,Par) ; % first call, here Par is not strictly needed as an input % Par.QuiverSameVelocityScalingsAsBefore=1; -% QuiverColorGHG(x,y,u,v,Par) ; % second call uses same scalings as previous one +% QuiverColorGHG(x,y,u,v,Par) ; % second call uses same scaling as previous one % % -% Note: When doing further contour plots on top of velocity plot, matlab will possibly change the +% Note: When doing further contour plots on top of velocity plot, MATLAB will possibly change the % limits of the colorbar and the position of the ticklables will no longer be correct. % If this happens then reset range and ticks, for example: % @@ -438,7 +438,7 @@ I=speed>Par.SpeedPlotIntervals(J) & speed <= Par.SpeedPlotIntervals(J+1) & speed>Par.MinSpeedToPlot; end - if numel(x(I))>0 % This should not really be needed, but veving resulting figures in matlab fig format + if numel(x(I))>0 % This should not really be needed, but % results in errors in Matlab2016a QuiverHandel=quiver(x(I)/Par.PlotXYscale,y(I)/Par.PlotXYscale,uplot(I),vplot(I),0,... 'color',Par.QuiverCmap(J,:),varargin{:}) ; hold on @@ -462,7 +462,7 @@ tickpos=1+N*log10(ticklabel)/log10(Par.SpeedPlotIntervals(N+1)); set(cbar,'Ytick',tickpos,'YTicklabel',ticklabel); else - caxis([0 max(Par.SpeedPlotIntervals)]); + clim([0 max(Par.SpeedPlotIntervals)]); end diff --git a/ReleaseNotes.m b/ReleaseNotes.m index 6ede1d44..e7d88409 100644 --- a/ReleaseNotes.m +++ b/ReleaseNotes.m @@ -2,8 +2,37 @@ %% % +% *Release Notes* _March 2024_ % +% Positive thickness constraints --- added dynamically when using the active-set option --- are not added to nodes already +% contained in a user-defined constraint. Hence, any user-defined thickness constraints are respected, even if this means +% that some thickness go below the minimum specified thickness. Previously, thickness constraints were added to all nodes +% with thickness less than CtrlVar.ThicMin. % +% +% +% *Release Notes* _February 2024_ +% +% Parallel spmd assembly option now improved and shows good scalability, although speedup always somewhat problem dependent. +% On local workstations with 12 workers, speedup ranging from 6 to 10 seems easily obtainable, and on machines with 24 workers a +% speedup of 20 has been observed. +% +% To switch on the smpd parallel assembly do: +% +% CtrlVar.Parallel.uvhAssembly.spmd.isOn=true; % assembly in parallel using spmd over sub-domain (domain decomposition) +% CtrlVar.Parallel.uvAssembly.spmd.isOn=true; % assembly in parallel using spmd over sub-domain (domain decomposition) +% +% +% The linear system can now also be solved using distributed arrays, although not all cases yet implemented. Turn this on/off as: +% +% CtrlVar.Parallel.Distribute=true/false; % linear system is solved using distributed arrays. +% +% Again, the speedup is problem dependent and never particularly large for low density sparse matrices as typically generated +% by Ua and other FE programs. +% +% CtrlVar.Parallel.isTest=false/true; % Runs both with and without parallel approach, and prints out some information on relative performance. +% % Good for testing if switching on the parallel options speeds things up, and by how much. +% % *Release Notes* _October 2023_ % % A (rare) case where the Cauchy direction is not a direction of descent was incorrectly updated. This has now been addressed. @@ -16,7 +45,7 @@ % % *Release Notes* _July 2023_ % -% * uv and uvh solver now uses dog-leg seach if Newton back-tracking results in small steps. +% * uv and uvh solver now uses dog-leg search if Newton back-tracking results in small steps. % % * Thanks to Sainan Sun for spotting that in an adaptive mesh step, call to calving was ahead of call to geometry and % densities. This has now been corrected. @@ -30,11 +59,11 @@ % % are set to true. % -% * Calving options have been greaty improved and a flexible framework for implementing calving laws implemented. Although -% still considered not fully testet, this option appears to work quite well. Further details can be found in +% * Calving options have been greatly improved and a flexible framework for implementing calving laws implemented. Although +% still considered not fully tested, this option appears to work quite well. Further details can be found in % Ua2D_DefaultParameters.m and in the DefineCalving.m files. % -% * In the active-set method a minimum number of new active nodes can be specifed for the active set to be updated ahead of a +% * In the active-set method a minimum number of new active nodes can be specified for the active set to be updated ahead of a % new uvh solve, e.g.: % % CtrlVar.MinNumberOfNewlyIntroducedActiveThicknessConstraints=5; @@ -58,7 +87,7 @@ % % The ice-free areas are automatically melted away using a mass-balance feedback % option implemented at the integration points. Second-order NR convergence is -% obtained even if the reulting mass balance distribution varies sigificantly +% obtained even if the resulting mass balance distribution varies significantly % spatially within an element % % To use this calving option set: @@ -133,8 +162,8 @@ % % DefineGeometryAndDensities.m % -% The previous approach of using seperate m-files to define geometry -% (DefineGeometry.m) and densitites (DefineDensities.m) still works. But if you +% The previous approach of using separate m-files to define geometry +% (DefineGeometry.m) and densities (DefineDensities.m) still works. But if you % have a "DefineGeometryAndDensities.m" in the run folder, only % "DefineGeometryAndDensities.m" is used and "DefineGeometry.m" and % "DefineDensities.m" ignored. @@ -154,9 +183,9 @@ % % plot(F.x.F,s,'.') % -% * Default inverse algorithim has changed. Now the defaul options is a +% * Default inverse algorithm has changed. Now the default options is a % Hessian-based inversion. The older-approach is still available by selecting a -% Gradien-based inversion. This is specificed using the CtrlVar field: +% Gradient-based inversion. This is specified using the CtrlVar field: % % CtrlVar.Inverse.MinimisationMethod % @@ -166,7 +195,7 @@ % % and this field is not used. % -% * Ocean and wind-indued drag over floating ice can be included. This is defined in +% * Ocean and wind-induced drag over floating ice can be included. This is defined in % % DefineSeaIceParameters.m % @@ -188,7 +217,7 @@ % * The shallow-ice sheet (SIA/SSHEET) option now includes basal sliding. % % The SSHEET option is implemented for the Weertman sliding law only. The transient SSHEET solution is done implicitly with respect to -% the thickneess using the NR method. When using SSHEET you will, in general, need to specify boundary conditions for both the +% the thickness using the NR method. When using SSHEET you will, in general, need to specify boundary conditions for both the % deformational and the basal sliding velocities. Note the SSHEET option is based on the shallow-ice approximation. % % *Release Notes* @@ -278,7 +307,7 @@ % _February 2020_ % % -% * �a can now be called with CtrlVar as second argument, e.g +% * Úa can now be called with CtrlVar as second argument, e.g % % Ua([],CtrlVar) % @@ -303,10 +332,10 @@ % potential violation of mass conservation. However, this also ensures smooth upper % surfaces even when refining mesh over areas with very uneven bedrock topography. % -% * Inversion can be done using all implemented sliding laws except Coulumb. +% * Inversion can be done using all implemented sliding laws except Coulomb. % % -% * u, v and h residuals now calulated in the L2 norm instead of the l2 norm as in the +% * u, v and h residuals now calculated in the L2 norm instead of the l2 norm as in the % past. % % *New user input file options:* diff --git a/RemoveSomeUnwantedCharactersFromString.m b/RemoveSomeUnwantedCharactersFromString.m new file mode 100755 index 00000000..04190dd8 --- /dev/null +++ b/RemoveSomeUnwantedCharactersFromString.m @@ -0,0 +1,15 @@ +function OutputString=RemoveSomeUnwantedCharactersFromString(InputString) + +OutputString=InputString; + +OutputString=replace(OutputString,"---","-"); +OutputString=replace(OutputString,"--","-"); +OutputString=replace(OutputString,"\-","\"); +OutputString=replace(OutputString,"/-","/"); + + + + + + +end \ No newline at end of file diff --git a/SSHEET_TransientImplicit.m b/SSHEET_TransientImplicit.m index 7ea46089..c26eb8d2 100755 --- a/SSHEET_TransientImplicit.m +++ b/SSHEET_TransientImplicit.m @@ -184,7 +184,7 @@ Up=2; if gamma>0.7*Up ; Up=2*gamma; end - parfor I=1:nnn + for I=1:nnn gammaTest=Up*(I-1)/(nnn-1)+gamma/1000; [rTest,~,~,rForceTest,rWorkTest,D2Test]=Func(gammaTest); gammaTestVector(I)=gammaTest ; rForceTestvector(I)=rForceTest; rWorkTestvector(I)=rWorkTest; rD2Testvector(I)=D2Test; diff --git a/SSTREAM2dNR2.m b/SSTREAM2dNR2.m index 28f006e3..722c1a08 100755 --- a/SSTREAM2dNR2.m +++ b/SSTREAM2dNR2.m @@ -1,4 +1,8 @@ -function [UserVar,F,l,Kuv,Ruv,RunInfo,L]=SSTREAM2dNR2(UserVar,CtrlVar,MUA,BCs,F,l,RunInfo) +% function [UserVar,F,l,Kuv,Ruv,RunInfo,L]=SSTREAM2dNR2(UserVar,CtrlVar,MUA,BCs,F,l,RunInfo) + + + +function [UserVar,RunInfo,F,l,Kuv,Ruv,L]=SSTREAM2dNR2(UserVar,RunInfo,CtrlVar,MUA,BCs,F,l) % Solves SSA/SSTREAM for u and v @@ -12,6 +16,7 @@ RunInfo.Forward.uvConverged=1; + if isempty(CtrlVar.CurrentRunStepNumber) || CtrlVar.CurrentRunStepNumber==0 CtrlVar.CurrentRunStepNumber=1; end @@ -94,7 +99,7 @@ % - %% Make sure iterate is feasable + %% Make sure iterate is feasible F.ub(BCs.ubFixedNode)=BCs.ubFixedValue; F.vb(BCs.vbFixedNode)=BCs.vbFixedValue; %% @@ -113,10 +118,10 @@ - - fext0=KRTFgeneralBCs(CtrlVar,MUA,F,true); % RHS with velocities set to zero, i.e. only external forces - - %% New normalisation idea, 10 April 2023 + CtrlVar.uvAssembly.ZeroFields=true; CtrlVar.uvMatrixAssembly.Ronly=true ; + % fext0=KRTFgeneralBCs(CtrlVar,MUA,F); % RHS with velocities set to zero, i.e. only external forces + [RunInfo,fext0]=uvMatrixAssembly(RunInfo,CtrlVar,MUA,F,BCs); % RHS with velocities set to zero, i.e. only external forces + %% New normalization idea, 10 April 2023 % set (ub,vb) to zero, except where BCs imply otherwise, ie make the iterate feasable % then calculate the const function for this value and use as normalisation % gamma=0; fext0=1; @@ -129,9 +134,10 @@ %% - - Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); % RHS with calculated velocities, i.e. difference between external and internal forces - + CtrlVar.uvAssembly.ZeroFields=false; CtrlVar.uvMatrixAssembly.Ronly=true ; + % Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); + [RunInfo,Ruv]=uvMatrixAssembly(RunInfo,CtrlVar,MUA,F,BCs); % RHS with calculated velocities, i.e. difference between external and internal forces + RunInfo.CPU.Solution.uv=0; @@ -144,7 +150,7 @@ rWork=0 ; % I set rWork to zero to disable it as initial criterion gamma=1; - iteration=0; ResidualReduction=1e10; RunInfo.CPU.solution.uv=0 ; RunInfo.CPU.Assembly.uv=0; + iteration=0; ResidualReduction=1e10; BackTrackInfo.iarm=nan; while true @@ -189,17 +195,24 @@ %% Newton step % If I want to use the Newton Decrement (work) criterion I must calculate the Newton % step ahead of the cost function + + CtrlVar.NRuvIncomplete=0; if rem(iteration-1,CtrlVar.ModifiedNRuvIntervalCriterion)==0 || ResidualReduction> CtrlVar.ModifiedNRuvReductionCriterion - tAssembly=tic; - [Ruv,Kuv]=KRTFgeneralBCs(CtrlVar,MUA,F); - RunInfo.CPU.Assembly.uv=toc(tAssembly)+RunInfo.CPU.Assembly.uv; - NRincomplete=0; + + CtrlVar.uvAssembly.ZeroFields=false; CtrlVar.uvMatrixAssembly.Ronly=false; + % [Ruv,Kuv,~,~]=KRTFgeneralBCs(CtrlVar,MUA,F); + [RunInfo,Ruv,Kuv]=uvMatrixAssembly(RunInfo,CtrlVar,MUA,F,BCs); + dAtilde=[]; + else - tAssembly=tic; - Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); - RunInfo.CPU.Assembly.uv=toc(tAssembly)+RunInfo.CPU.Assembly.uv; - NRincomplete=1; + + CtrlVar.uvAssembly.ZeroFields=false; CtrlVar.uvMatrixAssembly.Ronly=1; + % Ruv=KRTFgeneralBCs(CtrlVar,MUA,F); + [RunInfo,Ruv]=uvMatrixAssembly(RunInfo,CtrlVar,MUA,F,BCs); + + CtrlVar.NRuvIncomplete=1; + end @@ -232,9 +245,9 @@ tSolution=tic; if CtrlVar.Solver.isUpperLeftBlockMatrixSymmetrical - [sol,dl]=solveKApeSymmetric(Kuv,L,frhs,grhs,[dub;dvb],dl,CtrlVar); + [sol,dl,dAtilde]=solveKApeSymmetric(Kuv,L,frhs,grhs,[dub;dvb],dl,CtrlVar,dAtilde); else - [sol,dl]=solveKApe(Kuv,L,frhs,grhs,[dub;dvb],dl,CtrlVar); + [sol,dl,dAtilde]=solveKApe(Kuv,L,frhs,grhs,[dub;dvb],dl,CtrlVar,dAtilde); end RunInfo.CPU.Solution.uv=toc(tSolution)+RunInfo.CPU.Solution.uv; @@ -329,7 +342,7 @@ Up=2; if gamma>0.7*Up ; Up=2*gamma; end - parfor I=1:nnn + for I=1:nnn gammaTest=Up*(I-1)/(nnn-1)+gamma/1000; [rTest,~,~,rForceTest,rWorkTest,D2Test]=Func(gammaTest); gammaTestVector(I)=gammaTest ; rForceTestvector(I)=rForceTest; rWorkTestvector(I)=rWorkTest; rD2Testvector(I)=D2Test; @@ -365,7 +378,7 @@ PlotForceResidualVectors2(CtrlVar,MUA,F,'uv',Ruv,L,l.ubvb,iteration); end - if NRincomplete + if CtrlVar.NRuvIncomplete stri='i'; else stri=[]; @@ -385,7 +398,7 @@ end - if CtrlVar.InfoLevelNonLinIt>=10 && iteration >= 2 && CtrlVar.doplots==1 + if CtrlVar.InfoLevelNonLinIt>=5 && iteration >= 2 && CtrlVar.doplots==1 figruv=FindOrCreateFigure("NR-uv r"); clf(figruv) ; diff --git a/SSTREAM_TransientImplicit.m b/SSTREAM_TransientImplicit.m index 272ae2c6..bd445c52 100755 --- a/SSTREAM_TransientImplicit.m +++ b/SSTREAM_TransientImplicit.m @@ -31,7 +31,7 @@ % % All matrices are Nnodes x Nnodes, apart from: % Luv is #uv constraints x 2 Nnodes, i.e. Luv [u;v]= cuv - % Lh is # h contraints x Nnodes, i.e. Lh h= ch + % Lh is # h constraints x Nnodes, i.e. Lh h= ch % or % % [K L'] [ duvh ] = [ -R- L' l ] @@ -73,7 +73,7 @@ [F1.b,F1.s,F1.h,F1.GF]=Calc_bs_From_hBS(CtrlVar,MUA,F1.h,F1.S,F1.B,F1.rho,F1.rhow); % make sure that if any extrapolation of fields or interpolation was performed, - % that the geometrical fields are consistent with floation condition. + % that the geometrical fields are consistent with flotation condition. % However, since the uvh formulation is with respect to h % alone, this will not affect the solution since this does not % change h. @@ -172,12 +172,12 @@ - % I define two types of exit critera: + % I define two types of exit criteria: % 1) if residuals are below a given tolerance, exit and call it a success % 2) if step size is below a prescribed fraction of the Newton step in two % consecutive iterations, the minimisation procedure is judged to have % stagnated. There can be good or bad reasons for this: Possibly the - % minimisation procedure has converged on the miniumum and the norm of the + % minimisation procedure has converged on the minimum and the norm of the % gradient is small-enough (good) or it is too-large (bad). % @@ -275,7 +275,10 @@ % + tSolve=tic; [duvh,dl]=solveKApe(K,L,frhs,grhs,[dub;dvb;dh],dl,CtrlVar); + RunInfo.CPU.Solution.uvh=RunInfo.CPU.Solution.uvh+toc(tSolve); + dub=duvh(1:MUA.Nnodes) ; dvb=duvh(MUA.Nnodes+1:2*MUA.Nnodes); dh=duvh(2*MUA.Nnodes+1:end); @@ -330,8 +333,8 @@ Upper=2.2; Lower=-1 ; if gamma>0.7*Upper ; Upper=2*gamma; end - parfor I=1:nnn - gammaTest=(Upper-Lower)*(I-1)/(nnn-1)+Lower + for I=1:nnn + gammaTest=(Upper-Lower)*(I-1)/(nnn-1)+Lower; [~,~,~,rForceTest,rWorkTest,D2Test]=Func(gammaTest); %[rTest,~,~,rForceTest,rWorkTest,D2Test]=CalcCostFunctionNRuvh(UserVar,RunInfo,CtrlVar,MUA,F1,F0,dub,dvb,dh,dl,L,luvh,cuvh,gammaTest,Fext0); gammaTestVector(I)=gammaTest ; rForceTestvector(I)=rForceTest; rWorkTestvector(I)=rWorkTest; rD2Testvector(I)=D2Test; @@ -396,7 +399,7 @@ % Variables have been updated, if I have MassBalanceGeometryFeedback>0 I must % update the surface mass balance within this non-linear loop. Actually I here % only need to consider option 1 because if options 2 or 3 are used the - % mass-blance is updated anyhow witin the assmebly loop. + % mass-balance is updated anyhow within the assembly loop. if CtrlVar.MassBalanceGeometryFeedback>0 rdamp=CtrlVar.MassBalanceGeometryFeedbackDamping; @@ -473,7 +476,7 @@ %% print/plot some info - if CtrlVar.InfoLevelNonLinIt>=2 && iteration >= 2 && CtrlVar.doplots==1 + if CtrlVar.InfoLevelNonLinIt>=2 && iteration >= 1 && CtrlVar.doplots==1 figNR=FindOrCreateFigure(FigNames+"NR-uvh r"); clf(figNR) ; diff --git a/SayGoodbye.m b/SayGoodbye.m index 13efaceb..39bcfe21 100755 --- a/SayGoodbye.m +++ b/SayGoodbye.m @@ -3,6 +3,6 @@ function SayGoodbye(CtrlVar,RunInfo) if CtrlVar.WriteRunInfoFile fclose(RunInfo.File.fid); end - fprintf(CtrlVar.fidlog,' Run finishes at %s \n ================ Allt gott þá endirinn er allra bestur! ======================\n \n',datestr(now)); + fprintf(CtrlVar.fidlog,' Run finishes at %s \n ================ Allt gott þá endirinn er allra bestur! ======================\n \n',datetime); end \ No newline at end of file diff --git a/SummaryParallelPerformance.txt b/SummaryParallelPerformance.txt new file mode 100755 index 00000000..ae98156c --- /dev/null +++ b/SummaryParallelPerformance.txt @@ -0,0 +1,23 @@ + + + +UaTests\MassConservationTests\Peaks: + Comparision between sequential and parallel uvh solve using the user-defined parallel options set in DefineInitialInputs.m + #Elements=23134 #Nodes=104704 #Workers=12 + Note: Parallel options not switched on by user are not used in the parallel solve. + uvh Solve: tSeq=166.809805 sec tPar= 98.034216 sec tSeq/tPar=1.701547 + assembly: tSeq= 82.043358 sec tPar= 28.190217 sec tSeq/tPar=2.910349 + linsolve: tSeq= 68.323926 sec tPar= 56.581688 sec tSeq/tPar=1.207527 + + + + + + + +----------------------------------------------- + +32-Workers: +341265 x 341265 : tSeq=11.792888 tDistributed=5.407195 tSeq/rDistributed=2.180962 +227127 Ele : SPMD used for uvh assembly: tSeq=10.814372 tSPMD=2.096626 tSeq/rSPMD=5.157989 + diff --git a/TestABfgPreEliminateIterative.m b/TestABfgPreEliminateIterative.m index 2149d4b7..b7d745b2 100755 --- a/TestABfgPreEliminateIterative.m +++ b/TestABfgPreEliminateIterative.m @@ -1,22 +1,65 @@ % +%% % +% These are various ideas that I've tested while trying to get an iterative solver performance that is better then direct +% solver +% +% I have never been able to get the iterative solver to be even close to the direct one in terms of performance. +% +% The best option so far was use of gmres with ilu preconditioner combined with dissect. This was 'only' about 2 to 5 times slower than +% the direct solver. Also found the performance of the iterative solver to be highly problem dependent. +% +% Seems impossible to speed this up using parallel options as dissect not supported for distributed arrays (2023b) +% +% If series of similar solves, then by only doing the ilu and dissect for the first solve, the following solves are faster than +% direct solve. +% +% +%% +NumWorkers=8 ; + +ParPool = gcp('nocreate') ; + +if isempty(ParPool) + + parpool('Processes',NumWorkers) + +elseif (ParPool.NumWorkers~=NumWorkers) + + delete(gcp('nocreate')) + parpool('Processes',NumWorkers) + +end + +parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:genericError'); +parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:SaveNotSupported'); +warning('off','MATLAB:decomposition:genericError') +warning('off','MATLAB:decomposition:LoadNotSupported') + + + +%% TestCase="-direct-" ; % TestCase="-compare-" ; -% TestCase="-best-" ; +TestCase="-best-" ; + +load("solveKApePIGTWGuvh250896.mat","A","B","CtrlVar","f","g","x0","y0") + +CtrlVar.Parallel.Distribute=false; switch TestCase case "-direct-" - % Comaprision with Direct solver + % Comparison with Direct solver - load solveKApePIGTWGuvh250896.mat + tic [x,y,tolA,tolB]=ABfgPreEliminate(CtrlVar,A,B,f,g) ; toc @@ -26,71 +69,113 @@ case "-compare-" - % Iterative method comparision + % Iterative method comparison Peq=[] ; Req=[] ; Ceq=[] ; + L1=[]; + U1=[]; + L1eq=[]; + U1eq=[]; + + + + load("solveKApePIGTWGuvh250896time0k19NRit2.mat","A","B","CtrlVar","f","g") + CtrlVar.InfoLevelLinSolve=100; + + parpool('Threads') + % A=distributed(A) ; B=distributed(B) ; f=distributed(f) ; g=distributed(g); % equilibrate and dissect do not work with + % either distributed nor gpuarrays + x0=[]; y0=[]; - CtrlVar.InfoLevelLinSolve=100; - [x,y,tolA,tolB,Peq,Req,Ceq]=ABfgPreEliminateIterativeMethodComparision(CtrlVar,A,B,f,g,x0,y0,Peq,Req,Ceq) ; + + fprintf("\n\n\n-----------------------------------------------------------------------------------------\n\n") + + [x,y,tolA,tolB,Peq,Req,Ceq,L1,U1,L1eq,U1eq]=ABfgPreEliminateIterativeMethodComparision(CtrlVar,A,B,f,g,x0,y0,Peq,Req,Ceq,L1,U1,L1eq,U1eq) ; + + % Now call again using previous preconditioners and equilibrated matrix + + fprintf("\n\n\n-----------------------------------------------------------------------------------------\n\n") + + % Now load a matrix from next NR iteration + load("solveKApePIGTWGuvh250896time0k19NRit3.mat","A","B","CtrlVar","f","g") ; + CtrlVar.InfoLevelLinSolve=100; + + x0=x ; y0=y ; % use previous solution as an initial guess, and the previous preconditioners as well + + + [x,y,tolA,tolB,Peq,Req,Ceq,L1,U1,L1eq,U1eq]=ABfgPreEliminateIterativeMethodComparision(CtrlVar,A,B,f,g,x0,y0,Peq,Req,Ceq,L1,U1,L1eq,U1eq) ; case "-best-" -% From the method comparsion it is concluded that ilutp+dissect+gmrs is the best approach. -% Using equlibriate does not improve the convergence signficantly, and takes lot of time (30 sec, for the typical example +% From the method comparison it is concluded that ilutp+dissect+gmrs is the best approach. +% Using equlibriate does not improve the convergence significantly, and takes lot of time (30 sec, for the typical example % used here). % -% So fastes approach appearse to be: +% So fastest approach appears to be: % % 1) Preconditoner based in ilutp with droptolerance around 1e-6 or so % 2) dissect (a must to limit memory) % 3) gmres with tol=1e-15 and maxit around 30 (Usually only five or so needed) - L=[]; U=[] ; x0=[] ; y0=[] ; perm=[] ; + L=[]; U=[] ; P=[] ; x0=[] ; y0=[] ; perm=[] ; % load solveKApePIGTWGuvh250896.mat ; load("solveKApePIGTWGuvh250896time0k19NRit2.mat","A","B","CtrlVar","f","g","x0","y0") - + + CtrlVar.Parallel.Distribute=false; % A=distributed(A) ; B=distributed(B) ; f=distributed(f) ; g=distributed(g) ; x0=distributed(x0) ; y0=distributed(y0) ; % this does not work because dissect does not support distributed arrays % A=gpuArray(A) ; B=gpuArray(B) ; f=gpuArray(f) ; g=gpuArray(g) ; x0=gpuArray(x0) ; y0=gpuArray(y0) ; % this does not work because dissect does not support distributed arrays CtrlVar.InfoLevelLinSolve=100; - x0=[] ; y0=[] ; - fprintf("\n\n\n-----------------------------------------------------------------------------------------\n\n") + x0=[] ; y0=[] ; xtilde0=[]; + fprintf("\n-----------------------------------------------------------------------------------------\n\n") tstart1=tic ; - [x,y,tolA,tolB,L,U,perm]=ABfgPreEliminateIterative(CtrlVar,A,B,f,g,x0,y0,L,U,perm) ; - tend1=toc(tstart1) ; + [x,y,tolA,tolB,L,U,P,perm,xtilde]=ABfgPreEliminateIterative(CtrlVar,A,B,f,g,x0,y0,L,U,P,perm,xtilde0) ; + tend1=toc(tstart1) ; + tDirect=tic; + [xTest,yTest,tolA,tolB]=ABfgPreEliminate(CtrlVar,A,B,f,g) ; + tDirect=toc(tDirect); + + fprintf(" Iterative solve in %g sec \t Direct solve in %g sec \t norm(xTest-x)=%g \t norm(yTest-y)=%g \n ",tend1,tDirect,norm(xTest-x),norm(yTest-y)) - - + CtrlVar.InfoLevelLinSolve=100; - fprintf("\n\n\n-----------------------------------------------------------------------------------------\n\n") + fprintf("\n-----------------------------------------------------------------------------------------\n\n") % x0=x+1e-8*abs(x).*rand(length(x0),1) ; % for this slight modification of x0, a repeated solve is fast and does not require - % new LU factorisation. + % new LU factorization. load("solveKApePIGTWGuvh250896time0k19NRit3.mat","A","B","CtrlVar","f","g","x0","y0") + CtrlVar.Parallel.Distribute=false; % A=gpuArray(A) ; B=gpuArray(B) ; f=gpuArray(f) ; g=gpuArray(g) ; x0=gpuArray(x0) ; y0=gpuArray(y0) ; CtrlVar.InfoLevelLinSolve=100; - % x0=x ; y0=y; % L=[] ; U=[] ; perm=[] ; + x0=x ; y0=y; xtilde0=xtilde ; % L=[] ; U=[] ; perm=[] ; tstart2=tic ; - [x,y,tolA,tolB,L,U,perm]=ABfgPreEliminateIterative(CtrlVar,A,B,f,g,x0,y0,L,U,perm) ; + [x,y,tolA,tolB,L,U,P,perm,xtilde]=ABfgPreEliminateIterative(CtrlVar,A,B,f,g,x0,y0,L,U,P,perm,xtilde0) ; tend2=toc(tstart2) ; - fprintf("tend1=%f \t tend2=%f \n",tend1,tend2) + tDirect=tic; + [xTest,yTest,tolA,tolB]=ABfgPreEliminate(CtrlVar,A,B,f,g) ; + tDirect=toc(tDirect); + + fprintf(" Iterative solve in %g sec \t Direct solve in %g sec \t norm(xTest-x)=%g \t norm(yTest-y)=%g \n ",tend2,tDirect,norm(xTest-x),norm(yTest-y)) + + + fprintf("tend1=%f sec \t tend2=%f sec \n",tend1,tend2) otherwise diff --git a/TestGPU.m b/TestGPU.m index b08e5c97..dbe37a50 100755 --- a/TestGPU.m +++ b/TestGPU.m @@ -9,6 +9,24 @@ % %% + + +NumWorkers=8 ; + +ParPool = gcp('nocreate') ; + +if isempty(ParPool) + + parpool('Processes',NumWorkers) + +elseif (ParPool.NumWorkers~=NumWorkers) + + delete(gcp('nocreate')) + parpool('Processes',NumWorkers) + +end + +%% iExperiment=0; density=0.05 ; timings=zeros(10,7)+NaN; diff --git a/TestIterativeGPUsolve.m b/TestIterativeGPUsolve.m new file mode 100755 index 00000000..6893421c --- /dev/null +++ b/TestIterativeGPUsolve.m @@ -0,0 +1,46 @@ + +% +% As of Matlab 2024a Some GPU operations are much faster. For example, for this test +% +% DESKTOP-BU2IHIR - GPU NVIDIA Quadro RTX4000 +% Matlab 2024a : 1.4sec +% Matlab 2023a : 51.397637 +% +% which is an increase of about factor of 30. This is also explained in the release notes of R2024a +% +% +function TestIterativeGPUsolve + +% Create large sparse matrix. +A = gpuArray(gallery("wathen",500,500)); + +% Create a random right-hand side matrix. +actualSolution = rand(size(A,1),1); +b = A*actualSolution; + +% Create preconditioner matrix. +k = 3; +M = tril(triu(A,-k),k); + +% Time solver. +maxit = 100; +tol=1e-6; + +tic +[x,flag,relres,iter,resvector]=bicg(A,b,tol,maxit,M) ; +toc + +%t=gputimeit(@() bicg(A,b,[],maxNumberOfIterations,M)) + +figure(10) +semilogy(0:length(resvector)-1,resvector/norm(b),'-o') +yline(tol,'r--'); +legend('tri preconditioner','tolerance','Location','East') +xlabel('Iteration number') +ylabel('Relative residual') + + + + + +end \ No newline at end of file diff --git a/TestKRTFparallel.m b/TestKRTFparallel.m index 47ca3f87..6d7f8bb6 100755 --- a/TestKRTFparallel.m +++ b/TestKRTFparallel.m @@ -1,57 +1,21 @@ %% -clc -load TestSaveuvhAssembly -tic -for Iint=1:MUA.nip - - - [Tx1,Fx1,Ty1,Fy1,Th1,Fh1,Kxu1,Kxv1,Kyu1,Kyv1,Kxh1,Kyh1,Khu1,Khv1,Khh1]=... - uvhAssemblyIntPointImplicitSUPG(Iint,ndim,MUA,... - bnod,hnod,unod,vnod,AGlennod,nnod,Cnod,mnod,h0nod,u0nod,v0nod,as0nod,ab0nod,as1nod,ab1nod,dadhnod,Bnod,Snod,rhonod,... - uonod,vonod,Conod,monod,uanod,vanod,Canod,manod,... - CtrlVar,rhow,g,Ronly,ca,sa,dt,... - Tx0,Fx0,Ty0,Fy0,Th0,Fh0,Kxu0,Kxv0,Kyu0,Kyv0,Kxh0,Kyh0,Khu0,Khv0,Khh0); - - Tx=Tx+Tx1; Fx=Fx+Fx1; - Ty=Ty+Ty1; Fy=Fy+Fy1; - Th=Th+Th1; Fh=Fh+Fh1; - - Kxu=Kxu+Kxu1; Kxv=Kxv+Kxv1; - Kyu=Kyu+Kyu1; Kyv=Kyv+Kyv1; - Kxh=Kxh+Kxh1; Kyh=Kyh+Kyh1; - Khu=Khu+Khu1; Khv=Khv+Khv1; Khh=Khh+Khh1; - -end -toc +NumWorkers=8 ; +ParPool = gcp('nocreate') ; -tic +if isempty(ParPool) -parfor Iint=1:MUA.nip - - - [Tx1,Fx1,Ty1,Fy1,Th1,Fh1,Kxu1,Kxv1,Kyu1,Kyv1,Kxh1,Kyh1,Khu1,Khv1,Khh1]=... - uvhAssemblyIntPointImplicitSUPG(Iint,ndim,MUA,... - bnod,hnod,unod,vnod,AGlennod,nnod,Cnod,mnod,h0nod,u0nod,v0nod,as0nod,ab0nod,as1nod,ab1nod,dadhnod,Bnod,Snod,rhonod,... - uonod,vonod,Conod,monod,uanod,vanod,Canod,manod,... - CtrlVar,rhow,g,Ronly,ca,sa,dt,... - Tx0,Fx0,Ty0,Fy0,Th0,Fh0,Kxu0,Kxv0,Kyu0,Kyv0,Kxh0,Kyh0,Khu0,Khv0,Khh0); - - Tx=Tx+Tx1; Fx=Fx+Fx1; - Ty=Ty+Ty1; Fy=Fy+Fy1; - Th=Th+Th1; Fh=Fh+Fh1; - - Kxu=Kxu+Kxu1; Kxv=Kxv+Kxv1; - Kyu=Kyu+Kyu1; Kyv=Kyv+Kyv1; - Kxh=Kxh+Kxh1; Kyh=Kyh+Kyh1; - Khu=Khu+Khu1; Khv=Khv+Khv1; Khh=Khh+Khh1; - -end -toc + parpool('Processes',NumWorkers) + +elseif (ParPool.NumWorkers~=NumWorkers) + delete(gcp('nocreate')) + parpool('Processes',NumWorkers) + +end %% N=10000; @@ -85,8 +49,116 @@ +%% + + + +load("TestSolveKApe.mat","A","B","f","g","x0","y0","CtrlVar") + + +%% + +tSeq=tic; +[x,y]=ABfgPreEliminate(CtrlVar,A,B,f,g); +tSeq=toc(tSeq); + +tDistribute=tic; +Adist=distributed(A); +Bdist=distributed(B); +fdist=distributed(f); +gdist=distributed(g); +tDistribute=toc(tDistribute); + +tPar=tic; +[xDist,yDist]=ABfgPreEliminate(CtrlVar,Adist,Bdist,fdist,gdist); +x2=gather(xDist) ; y2=gather(yDist) ; +tPar=toc(tPar); + +fprintf("tSeq=%g \t tDistribute=%g \t tPar=%g \t gain=%g \n",tSeq,tDistribute,tPar,tSeq/(tDistribute+tPar)) + +% tSeq=26.2609 tDistribute=1.36496 tPar=13.7741 gain=1.73465 C23000099 8 workers +%% + +load("uvAtilde.mat","Atilde","btilde") + +spparms ('spumoni', 0) +Gain=nan(32,1); + + +for NumWorkers=[1 2 3 4 6 8 10 12] + + ParPool = gcp('nocreate') ; + + if isempty(ParPool) + + parpool('Processes',NumWorkers); + elseif (ParPool.NumWorkers~=NumWorkers) + delete(gcp('nocreate')); + parpool('Processes',NumWorkers); + + end + + for iRepeat=1:3 + + tSeq=tic; + + x=Atilde\btilde; + + tSeq=toc(tSeq) ; + + tDist=tic; + + AtildeDist=distributed(Atilde); + btildeDist=distributed(btilde); + x=AtildeDist\btildeDist; + x=gather(x); + tDist=toc(tDist); + + + + fprintf("%i : tSeq=%g \t tDist=%g \t gain=%g \n",NumWorkers,tSeq,tDist,tSeq/tDist) + end + + Gain(NumWorkers)=tSeq/tDist; +end + +% rather odd behaviour: about factor 2 gain irrespectivly of number of workers... +% even just one worker results in about gain of 2...Something else must be going on here. +figure(100) ; plot(Gain,'or') + + +%% + + + +%% +load("solveKApePIGTWGuvh250896.mat","A","B","CtrlVar","f","g","x0","y0") + + +CtrlVar.Parallel.Distribute=false ; + +tSeq=tic; +[x,y]=solveKApe(A,B,f,g,x0,y0,CtrlVar); +tSeq=toc(tSeq); + +CtrlVar.Parallel.Distribute=true ; + +tDist=tic; +[x,y]=solveKApe(A,B,f,g,x0,y0,CtrlVar); +tDist=toc(tDist); + + +% hm, seems better to do the distribution just ahead of the \ operation, ie within ABfgPreEliminate +tDist2=tic; +Adist=distributed(A); Bdist=distributed(B); +[x,y]=solveKApe(Adist,Bdist,f,g,x0,y0,CtrlVar); +tDist2=toc(tDist2); + +fprintf("%i : tSeq=%g \t tDist=%g \t tDist2=%g \t gain=%g \n",NumWorkers,tSeq,tDist,tDist2, tSeq/tDist) + +%% diff --git a/TestLocateEleIslands.m b/TestLocateEleIslands.m new file mode 100755 index 00000000..b2b645da --- /dev/null +++ b/TestLocateEleIslands.m @@ -0,0 +1,231 @@ + + +% +% Tests and examples of the use of: +% +% LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly.m +% +% + +TestCase=4; % There are currenlty 3 test cases available. + +%% +% +% +% Note: For TestCase=2 you will need an input file. You can get this input file from: +% +% https://livenorthumbriaac-my.sharepoint.com/:f:/g/personal/hilmar_gudmundsson_northumbria_ac_uk/EulRApgZzIlMq7mgx33DD5UB1_MDwEFIah-_CWrQcxJNnA?e=3om5cp +% +% There are several .mat files in this directory and you might want to download them all into a seperate folder and add to +% the matlab path. These mat fiels are used in various Ua examples and tests and for plotting purposes, but none of them are required to run Ua. +% +%% + +switch TestCase + + + case 1 + clearvars + + CtrlVar=Ua2D_DefaultParameters(); + CtrlVar.TriNodes=3; + CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; + CtrlVar.PlotNodalLabels=1; CtrlVar.PlotNodes=1; + CtrlVar.PlotXYscale=1; + CtrlVar.MeshSizeMax=0.5; CtrlVar.MeshSizeMin=0.5; CtrlVar.MeshSize=0.5; + UserVar=[]; + CtrlVar.MeshBoundaryCoordinates=[1 NaN ; -1 -1 ; -1 -1.5 ; -1.5 -1 ; -1 -1 ; -1 0 ; 0 0.5 ; 0 0 ; -1 0 ; 1 -0.5 ; 1 -1 ; 1 -1.5 ; 0.5 -1.5 ; 1 -1 ; ... % boundary of mesh 1 + 2 NaN ; -2.0 -0.5 ; -2.0 0.5 ; -1.5 0.5 ; -1.5 -0.5 ; ... + 3 NaN ; 2.0 -0.5 ; 2.0 0.5 ; 1.5 0.5 ; 1.5 -0.5 ]; + + [UserVar,MUA]=genmesh2d(UserVar,CtrlVar); + + FindOrCreateFigure("Mesh") ; PlotMuaMesh(CtrlVar,MUA); drawnow + + [Islands]=LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly(CtrlVar,MUA) ; + + FindOrCreateFigure("Islands") ; + CtrlVar.PlotNodalLabels=0; + PlotMuaMesh(CtrlVar,MUA); + hold on + PlotMuaMesh(CtrlVar,MUA,Islands.Free,color="r",LineWidth=2); + PlotMuaMesh(CtrlVar,MUA,Islands.OneNode,color="b",LineStyle="--",LineWidth=2); + title("Islands (red) and one-node or less connection (blue)") + + + %% + + case 2 + + doPLots=true; + + load("EleDeactivationTestDataLarge.mat","CtrlVar","F","MUA") + nNodesIn=MUA.Nnodes; + if doPLots + FindOrCreateFigure("Mesh") ; PlotMuaMesh(CtrlVar,MUA); + end + + + fprintf("LevelSetElementDeactivation: deactivating ALL elements downstream of calving fronts. ") + isIceNode = F.LSF >= 0 ; % All icy nodes + isIceElement=AllElementsContainingGivenNodes(MUA.connectivity,isIceNode) ; % all elements containing at least one icy node + ElementsToBeDeactivated=~isIceElement ; + + if doPLots + FindOrCreateFigure("MUA mesh: Ahead of level set deactivation") + PlotMuaMesh(CtrlVar,MUA); + hold on + PlotMuaMesh(CtrlVar,MUA,ElementsToBeDeactivated,color="r",LineStyle="--",LineWidth=2); + title("Level Set Deactivation") + end + + CtrlVar.UpdateMUAafterDeactivating=false ; + [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated) ; + + if doPLots + FindOrCreateFigure("MUAnew mesh: After level set deactivation") + PlotMuaMesh(CtrlVar,MUA); + title("After Level Set Deactivation") + end + + CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly="-Islands-OneNodeOrLessConnections-" ; + [Islands]=LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly(CtrlVar,MUA) ; + + + + FindOrCreateFigure("Islands") ; + CtrlVar.PlotNodalLabels=0; + PlotMuaMesh(CtrlVar,MUA); + hold on + PlotMuaMesh(CtrlVar,MUA,Islands.Free,color="r",LineWidth=2); + PlotMuaMesh(CtrlVar,MUA,Islands.OneNode,color="b",LineStyle="--",LineWidth=2); + title("Islands (red) and one-node or less connection (blue)") + + ElementsToBeDeactivated=Islands.OneNode; + [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated,k,l) ; + + + if doPLots + FindOrCreateFigure("MUAnew mesh: After level set deactivation and island removal") + PlotMuaMesh(CtrlVar,MUA); + title("After Level Set Deactivation and island removal") + end + + %% + + + case 3 + + % Shows how to map fields between meshes for repeated element deactivation + + CtrlVar=Ua2D_DefaultParameters(); + CtrlVar.UpdateMUAafterDeactivating=false; + CtrlVar.TriNodes=3; + CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; + CtrlVar.PlotNodes=1; + + CtrlVar.PlotEleLabels=1; + CtrlVar.PlotNodalLabels=1; + CtrlVar.PlotXYscale=1; + CtrlVar.MeshSizeMax=0.5; CtrlVar.MeshSizeMin=0.5; CtrlVar.MeshSize=0.5; + UserVar=[]; + CtrlVar.MeshBoundaryCoordinates=[1 NaN ; -1 -1 ; -1 -1.5 ; -1.5 -1 ; -1 -1 ; -1 0 ; 0 0.5 ; 0 0 ; -1 0 ; 1 -0.5 ; 1 -1 ; 1 -1.5 ; 0.5 -1.5 ; 1 -1 ; ... % boundary of mesh 1 + 2 NaN ; -2.0 -0.5 ; -2.0 0.5 ; -1.5 0.5 ; -1.5 -0.5 ; ... + 3 NaN ; 2.0 -0.5 ; 2.0 0.5 ; 1.5 0.5 ; 1.5 -0.5 ]; + + + + [UserVar,MUA]=genmesh2d(UserVar,CtrlVar); + + nNodesIn=MUA.Nnodes ; % the original number of nodes + + + FindOrCreateFigure("Mesh Original") ; PlotMuaMesh(CtrlVar,MUA); + + F.x=MUA.coordinates(:,1) ; F.y=MUA.coordinates(:,2) ; + UaPlots(CtrlVar,MUA,[],F.x,FigureTitle="x on original mesh") ; + + ElementsToBeDeactivated=[2 29] ; + [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated) ; + + FindOrCreateFigure("Mesh after First Deactivation") ; PlotMuaMesh(CtrlVar,MUA); + UaPlots(CtrlVar,MUA,[],F.x(k),FigureTitle="First deactivation") ; + + ElementsToBeDeactivated=[2 16 ] ; + [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated,k,l) ; + + FindOrCreateFigure("Mesh after Second Deactivation") ; PlotMuaMesh(CtrlVar,MUA); + UaPlots(CtrlVar,MUA,[],F.x(k),FigureTitle="Second deactivation") ; + + + [Islands]=LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly(CtrlVar,MUA) ; + + FindOrCreateFigure("Islands") ; + + PlotMuaMesh(CtrlVar,MUA); + hold on + PlotMuaMesh(CtrlVar,MUA,Islands.Free,color="r",LineWidth=2); + PlotMuaMesh(CtrlVar,MUA,Islands.OneNode,color="b",LineStyle="--",LineWidth=2); + title("Islands (red) and one-node or less connection (blue)") + + ElementsToBeDeactivated=Islands.OneNode ; [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated,k,l) ; + + FindOrCreateFigure("Mesh after Third Deactivation") ; PlotMuaMesh(CtrlVar,MUA); + UaPlots(CtrlVar,MUA,[],F.x(k),FigureTitle="Third deactivation") ; + + % k=k1(k2(k3)); % k gives the mapping between new and old nodal numbers, fNew=fOld(k) + % l=1:nNodesIn ; l=l(:)+nan; % l gives the mapping betwenen old and new, i=l(j) gives the new node number i for the old node number j + % l(k(1:numel(k)))=1:numel(k); % i=l(j) is nan if the original j node was deleted + + + fprintf(" done \n") + + + case 4 + + + doPLots=true; + + CtrlVar=Ua2D_DefaultParameters(); + load("UaLogoMUA.mat","MUA") + + + if doPLots + FindOrCreateFigure("Mesh") ; PlotMuaMesh(CtrlVar,MUA); + end + + + + CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly="-Islands-OneNodeOrLessConnections-" ; + % + CtrlVar.MaxNumberOfIslands=2 ; + [Islands]=LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly(CtrlVar,MUA); + + + + FindOrCreateFigure("Islands") ; + CtrlVar.PlotNodalLabels=0; + PlotMuaMesh(CtrlVar,MUA); + hold on + PlotMuaMesh(CtrlVar,MUA,Islands.Free,color="r",LineWidth=2); + PlotMuaMesh(CtrlVar,MUA,Islands.OneNode,color="b",LineStyle="--",LineWidth=2); + title("Islands (red) and one-node or less connection (blue)") + + if CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly=="-Islands-OneNodeOrLessConnections-" + ElementsToBeDeactivated=Islands.OneNode; % + elseif CtrlVar.LocateDetachedIslandsAndRegionsConnectedByOneNodeOnly=="-Islands-" + ElementsToBeDeactivated=Islands.Free; + end + + [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated) ; + + + if doPLots + FindOrCreateFigure("MUAnew mesh: After deactivation and island removal") + PlotMuaMesh(CtrlVar,MUA); + title("Mesh remaining after element deactivation") + end + + +end + diff --git a/TestParallelAssemblyOptions.m b/TestParallelAssemblyOptions.m new file mode 100755 index 00000000..3cefc0f0 --- /dev/null +++ b/TestParallelAssemblyOptions.m @@ -0,0 +1,138 @@ + + + +NumWorkers=8 ; + +ParPool = gcp('nocreate') ; + +if isempty(ParPool) + + parpool('Processes',NumWorkers) + +elseif (ParPool.NumWorkers~=NumWorkers) + + delete(gcp('nocreate')) + parpool('Processes',NumWorkers) + +end + +parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:genericError'); +parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:SaveNotSupported'); +warning('off','MATLAB:decomposition:genericError') +warning('off','MATLAB:decomposition:LoadNotSupported') + + +Solving="-uv-" ; + + +UserVar=FileDirectories; + + +%load(UserVar.InverseRestartFileDirectory+"InverseRestartFile-Joughin-Ca1-Cs100000-Aa1-As100000-5km-Alim-Clim-.mat","CtrlVarInRestartFile","RunInfo","MUA","F","BCs","l") + +if contains(Solving,"-uv-") + load(UserVar.InverseRestartFileDirectory+"InverseRestartFile-Cornford-Ca1-Cs100000-Aa1-As100000-5km-Alim-Clim-.mat","CtrlVarInRestartFile","RunInfo","MUA","F","BCs","l") +else + load(UserVar.ForwardRestartFileDirectory+"Restart-FT-P-Duvh-TWIS-MR4-SM-TM001-Cornford-2k5km-Alim-Clim-Ca1-Cs100000-Aa1-As100000-InvMR5","CtrlVarInRestartFile","RunInfo","MUA","F","BCs","l") +end + +load(UserVar.ForwardRestartFileDirectory+"Restart-FT-P-Duvh-TWIS-MR4-SM-TM001-Cornford-2k5km-Alim-Clim-Ca1-Cs100000-Aa1-As100000-InvMR5","CtrlVarInRestartFile","RunInfo","MUA","F","BCs","l") + +tic +MUA.dM=decomposition(MUA.M,'chol','upper') ; +toc + +RunInfo=UaRunInfo; % reset runinfo + + +CtrlVar=CtrlVarInRestartFile; +CtrlVar.InfoLevelNonLinIt=1; CtrlVar.InfoLevel=1; + +CtrlVar.uvGroupAssembly=false; CtrlVar.uvhGroupAssembly=false; CtrlVar.etaZero=10; + +CtrlVar.Parallel.uvAssembly.spmd.nWorkers=[]; + + +CtrlVar.Parallel.Options="-none-" ; +CtrlVar.Parallel.Options="-auto-" ; + +if CtrlVar.Parallel.Options=="-auto-" + + CtrlVar.Parallel.uvAssembly.spmd.isOn=true; + CtrlVar.Parallel.uvAssembly.parfeval.isOn=false; + CtrlVar.Parallel.uvhAssembly.spmd.isOn=true; + CtrlVar.Parallel.Distribute=true ; + +elseif CtrlVar.Parallel.Options=="-none-" + + CtrlVar.Parallel.uvAssembly.spmd.isOn=false; + CtrlVar.Parallel.uvAssembly.parfeval.isOn=false; + CtrlVar.Parallel.uvhAssembly.spmd.isOn=false; + CtrlVar.Parallel.Distribute=false ; + +end + +CtrlVar.Parallel.isTest=false; + + +MUA=UpdateMUA(CtrlVar,MUA) ; + + +%% modified NR options +CtrlVar.ModifiedNRuvIntervalCriterion=4 ; CtrlVar.ModifiedNRuvReductionCriterion=0.5 ; % Total time=237.335 Solver=49.1201 Assembly=92.7946 +% CtrlVar.ModifiedNRuvIntervalCriterion=2 ; CtrlVar.ModifiedNRuvReductionCriterion=0.5 ; % Total time=193.215 Solver=53.4797 Assembly=79.4635 +% CtrlVar.ModifiedNRuvIntervalCriterion=1 ; CtrlVar.ModifiedNRuvReductionCriterion=0.5 ; % Total time=202.01 Solver=71.846 Assembly=78.921 + CtrlVar.InfoLevelNonLinIt=5 ; +%% + +if contains(Solving,"-uv-") + % F.ub=F.ub*0 ; F.vb=F.vb*0; + tTotal=tic; + [UserVar,RunInfo,F,l,Kuv,Ruv,Lubvb]= uv(UserVar,RunInfo,CtrlVar,MUA,BCs,F,l) ; + tTotal=toc(tTotal); + + fprintf("Total time=%g \t Solver=%g \t Assembly=%g \n",tTotal,RunInfo.CPU.Solution.uv,RunInfo.CPU.Assembly.uv) + + UaPlots(CtrlVar,MUA,F,"-uv-") + + + % Total time=5.5462 Solver=2.02292 Assembly=3.44374 C23000099 12 SPMD Distributed + % Total time=6.41722 Solver=2.10235 Assembly=4.25054 C23000099 8 SPMD Distributed + + % Total time=17.3182 Solver=6.08226 Assembly=11.1686 C23000099 ~SPMD ~Distributed + +end + + + + +if contains(Solving,"-uvh-") + %% uvh + CtrlVar.dt=0.001; + + tTotal=tic; + [UserVar,RunInfo,F1,l1,BCs1,dt]=uvh(UserVar,RunInfo,CtrlVar,MUA,F,F,l,l,BCs) ; + tTotal=toc(tTotal); + + fprintf("Total time=%g \t Solver=%g \t Assembly=%g \n",tTotal,RunInfo.CPU.Solution.uvh,RunInfo.CPU.Assembly.uvh) + + % Total time=89.8162 Solver=47.6165 Assembly=22.6194 C23000099 SPMD(24) + + % Total time=94.3706 Solver=49.6399 Assembly=23.7048 C23000099 SPMD(12) + % Total time=75.4851 Solver=30.5031 Assembly=24.2612 C23000099 SPMD(12) distributed + + % Total time=141.966 Solver=47.9826 Assembly=52.8219 C23000099 SPMD(4) + % Total time=134.659 Solver=28.9537 Assembly=68.6005 C23000099 ~SPMD(8) distributed + + % Total time=158.332 Solver=51.4621 Assembly=68.7052 C23000099 ~SPMD(12) ~distributed + + + + + % Total time=116.786 Solver=62.4066 Assembly=29.1553 DESKTOP-BU2IHIR SPMD(12) + % Total time=174.072 Solver=62.0067 Assembly=69.6168 DESKTOP-BU2IHIR ~SPMD(12) + + UaPlots(CtrlVar,MUA,F,"-uv-") + + +end \ No newline at end of file diff --git a/TestParallelLinsolve.m b/TestParallelLinsolve.m new file mode 100755 index 00000000..db4dc2c0 --- /dev/null +++ b/TestParallelLinsolve.m @@ -0,0 +1,150 @@ + + +%% +% +% 2023-01: General conclusions. +% +% For full matrices it is easy to get significant speed up my simply creating distributed arrays. +% +% For sparse matrices it is also easy to get significant speedup, provided that matrix has density of 0.1 or more +% +% For matrices that arise with Ua the density is however much smaller, or about 0.0001, and no significant speedup is +% observed. +% +% +%% + +% delete(gcp('nocreate')); parpool('Processes',8) + +% delete(gcp('nocreate')); parpool('Threads',8) + +% distributed not supported in thread-based parallel pool (F2024a) + +% https://uk.mathworks.com/help/parallel-computing/benchmarking-a-b.html + +%% full solver +% +% Very simple approach to evaluate parallel performance when solving full systems. +% +% This clearly does speed things up, although exact performance gain will depend on various factors. +% + +nWVector=[1 2 4 6 8 10 12]; +tSolveVector=nWVector+nan; +perfVector=nWVector+nan; +iCount=0; +N=20000; +A = rand( N ); +b = sum(A,2) ; + + +for nW=nWVector + + delete(gcp('nocreate')); + parpool('Processes',nW) ; + + ADist=distributed(A); + bDist=distributed(b); + + tSolve=tic ; % Start of timed region + x = ADist \ bDist; % Solve the linear system + tSolve = toc(tSolve) ; % End of timed region + perf = ( 2/3 * N^3 + 3/2 * N^2 ) / tSolve / 1.e9 ; + + iCount=iCount+1; + tSolveVector(iCount)=tSolve; + perfVector(iCount)=perf; + fprintf("nW=%i \t time %f sec \t GFlops %f \n ",nW,tSolve,perf) + + +end + +figure(30) +yyaxis left +plot(nWVector,tSolveVector,"o-b") +ylabel("time for solve (sec)",Interpreter="latex") +yyaxis right +plot(nWVector,perfVector,"o-r") +ylabel("Gigaflops",Interpreter="latex") + +xlabel("\# workers",Interpreter="latex") ; +title("direct solver, full system, 20k$\times$20k ",Interpreter="latex") + + + + + +%% sparse solver + +%% full solver +% +% Very simple approach to evaluate parallel performance when solving full systems. +% +% This clearly does speed things up, although exact performance gain will depend on various factors. +% + +filename=[]; +filename="solveKApePIGTWGuvh250896time0k19NRit2"; + + +nWVector=[1 2 4 6 8 10 12]; +nWVector=[1 4 8 10 ] ; +tSolveVector=nWVector+nan; +perfVector=nWVector+nan; +iCount=0; + + +if isempty(filename) + + n=20; + N=1000*n; + density=0.1 ; + A = sprand( N , N , density); + b = sum(A,2) ; + +else + + load(filename,"A") + b = sum(A,2) ; + N=size(A,1) ; + density=nnz(A)/N^2; + +end + +for nW=nWVector + + delete(gcp('nocreate')); + parpool('Processes',nW) ; + + ADist=distributed(A); + bDist=distributed(b); + + tSolve=tic ; % Start of timed region + x = ADist \ bDist; % Solve the linear system + tSolve = toc(tSolve) ; % End of timed region + perf = ( 2/3 * N^3 + 3/2 * N^2 ) / tSolve / 1.e9 ; + + iCount=iCount+1; + tSolveVector(iCount)=tSolve; + perfVector(iCount)=perf; + fprintf("nW=%i \t time %f sec \t GFlops %f \n ",nW,tSolve,perf) + + +end + +figure(500) +% yyaxis left +plot(nWVector,tSolveVector,"o-b") +ylabel("time for solve (sec)",Interpreter="latex") +% yyaxis right ; plot(nWVector,perfVector,"o-r") ; ylabel("Gigaflops",Interpreter="latex") +xlabel("\# workers",Interpreter="latex") ; + + +title(sprintf("direct solver, sparse system, %ik $\\times$ %ik, density=%g ",round(N/10e3),round(N/10e3),density),Interpreter="latex") + + + + + + +%% diff --git a/TestSlipperinessInputValues.m b/TestSlipperinessInputValues.m index 0a1b2cdb..c8c2409e 100755 --- a/TestSlipperinessInputValues.m +++ b/TestSlipperinessInputValues.m @@ -1,8 +1,8 @@ -function [C,m,q,muk]=TestSlipperinessInputValues(CtrlVar,MUA,C,m,q,muk) +function [C,m,q,muk,V0]=TestSlipperinessInputValues(CtrlVar,MUA,C,m,q,muk,V0) -narginchk(4,6) -nargoutchk(2,4) +narginchk(4,7) +nargoutchk(2,5) @@ -18,6 +18,10 @@ muk=[]; end +if nargin<7 + V0=[]; +end + if numel(C)==1 %fprintf(' C given by user is a scalar. Assuming that C is same everywhere. \n') @@ -30,7 +34,7 @@ if numel(m)==1 - + if CtrlVar.CisElementBased m=m+zeros(MUA.Nele,1); else @@ -41,90 +45,119 @@ if isempty(q) - + pattern=["Budd","W-N0"]; if contains(CtrlVar.SlidingLaw,pattern) fprintf("Input Error: \t For sliding law: %s \n \t \t \t \t q must be defined in DefineSlipperiness.m \n",CtrlVar.SlidingLaw) fprintf("\t \t \t \t and in an inverse run in DefineInputsForInverseRun.m as well. \n") error("Incorrect inputs") - + end - + else - + if numel(q)==1 - + if CtrlVar.CisElementBased q=q+zeros(MUA.Nele,1); else q=q+zeros(MUA.Nnodes,1); end end - + end if isempty(muk) - + pattern=["Tsai","Coulomb","Cornford","Umbi","minCW-N0","rpCW-N0","rCW-N0"] ; if contains(CtrlVar.SlidingLaw,pattern) fprintf("Input Error: \t For sliding law: %s \n \t \t \t \t muk must be defined in DefineSlipperiness.m \n",CtrlVar.SlidingLaw) fprintf("\t \t \t \t and in an inverse run in DefineInputsForInverseRun.m as well. \n") error("Incorrect inputs") - + end - + else - + if numel(muk)==1 - + if CtrlVar.CisElementBased muk=muk+zeros(MUA.Nele,1); else muk=muk+zeros(MUA.Nnodes,1); end end - + +end + +pattern=["Joughin","rCW-V0"]; +if ~contains(CtrlVar.SlidingLaw,pattern) + V0=[]; end +if isempty(V0) + + pattern=["Joughin","rCW-V0"]; + if contains(CtrlVar.SlidingLaw,pattern) + fprintf("Input Error: \t For sliding law: %s \n \t \t \t \t V0 must be defined in DefineSlipperiness.m \n",CtrlVar.SlidingLaw) + fprintf("\t \t \t \t and in an inverse run in DefineInputsForInverseRun.m as well. \n") + error("Incorrect inputs") + + end + +else + + if numel(V0)==1 + + if CtrlVar.CisElementBased + V0=V0+zeros(MUA.Nele,1); + else + V0=V0+zeros(MUA.Nnodes,1); + end + end + +end + + if CtrlVar.AutomaticallyMapAGlenBetweenNodesAndEleIfEnteredIncorrectly - + if CtrlVar.CisElementBased - + if nC==MUA.Nnodes fprintf('\n Note: C is element based, but entered on input as a nodal variable.\n') fprintf(' C will be mapped from nodes to elements by averaging over neighbouring nodes. \n') C=Nodes2EleMean(MUA.connectivity,C); end - + if nm==MUA.Nnodes fprintf('\n Note: m is element based, but entered on input as a nodal variable.\n') fprintf(' m will be mapped from nodes to elements by averaging over neighbouring nodes. \n') m=Nodes2EleMean(MUA.connectivity,m); end - + else - + if nC==MUA.Nele || nm==MUA.Nele - + M=Ele2Nodes(MUA.connectivity,MUA.Nnodes); - + if nC==MUA.Nele - + fprintf('\n Note: C is nodal based, but entered on input as an element variable.\n') fprintf(' C will be mapped from elements to nodes by averaging over neighbouring elements. \n') - + C=M*C; end - + if nm==MUA.Nele - + fprintf('\n Note: m is nodal based, but entered on input as an element variable.\n') fprintf(' m will be mapped from elements to nodes by averaging over neighbouring elements. \n') - + m=M*m; end end @@ -140,7 +173,7 @@ elseif ~CtrlVar.CisElementBased && ~(length(MUA.coordinates) == length(C)) save TestSave ; error(' C is node-based but input does not have same number of elements as there are nodes in mesh. All variables saved in TestSave.mat ') - + end @@ -162,7 +195,7 @@ if niU>0 fprintf('TestCInputValues: On input %i C values are larger than largest allowed value (%g). \n',niU); fprintf(' These values have been reset to the maximum allowed value of %g .\n',niU,CtrlVar.Cmax); - + end if niL>0 fprintf('TestCInputValues: On input %i C values are smaller than smallest allowed value (%g). \n',niL,CtrlVar.Cmin); diff --git a/Ua.m b/Ua.m index e37f054a..729b63fc 100755 --- a/Ua.m +++ b/Ua.m @@ -90,7 +90,7 @@ % Not all of these user m-files are always needed. For example % `DefineInverseModellingVariables.m' is only needed for inverse runs. Also % 'DefineStartVelValues.m' is not often required as setting start velocities to -% zero (the default opton) is usually a good approach. And DefineDesiredEleSizes +% zero (the default option) is usually a good approach. And DefineDesiredEleSizes % is only needed if one finds that the standard remeshing options within Úa are % too limited. % diff --git a/Ua2D.m b/Ua2D.m index f4c7c56b..5656cee7 100755 --- a/Ua2D.m +++ b/Ua2D.m @@ -19,14 +19,13 @@ warning('off','MATLAB:triangulation:PtsNotInTriWarnId') warning('off','MATLAB:decomposition:SaveNotSupported') warning('off','MATLAB:decomposition:genericError') +warning("off","matlab:decomposition:LoadNotSupported") + + + + -ParPool = gcp('nocreate') ; -if ~isempty(ParPool) - parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:genericError'); - parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:SaveNotSupported'); -end - %% initialize some variables RunInfo=UaRunInfo; Fm1=UaFields; @@ -104,7 +103,7 @@ -% do some basic test on the vality of the CtrlVar fields, validate CtlrVar +% do some basic test on the validity of the CtrlVar fields, validate CtlrVar CtrlVar=CtrlVarValidityCheck(CtrlVar); @@ -127,6 +126,27 @@ end end + +%% Check and set some parallel variables +ParPool = gcp; +CtrlVar.Parallel.uvhAssembly.spmd.nWorkers=ParPool.NumWorkers; + +if ~isempty(ParPool) + + parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:genericError'); + parfevalOnAll(gcp(), @warning, 0, 'off','MATLAB:decomposition:SaveNotSupported'); + + if CtrlVar.Parallel.uvhAssembly.spmd.isOn + CtrlVar.Parallel.uvhAssembly.spmd.nWorkers=ParPool.NumWorkers; + end + + if CtrlVar.Parallel.uvAssembly.spmd.isOn + CtrlVar.Parallel.uvAssembly.spmd.nWorkers=ParPool.NumWorkers; + end + +end + + %% Get input data if CtrlVar.InverseRun % inverse run @@ -188,7 +208,7 @@ else % New forward run (ie not a restart) - + CtrlVar.CurrentRunStepNumber=1; RunInfo.Message="Getting inputs for a new forward run"; CtrlVar.RunInfoMessage=RunInfo.Message; [UserVar,RunInfo,MUA,BCs,F,l]=GetInputsForForwardRun(UserVar,CtrlVar,RunInfo); @@ -225,10 +245,10 @@ % For convenience I assume that the user defines S, B, s and b. The program % then calculates h=s-b and then s and b from h, B and S given the ice and % ocean specific density. The thickness is preserved, and s and b are -% consistent with the floating condition for a given ice tickness h, rho and +% consistent with the floating condition for a given ice thickness h, rho and % rhow. if ~isfield(RunInfo,'Message') ; RunInfo.Message=[] ; end -RunInfo.Message="All initial inputs now defined."; % this is a string, will only work correclty post Matlab 2017b. +RunInfo.Message="All initial inputs now defined."; % this is a string, will only work correctly post MATLAB 2017b. CtrlVar.RunInfoMessage=RunInfo.Message; @@ -267,16 +287,25 @@ %x=coordinates(:,1); y=coordinates(:,2); DT = DelaunayTri(x,y); TRI=DT.Triangulation; %figure(21) ; trisurf(TRI,x/CtrlVar.PlotXYscale,y/CtrlVar.PlotXYscale,h) ; title(' h') + fprintf('\n ========================= Inverting for model parameters. ========================= \n') + + CtrlVar.Parallel.BuildWorkers=true; + MUA=UpdateMUA(CtrlVar,MUA); + + RunInfo.CPU.Inversion=tic; [UserVar,F,l,InvFinalValues,RunInfo]=... InvertForModelParameters(UserVar,CtrlVar,MUA,BCs,F,l,InvStartValues,Priors,Meas,BCsAdjoint,RunInfo); - + RunInfo.CPU.Inversion=toc(RunInfo.CPU.Inversion); F.C=InvFinalValues.C ; %fprintf(CtrlVar.fidlog,' C set equal to InvFinalValues.C. '); F.AGlen=InvFinalValues.AGlen ; %fprintf(CtrlVar.fidlog,' AGlen set equal InvFinalValues.AGlen \n '); F.m=InvFinalValues.m ; F.n=InvFinalValues.n ; + + + [UserVar,RunInfo,F,l,drdu,Ruv,Lubvb]= uv(UserVar,RunInfo,CtrlVar,MUA,BCs,F,l); @@ -454,12 +483,11 @@ end end - if CtrlVar.UpdateBoundaryConditionsAtEachTimeStep - [UserVar,BCs]=GetBoundaryConditions(UserVar,CtrlVar,MUA,BCs,F); - F=StartVelocity(CtrlVar,MUA,BCs,F); % start velocity might be a function of GF + if CtrlVar.UpdateBoundaryConditionsAtEachTimeStep + [UserVar,BCs]=GetBoundaryConditions(UserVar,CtrlVar,MUA,BCs,F); % update boundary conditions at each time step end - % get mass-balance after any modifications to geometry, as mass balance might depent + % get mass-balance after any modifications to geometry, as mass balance might depend % on geometry. [UserVar,F]=GetMassBalance(UserVar,CtrlVar,MUA,F); @@ -477,6 +505,9 @@ RunInfo.Message="-RunStepLoop- Diagnostic step. Solving for velocities."; CtrlVar.RunInfoMessage=RunInfo.Message; + CtrlVar.Parallel.BuildWorkers=true; + MUA=UpdateMUA(CtrlVar,MUA); + [UserVar,RunInfo,F,l,Kuv,Ruv,Lubvb]= uv(UserVar,RunInfo,CtrlVar,MUA,BCs,F,l); @@ -506,10 +537,7 @@ - if numel(RunInfo.Forward.time) < CtrlVar.CurrentRunStepNumber - RunInfo.Forward.time=[RunInfo.Forward.time;RunInfo.Forward.time+NaN]; - RunInfo.Forward.dt=[RunInfo.Forward.dt;RunInfo.Forward.dt+NaN]; - end + RunInfo=ExtendAllocations(RunInfo,CtrlVar,CtrlVar.CurrentRunStepNumber); RunInfo.Forward.time(CtrlVar.CurrentRunStepNumber)=CtrlVar.time; RunInfo.Forward.dt(CtrlVar.CurrentRunStepNumber)=CtrlVar.dt; @@ -538,16 +566,19 @@ RunInfo.Forward.IterationsTotal,datetime('now'),... duration(0,0,RunInfo.CPU.Assembly.uvh),duration(0,0,RunInfo.CPU.Solution.uvh),RunInfo.CPU.WallTime); end - - - if CtrlVar.InitialDiagnosticStep % if not a restart step, and if not explicitly requested by user, then do not do an inital dignostic step + + + if CtrlVar.InitialDiagnosticStep % if not a restart step, and if not explicitly requested by user, then do not do an initial diagnostic step %% diagnostic step, solving for uv. Always needed at a start of a transient run. Also done if asked by the user. CtrlVar.InitialDiagnosticStep=0; - + fprintf(CtrlVar.fidlog,' initial diagnostic step at t=%-.15g \n ',CtrlVar.time); - + + + CtrlVar.Parallel.BuildWorkers=true; + MUA=UpdateMUA(CtrlVar,MUA); [UserVar,RunInfo,F,l,Kuv,Ruv,Lubvb]= uv(UserVar,RunInfo,CtrlVar,MUA,BCs,F,l); - + %ub0=ub ; ud0=ud ; vb0=vb ; vd0=vd; @@ -584,22 +615,31 @@ %% advance the solution by dt using a fully implicit method with respect to u,v and h - - - + + + CtrlVar.time=CtrlVar.time+CtrlVar.dt; % I here need the mass balance at the end of the time step, hence must increase t - F.time=CtrlVar.time ; F.dt=CtrlVar.dt ; + F.time=CtrlVar.time ; F.dt=CtrlVar.dt ; [UserVar,F]=GetMassBalance(UserVar,CtrlVar,MUA,F); CtrlVar.time=CtrlVar.time-CtrlVar.dt; % and then take it back to t at the beginning. - F.time=CtrlVar.time ; F.dt=CtrlVar.dt ; - + F.time=CtrlVar.time ; F.dt=CtrlVar.dt ; + % uvh implicit step (The F on input is based on an explicit estimate, on % return I have the implicit estimate. The explicit estimate is only there to % speed up the non-linear solver. + + if CtrlVar.Parallel.isTest + uvhSolveCompareSequencialAndParallelPerformance(UserVar,RunInfo,CtrlVar,MUA,F0,F,l,BCs); + end + + CtrlVar.Parallel.BuildWorkers=true; + MUA=UpdateMUA(CtrlVar,MUA); [UserVar,RunInfo,F,l,BCs,dt]=uvh(UserVar,RunInfo,CtrlVar,MUA,F0,F,l,l,BCs); - + + + CtrlVar.dt=dt; % I might have changed dt within uvh - + F.dt=dt; if ~RunInfo.Forward.uvhConverged warning("Ua2D:WTSHTF","uvh did not converge") @@ -614,8 +654,9 @@ CtrlVar.time=CtrlVar.time+CtrlVar.dt; + F.time=CtrlVar.time ; F.dt=CtrlVar.dt ; - % Recalulating geometry based on floation not really needed here because uvh + % Recalculating geometry based on flotation not really needed here because uvh % does this implicitly. [F.b,F.s,F.h,F.GF]=Calc_bs_From_hBS(CtrlVar,MUA,F.h,F.S,F.B,F.rho,F.rhow); [F,Fm1]=UpdateFtimeDerivatives(UserVar,RunInfo,CtrlVar,MUA,F,F0); @@ -664,7 +705,7 @@ end end % CtrlVar.TimeDependentRun - %% calculations for this rund step are now done, only some plotting/writing issues do deal with + %% calculations for this run step are now done, only some plotting/writing issues do deal with @@ -700,7 +741,9 @@ end if CtrlVar.WriteRestartFile==1 && mod(CtrlVar.CurrentRunStepNumber,CtrlVar.WriteRestartFileInterval)==0 - WriteForwardRunRestartFile(UserVar,CtrlVar,MUA,BCs,F,F.GF,l,RunInfo); + + WriteForwardRunRestartFile(UserVar,CtrlVar,MUA,BCs,F,F.GF,l,RunInfo); + end @@ -748,7 +791,7 @@ %% saving outputs if CtrlVar.WriteRestartFile==1 && mod(CtrlVar.CurrentRunStepNumber,CtrlVar.WriteRestartFileInterval)~=0 - WriteForwardRunRestartFile(UserVar,CtrlVar,MUA,BCs,F,F.GF,l,RunInfo); + WriteForwardRunRestartFile(UserVar,CtrlVar,MUA,BCs,F,F.GF,l,RunInfo); end if CtrlVar.PlotWaitBar ; multiWaitbar('CloseAll'); end diff --git a/Ua2D_DefaultParameters.m b/Ua2D_DefaultParameters.m index a0d13108..d4572085 100755 --- a/Ua2D_DefaultParameters.m +++ b/Ua2D_DefaultParameters.m @@ -9,9 +9,10 @@ % + %% % -% Most likely when running a, only a fairly limited number of the parameters listed below need to be set/changed. +% Most likely when running Ua, only a fairly limited number of the parameters listed below need to be set/changed. % Changing the parameter values from their default values should be done by the user in `DefineInitialUserInput.m'. % That user m-file should be located in a separate run-directory, together with all the other user m-files @@ -25,6 +26,7 @@ %% Types of run % + CtrlVar.UaRunType="" ; % "-uvh-" , "-uv-h-" , "-uv-" , "-h-" ; @@ -64,7 +66,7 @@ % % Several sliding laws can be defined. These include *Weertman* (power-law relationship % between basal drag and velocity, i.e. u=C tau^m ) and *Coulomb* friction (basal drag equal a constant times -% effective pressure, i.e. tau = mu N). When using Columb friction define mu in +% effective pressure, i.e. tau = mu N). When using Coulomb friction define mu in % DefineSlipperiness.m instead of C. % % The other sliding laws are all just different ways of combining Weertman and Coulomb. @@ -85,7 +87,7 @@ % model, where N=rho g (h-h_f) where h_f is the flotation thickness. % CtrlVar.SlidingLaw="Weertman" ; -CtrlVar.MustBe.SlidingLaw=["Weertman","Budd","Tsai","Coulomb","Cornford","Umbi","W","W-N0","minCW-N0","C","rpCW-N0","rCW-N0"] ; +CtrlVar.MustBe.SlidingLaw=["Weertman","Budd","Tsai","Coulomb","Cornford","Umbi","Joughin","W","W-N0","minCW-N0","C","rpCW-N0","rCW-N0","rCW-V0"] ; %% Boundary conditions CtrlVar.UpdateBoundaryConditionsAtEachTimeStep=0; % if true, `DefineBoundaryConditions.m' is called at the beginning of each time step to update the boundary conditions. % otherwise boundary conditions are only updated at the beginning of the run (also at the beginning or a restart run). @@ -105,7 +107,7 @@ % This is done internally at various different stages. Note that s and b, as % returned by the user in DefineGeometry.m, will be changed to ensure flotation. % -% It is possible to change the default behaviour and calculate h and b from s, B +% It is possible to change the default behavior and calculate h and b from s, B % and S. CtrlVar.Calculate.Geometry="bs-FROM-hBS" ; % {"bs-FROM-hBS" ; "bh-FROM-sBS" } @@ -122,8 +124,8 @@ % % The geometrical variables are: s, b, B and S. % -% To specify which geometrical variables should be updated/modifed set the following -% stings acordingly: +% To specify which geometrical variables should be updated/modified set the following +% stings accordingly: % CtrlVar.GeometricalVarsDefinedEachDiagnosticRunStepByDefineGeometry=""; CtrlVar.GeometricalVarsDefinedEachTransienRunStepByDefineGeometry=""; @@ -149,12 +151,12 @@ CtrlVar.IgnoreComplexPart=1; % it is possible that when solving an asymmetrical system, % numerical errors cause the solution to no longer be real. - % In that case, set to true to simply ignor complex part. + % In that case, set to true to simply ignore complex part. %% Element type % % The options are: linear, quadratic, or cubic Lagrangian triangle elements -CtrlVar.TriNodes=3 ; % Possible values are 3, 6, 10 node (linear/quadradic/cubic) -CtrlVar.MustBe.TriNodes=[3,6,10] ; % Possible values are 3, 6, 10 node (linear/quadradic/cubic) +CtrlVar.TriNodes=3 ; % Possible values are 3, 6, 10 node (linear/quadratic/cubic) +CtrlVar.MustBe.TriNodes=[3,6,10] ; % Possible values are 3, 6, 10 node (linear/quadratic/cubic) %% Control on transient runs % Once either the number of time steps or total time modeled reaches prescribed values % the run stops. @@ -169,7 +171,7 @@ % 1) so demanded by the user, i.e. if the user sets CtrlVar.InitialDiagnosticStep=1, and % 2) at always at the start of an implicit uvh transient run which is not a % restart run. - % Howere, unless demanded by the user, no initial diagnostic step is done at the beginning of a transient restart run. + % However, unless demanded by the user, no initial diagnostic step is done at the beginning of a transient restart run. CtrlVar.InitialDiagnosticStepAfterRemeshing=0 ; % Forces a diagnostic calculation after re-meshing. % Note: a diagnostic calculation is always done after global re-meshing @@ -291,7 +293,7 @@ %% Explicit estimation % -% In a transient run u, v and h can estimated explicity ahead of an implicit uvh +% In a transient run u, v and h can estimated explicitly ahead of an implicit uvh % calculation. If the explicit estimate is a good starting point, then the number of % non-linear uvh iterations is reduced. One can either use second-order Adams-Bashforth % method for a variable time step, or calculate dh/dt explicitly from flux convergence and @@ -305,7 +307,7 @@ CtrlVar.MustBe.ExplicitEstimationMethod=["-Adams-Bashforth-","-dhdt-","-no extrapolation-"] ; CtrlVar.LimitRangeInUpdateFtimeDerivatives=false ; %% Numerical Regularization Parameters (note: these are not related to inverse modeling regularization) -% Note: Some of those paramters have physical dimentions and these values may have to be +% Note: Some of those parameters have physical dimensions and these values may have to be % adjusted to the specific situation. CtrlVar.SpeedZero=1e-4; % needs to be larger than 0 but should also be much smaller than any velocities of interest. CtrlVar.EpsZero=1e-10; % needs to be larger than 0 but should also be much smaller than any effective strain rates of interest. @@ -318,7 +320,7 @@ % taking A for temperate ice and strain rates of 1 (1/yr). % giving: % n=3 ; eps=1 ; 0.5*AGlenVersusTemp(0)^(-1/n) *181 eps^((1-n)/n) =181 -% So settting etaZero=10 kPa/yr would not affect the effective viscosity +% So setting etaZero=10 kPa/yr would not affect the effective viscosity % in all realistic cases. However, this might % sometimes need to me adjusted. Before May-2023 the % default value was etaZero=0, ie no lower limit on @@ -398,7 +400,7 @@ % 2) If the step length in the backtracking becomes smaller than CtrlVar.uvhExitBackTrackingStepLength=1e-3; -% while at the same time these Work and Force tolerances also fullfilled: +% while at the same time these Work and Force tolerances also fulfilled: CtrlVar.uvhAcceptableWorkAndForceTolerances=[inf 1e-6]; CtrlVar.uvhAcceptableWorkOrForceTolerances=[1 1e-8]; @@ -427,9 +429,9 @@ -CtrlVar.uvhMinimisationQuantity="Force Residuals"; % used in SSTREAM/SSA when solving implictly for u, v, and h -CtrlVar.uvMinimisationQuantity="Force Residuals"; % used in SSTREAM/SSA when solving implictly for velocities. -CtrlVar.hMinimisationQuantity="Force Residuals"; % used in SSHEET/SIA when solving implictly for h +CtrlVar.uvhMinimisationQuantity="Force Residuals"; % used in SSTREAM/SSA when solving implicitly for u, v, and h +CtrlVar.uvMinimisationQuantity="Force Residuals"; % used in SSTREAM/SSA when solving implicitly for velocities. +CtrlVar.hMinimisationQuantity="Force Residuals"; % used in SSHEET/SIA when solving implicitly for h CtrlVar.LSFMinimisationQuantity="Force Residuals"; CtrlVar.MustBe.uvhMinimisationQuantity=["Force Residuals","Work Residuals"]; @@ -471,7 +473,7 @@ CtrlVar.ModifiedNRuvReductionCriterion=0.5; % fractional reduction forcing an update CtrlVar.ModifiedNRuvhIntervalCriterion=1; CtrlVar.ModifiedNRuvhReductionCriterion=0.5; -% Settingn for example: +% Setting for example: % CtrlVar.ModifiedNRuvIntervalCriterion=10; % CtrlVar.ModifiedNRuvReductionCriterion=0.95; % will cause the matrix only to be updated every 10-th non-linear iteration, unless @@ -490,7 +492,7 @@ CtrlVar.NewtonBacktrackingBeta=1e-4; % affects the Amarijo exit criteria in the back-stepping CtrlVar.LineSearchAllowedToUseExtrapolation=0; % If true, backtracking algorithm may start with an extrapolation step. CtrlVar.BacktrackingGammaMin=1e-10; % smallest step-size in Newton/Picard backtracking as a fraction of the full Newton/Picard step. -CtrlVar.BacktrackingGammaMinAdjoint=1e-20; % smallest step-size allowed while backtracking in adjoint step. (This is an absolut step size, i.e. not a fraction of initial step size.) +CtrlVar.BacktrackingGammaMinAdjoint=1e-20; % smallest step-size allowed while backtracking in adjoint step. (This is an absolute step size, i.e. not a fraction of initial step size.) CtrlVar.GuardAgainstWildExtrapolationInExplicit_uvh_Step=0; @@ -508,7 +510,7 @@ CtrlVar.BackTrackMinXfrac=1e-10 ; % exit backtracking if pos. of minimum is changing by less than this fraction of initial step CtrlVar.BackTrackMaxFuncSame=3 ; % exit backtracking if this many evaluations of cost function resulted in no further decrease of cost function -% Limit stepsize based on quadradic/cubic interpolation to these lower/upper +% Limit stepsize based on quadratic/cubic interpolation to these lower/upper % limits withing the current lower/upper range. CtrlVar.BackTrackGuardLower=0.25; CtrlVar.BackTrackGuardUpper=0.95; @@ -517,10 +519,10 @@ % ratio is smaller than: CtrlVar.BackTrackContinueIfLastReductionRatioLessThan=0.5; % The ratio is CurrentValue/LastValue, so smaller ratio means greater reduction. -% Note: The inital target is CtrlVar.NewtonAcceptRatio, and +% Note: The initial target is CtrlVar.NewtonAcceptRatio, and % after that target=f(0)+CtrlVar.BackTrackBeta slope step % CurrentValue/InitalValue < CtrlVar.NewtonAcceptRatio -% unless some other exit critera are reached. +% unless some other exit criteria are reached. %% Lin equation solver parameters % @@ -528,14 +530,14 @@ % Solver (ALS) % % -% The matlab \ operator sometimes fails for indefinite block matrices. For +% The MATLAB \ operator sometimes fails for indefinite block matrices. For % that reason the default linear solver is Augmented Lagrangian Solver (ALS) % % ALS uses an outer iteration and the inner problem is solved direction. Usually % only a few outer iterations are required. % % For asymmetrical indefinite block-structured systems the ALS method is almost -% always better than the default Matlab backslash operator. ALS is an iterative +% always better than the default MATLAB backslash operator. ALS is an iterative % method with an inner and outer iteration. Convergence depends on % ALSpower. If ALS does not converge then tying a smaller ALSpower % usually does the trick. @@ -545,12 +547,12 @@ CtrlVar.ALSIterationMin=3; CtrlVar.ALSIterationMax=25; CtrlVar.ALSpower=5; % ALS parameters CtrlVar.UzawaIterationMin=3; CtrlVar.UzawaIterationMax=25; CtrlVar.UzawaPower=5; % Uzawa parameters CtrlVar.LinSolveTol=1e-8; % Residual when solving linear system. - % If the standard Matlab backslash algorithm is used, default Matlab values apply and this number is not used + % If the standard MATLAB backslash algorithm is used, default MATLAB values apply and this number is not used % For indefinite block-structured systems of the type [A B' ; B 0] [x;y]=[f;g] % the relative residual is defined in standard way as: % Residual=norm([A B' ; B sparse(m,m)]*[x;y]-[f ; g])/norm([f;g]); - % A value of 1e-8 is arguably alread a relativily small number, in many cases 1e-6 would be considered acceptable -CtrlVar.Solve.LUvector=false; % LU factorisation done using vector format, consider seeting to true if memory an issue + % A value of 1e-8 is arguably already a relatively small number, in many cases 1e-6 would be considered acceptable +CtrlVar.Solve.LUvector=false; % LU factorisation done using vector format, consider setting to true if memory an issue %% Internal variables related to matrix assembly % These variables are only for testing purposes. Do not change from default @@ -580,9 +582,8 @@ % Depending on info levels, figures might be plotted as well. However, this is only done % if corresponding plotting logicals such as CtrlVar.doplots, CtrlVar.doAdaptMeshPlot, etc, are also true. % -% Further description of what infomation is provided depending on the values of the info parameters is provided below. -% -% If you, for example set, +% Further description of what information is provided depending on the values of the info parameters is provided below. +%% If you, for example set, % % CtrlVar.InfoLevelNonLinIt=5 ; CtrlVar.InfoLevelBackTrack=100; % @@ -616,7 +617,7 @@ % 1 : basic convergence information at end of non-linear step. % >1 : detailed info on residuals given at the end of non-linear step. % >=2 : info on backtracking step as well. -% >=5 : plots change in velocites and ice thickness over each uvh time step, and basal drag vectors +% >=5 : plots change in velocities and ice thickness over each uvh time step, and basal drag vectors % >=10 : calculates/plots additional info on residuals as a function of step size within line search, and rate of convergence % >=100 : plots residual vectors % @@ -634,12 +635,15 @@ % are both true. % % 0 : no information on adaptive meshing printed. -% >=10 : plots showing mesh before and at the end of each mesh adaptaion. +% >=10 : plots showing mesh before and at the end of each mesh adaption. % >=100 : Further plots on changes in mesh during an adapt mesh iteration produced. % % % -CtrlVar.InfoLevelAdaptiveMeshing=1; +CtrlVar.InfoLevelAdaptiveMeshing=1; % Information related to adapt meshing + % 1 : default basic information + % 10 : additional plots, e.g showing element to be deactivated, refine or coarsened. + % But plots are only produced if additionally CtrlVar.doplots=true ; CtrlVar.InfoLevelLinSolve=0; % If the linear solver does not converge (it sometimes uses a inner and outer loop to deal with indefinite systems) % then increasing this number will give further information. G @@ -653,10 +657,10 @@ CtrlVar.InfoLevelBackTrack=1; % Controls information given during backtracking. % As with other info parameters, higher values provide more information % 10 : - % 100 : plots evaluated function values along the backtracking direciton - % 1000 : plots backtracking with further addional values calculated at regular intervales along the step, and prints detailed info about backtracking + % 100 : plots evaluated function values along the backtracking direction + % 1000 : plots backtracking with further additional values calculated at regular intervals along the step, and prints detailed info about backtracking -CtrlVar.InfoLevelCPU=0; % if 1 then some info on CPU time usage is given +CtrlVar.InfoLevelCPU=0; % if 10 or higher then some info on CPU time usage is given CtrlVar.StandartOutToLogfile=false ; % if true standard output is directed to a logfile % name of logfile is $Experiment.log @@ -754,28 +758,28 @@ % % The gradient calculation is exact, well as exact as a numerical method can be expected to be exact. % -% The Hessian of the regularisation term is exact, but the Hessian of the misfit term is approximated (see details in the Ua +% The Hessian of the regularization term is exact, but the Hessian of the misfit term is approximated (see details in the Ua % Compendium) % -% The optimisation step in the inversion can then be done using either the Matlab optimisationo toolbox, or an some Ua optimisation +% The optimization step in the inversion can then be done using either the Matlab optimization toolbox, or an some Ua optimization % routines. % -% Default is to use Hessian based optimisation, which uses both the gradient and the Hessian approximation, or gradient-based -% minimisation, which only uses the gradient and builds up an approximation of the Hessian from the gradient. +% Default is to use Hessian based optimization, which uses both the gradient and the Hessian approximation, or gradient-based +% minimization, which only uses the gradient and builds up an approximation of the Hessian from the gradient. % -% The default option is Hessian-based optimisation using the matlab optimisation toolbox. +% The default option is Hessian-based optimization using the matlab optimization toolbox. % -CtrlVar.Inverse.MinimisationMethod="MatlabOptimization-HessianBased"; % Hessian-based, Matlab toolbox -% ="MatlabOptimization-GradientBased"; % gradient-based, Matlab toolbox -% ="UaOptimization-GradientBased"; % gradient-based, Ua optimisation toolbox -% ="UaOptimization-HessianBased"; % Hessian-based, Ua optimisation toolbox +CtrlVar.Inverse.MinimisationMethod="MatlabOptimization-HessianBased"; % Hessian-based, MATLAB toolbox +% ="MatlabOptimization-GradientBased"; % gradient-based, MATLAB toolbox +% ="UaOptimization-GradientBased"; % gradient-based, Ua optimization toolbox +% ="UaOptimization-HessianBased"; % Hessian-based, Ua optimization toolbox -% If a Hessian-based optimisation is used, the the expressions for the Hessians can be selected as follows: +% If a Hessian-based optimization is used, the the expressions for the Hessians can be selected as follows: CtrlVar.Inverse.Hessian="RHA=E RHC=E IHC=FP IHA=FP"; -% Here R stands for Regularisation and I stands for Misfit. +% Here R stands for Regularization and I stands for Misfit. % E stands for 'exact' and 'FP' for 'fixed-point' % -% So RHA=E implies that the Hessian (H) for the AGlen (A) regularisation term (R) is based on the exact (E) expression for H. +% So RHA=E implies that the Hessian (H) for the AGlen (A) regularization term (R) is based on the exact (E) expression for H. % So IHC=FP implies that the Hessian (H) for the AGlen (C) misfit term (I) is based on the exact 'fixed-point' (FP) expression for H. @@ -789,7 +793,10 @@ % and with respect to the l2 inner product when using the I pre-multiplier. % -CtrlVar.Inverse.Iterations=1; % Number of inverse iterations +CtrlVar.Inverse.Iterations=1; % Maximum number of inverse iterations +CtrlVar.Inverse.OptimalityTolerance=1e-10; % see MATLAB documentation on the use of the fmincon function, needed for inversion using the matlab optimisation toolbox +CtrlVar.Inverse.FunctionTolerance=1 ; % see MATLAB documentation on the use of the fmincon function, needed for inversion using the matlab optimisation toolbox +CtrlVar.Inverse.StepTolerance=1e-30 ; % see MATLAB documentation on the use of the fmincon function, needed for inversion using the matlab optimisation toolbox CtrlVar.Inverse.WriteRestartFile=1; % always a good idea to write a restart file. CtrlVar.Inverse.NameOfRestartOutputFile='InverseRestart.mat'; @@ -802,9 +809,9 @@ %% % -% Inversion can be done using mesurements of: +% Inversion can be done using measurements of: % -% * horizontal velocites (uv) +% * horizontal velocities (uv) % * rate of thickness change (dh/dt). % % To select which types of surface measurements to use in the inversion set: @@ -878,7 +885,7 @@ % -] CtrlVar.Inverse.StoreSolutionAtEachIteration=0; % if true then inverse solution at each iteration is saved in the RunInfo variable. %% -% I and R are multiplied by these following DataMisit and Regularisation +% I and R are multiplied by these following DataMisit and Regularization % multipliers. This is a convening shortcut of getting rid of either the misfit % (I) or the regularization term (R) in the objective function (J) altogether. CtrlVar.Inverse.DataMisfit.Multiplier=1; @@ -917,10 +924,10 @@ % % Refer to the matlab documentation for further information. % -% The optimization routines used are either the matlab routine fminunc or +% The optimization routines used are either the MATLAB routine fminunc or % fmincon. % -% You will need to have the matlab optimisation toolbox to be able to do this. +% You will need to have the MATLAB optimization toolbox to be able to do this. % % The Matlab optimization toolbox has various algorithms to choose from, each of % which has large number of parameters. @@ -995,11 +1002,11 @@ 'FunValCheck','off',... 'MaxFunctionEvaluations',1e6,... 'MaxIterations',CtrlVar.Inverse.Iterations,...,... - 'OptimalityTolerance',1e-20,... + 'OptimalityTolerance',CtrlVar.Inverse.OptimalityTolerance,... 'OutputFcn',@fminuncOutfun,... 'PlotFcn',{@optimplotlogfval,@optimplotstepsize},... - 'StepTolerance',1e-30,... - 'FunctionTolerance',1,... + 'StepTolerance',CtrlVar.Inverse.StepTolerance,... + 'FunctionTolerance',CtrlVar.Inverse.FunctionTolerance,... 'UseParallel',true,... 'HessianApproximation',{'lbfgs',250},... 'HessianFcn',[],... @@ -1010,7 +1017,7 @@ 'SubproblemAlgorithm','cg'); % here the options are ' % These are the default parameters using Hessian based inversion with the MATLAB optimisation toolbox - Hfunc=@(p,lambda) p+lambda ; % just needs to defined here, this is then later replaced with a function that returns the Hessian estmation. + Hfunc=@(p,lambda) p+lambda ; % just needs to defined here, this is then later replaced with a function that returns the Hessian estimation. CtrlVar.Inverse.MatlabOptimisationHessianParameters = optimoptions('fmincon',... 'Algorithm','interior-point',... 'CheckGradients',false,... @@ -1023,11 +1030,11 @@ 'FunValCheck','off',... 'MaxFunctionEvaluations',1e6,... 'MaxIterations',CtrlVar.Inverse.Iterations,...,... - 'OptimalityTolerance',1e-20,... + 'OptimalityTolerance',CtrlVar.Inverse.OptimalityTolerance,... 'OutputFcn',@fminuncOutfun,... 'PlotFcn',{@optimplotlogfval,@optimplotstepsize},... - 'StepTolerance',1e-30,... - 'FunctionTolerance',1,... + 'StepTolerance',CtrlVar.Inverse.StepTolerance,... + 'FunctionTolerance',CtrlVar.Inverse.FunctionTolerance,... 'UseParallel',true,... 'HessianFcn',Hfunc,... 'HessianMultiplyFcn',[],... @@ -1163,7 +1170,7 @@ % *By default a uses mesh2d* % % -% When generating the mesh from within a the procedures involved are identical, irrespectivly of whether it is gmsh or mesh2d wich is being +% When generating the mesh from within a the procedures involved are identical, irrespective of whether it is gmsh or mesh2d wich is being % used. In either case the outlines of the mesh are % defined by the variable % @@ -1236,7 +1243,7 @@ % % %CtrlVar.MeshGenerator="gmsh"; % possible values: {mesh2d|gmsh} -CtrlVar.MeshGenerator="mesh2d"; % this is the deault option +CtrlVar.MeshGenerator="mesh2d"; % this is the default option CtrlVar.MustBe.MeshGenerator=["mesh2d","gmsh"]; %% Options related to the use of the gmsh external mesh generator @@ -1365,8 +1372,8 @@ CtrlVar.MaxNumberOfNewlyIntroducedActiveThicknessConstraints=1000 ; % In any active-set iteration, this is the maximum number of additional new constraints -CtrlVar.MinNumberOfNewlyIntroducedActiveThicknessConstraints=5; % In any active-set iteration, this is the min number of additional new constraints. - % This can be used to surpress new active-set iteration if only a few new constraints are identified. +CtrlVar.MinNumberOfNewlyIntroducedActiveThicknessConstraints=0; % In any active-set iteration, this is the min number of additional new constraints. + % This can be used to suppress new active-set iteration if only a few new constraints are identified. % The exact number here can be expected to be problem dependent, but it seems safe to assume that if only % a few new constraints need to be activated or de-activated, no-new active set iteration is needed. Here the number 5 has % been defined as being "a few". @@ -1374,15 +1381,18 @@ % thickness barrier, option 3 CtrlVar.ThicknessBarrier=1; % set to 1 for using the barrier method (Option 3) - % additonal mass-balance term, ab, on the form: + % additional mass-balance term, ab, on the form: % ab = a1*(h-hmin)+a3*(hint-hmin).^3) % is added, and applied at integration points where hnElements + nPadding=max(2*nElements,index) ; + Padding=nan(nPadding,1); + else + return + end + + if contains(CtrlVar.UaRunType,["-uvh-","-uv-"]) + + + + obj.Forward.time=resize(obj.Forward.time,nPadding,FillValue=nan) ; + obj.Forward.dt=resize(obj.Forward.dt,nPadding,FillValue=nan) ; + + obj.Forward.uvhIterations=resize(obj.Forward.uvhIterations,nPadding,FillValue=nan) ; + obj.Forward.uvhResidual=resize(obj.Forward.uvhResidual,nPadding,FillValue=nan) ; + obj.Forward.uvhBackTrackSteps=resize(obj.Forward.uvhBackTrackSteps,nPadding,FillValue=nan) ; + + obj.Forward.uvhActiveSetIterations=resize(obj.Forward.uvhActiveSetIterations,nPadding,FillValue=nan) ; + obj.Forward.uvhActiveSetCyclical=resize(obj.Forward.uvhActiveSetCyclical,nPadding,FillValue=nan) ; + obj.Forward.uvhActiveSetConstraints=resize(obj.Forward.uvhActiveSetConstraints,nPadding,FillValue=nan) ; + + obj.Forward.uvIterations=resize(obj.Forward.uvIterations,nPadding,FillValue=nan) ; + obj.Forward.uvResidual=resize(obj.Forward.uvResidual,nPadding,FillValue=nan) ; + obj.Forward.uvBackTrackSteps=resize(obj.Forward.uvBackTrackSteps,nPadding,FillValue=nan) ; + + + end + if contains(CtrlVar.UaRunType,"-h-") + + obj.Forward.hIterations=[obj.Forward.hIterations;Padding]; + obj.Forward.hResidual=[obj.Forward.hResidual;Padding]; + obj.Forward.hBackTrackSteps=[obj.Forward.hBackTrackSteps;Padding]; + + + end + + if CtrlVar.LevelSetMethod + + Padding=NaN(nPadding,1); + obj.LevelSet.time=[obj.LevelSet.time;Padding]; + obj.LevelSet.Iterations=[obj.LevelSet.Iterations;Padding]; + obj.LevelSet.Residual=[obj.LevelSet.Residual;Padding]; + obj.LevelSet.BackTrackSteps=[obj.LevelSet.BackTrackSteps;Padding]; + obj.LevelSet.Phase=[obj.LevelSet.Phase;strings(nPadding,1)]; + + + end + end end methods (Static) @@ -126,15 +198,15 @@ if ~isfield(s.Forward,'uvhIterations') - N=1000; % initial memory allocation - obj.Forward.time=zeros(N,1)+NaN; - obj.Forward.dt=zeros(N,1)+NaN; - obj.Forward.uvhIterations=zeros(N,1)+NaN; - obj.Forward.uvhResidual=zeros(N,1)+NaN; - obj.Forward.uvhBackTrackSteps=zeros(N,1)+NaN; - obj.Forward.uvhActiveSetIterations=zeros(N,1)+NaN; - obj.Forward.uvhActiveSetCyclical=zeros(N,1)+NaN; - obj.Forward.uvhActiveSetConstraints=zeros(N,1)+NaN; + N=2; % initial memory allocation + obj.Forward.time=NaN(N,1); + obj.Forward.dt=NaN(N,1); + obj.Forward.uvhIterations=NaN(N,1); + obj.Forward.uvhResidual=NaN(N,1); + obj.Forward.uvhBackTrackSteps=NaN(N,1); + obj.Forward.uvhActiveSetIterations=NaN(N,1); + obj.Forward.uvhActiveSetCyclical=NaN(N,1); + obj.Forward.uvhActiveSetConstraints=NaN(N,1); end @@ -152,20 +224,7 @@ if ~isfield(s.Forward,'hiCount') obj.Forward.hiCount=0; end - - % I got rid of this counter, if I keep this in here, these fields will always be set to zero on load - % if ~isfield(s.Forward,'iCounter') - % - % N=1000; % initial memory allocation - % obj.Forward.time=zeros(N,1)+NaN; - % obj.Forward.dt=zeros(N,1)+NaN; - % obj.Forward.uvhIterations=zeros(N,1)+NaN; - % obj.Forward.uvhResidual=zeros(N,1)+NaN; - % obj.Forward.uvhBackTrackSteps=zeros(N,1)+NaN; - % obj.Forward.uvhActiveSetIterations=zeros(N,1)+NaN; - % obj.Forward.uvhActiveSetCyclical=zeros(N,1)+NaN; - % obj.Forward.uvhActiveSetConstraints=zeros(N,1)+NaN; - % end + if ~isfield(s.Forward,'ubvbRecalculatedOnNewMesh') obj.Forward.ubvbRecalculatedOnNewMesh=false; diff --git a/UaUtilities/BedMachineToUaGriddedInterpolants.m b/UaUtilities/BedMachineToUaGriddedInterpolants.m index 0a768ad1..8d0a3cc0 100644 --- a/UaUtilities/BedMachineToUaGriddedInterpolants.m +++ b/UaUtilities/BedMachineToUaGriddedInterpolants.m @@ -1,7 +1,7 @@ function [Fs,Fb,FB,Frho,Boundary]=BedMachineToUaGriddedInterpolants(filename,N,LakeVostok,BoundaryResolution,SaveOutputs) %% -% Reads BedMachine nc file and creates Úa gridded interpolants with s, b, B and rho. +% Reads BedMachine nc file and creates Ua gridded interpolants with s, b, B and rho. % % Note: This is just a rough idea as to how this could be done and most likely will need some modifications for some particular % applications. diff --git a/UaUtilities/CalcIceShelfMeltRates.m b/UaUtilities/CalcIceShelfMeltRates.m index 0f3557ab..57c9fe0f 100644 --- a/UaUtilities/CalcIceShelfMeltRates.m +++ b/UaUtilities/CalcIceShelfMeltRates.m @@ -4,7 +4,7 @@ % % ab=CalcIceShelfMeltRates(CtrlVar,MUA,u,v,s,b,S,B,rho,rhow,dsdt,as,dhdt) % -% Calculates basal meltrate from ice-flux divergence, surface mass balance (as) and surface elevation rate changes (dsdt) or alternativily from +% Calculates basal melt-rate from ice-flux divergence, surface mass balance (as) and surface elevation rate changes (dsdt) or alternatively from % rates of thickness change (dhdt). % % Just a rough way of doing this...please look through the code and adjust as you feel needed. @@ -15,7 +15,7 @@ % % where: % dhdt is the rate of thickness change -% dqxdx and dqydy are the flux gradients calcuated from u, v, h, and rho +% dqxdx and dqydy are the flux gradients calculated from u, v, h, and rho % as is the surface accumulation in meters of water equivalent % % Note: It is very likely that the calculated ab values need to me smoothed or regularized. Smoothing can, for example, be done @@ -25,7 +25,7 @@ % % giving the system (R+P) ab = P F % -% where F is this function, and R and P regularisation and likelyhood inverse covariances. +% where F is this function, and R and P regularization and likelihood inverse covariance. % % % Example would be: diff --git a/UaUtilities/CalcVAF.m b/UaUtilities/CalcVAF.m index 4321c035..10dfcc0b 100755 --- a/UaUtilities/CalcVAF.m +++ b/UaUtilities/CalcVAF.m @@ -119,7 +119,7 @@ hold on ; PlotGroundingLines(CtrlVar,MUA,GF,[],[],[],'r'); xlabel("xps (km)",interpreter="latex") ; ylabel("yps (km)",interpreter="latex") ; title(cbar,"(m)") ; title("ice thickness above flotation") - fprintf("VAF=%f (Gt/yr)\n",VAF.Total/1e9) ; + fprintf("VAF=%f (Gt)\n",VAF.Total/1e9) ; fprintf("GroundedArea=%-7.2f (times the area of iceland)\n",GroundedArea.Total/1e6/103e3) ; colormap(othercolor('Blues7',1024)); diff --git a/UaUtilities/DraftDependentMeltParameterisations.m b/UaUtilities/DraftDependentMeltParameterisations.m index 9572243f..13245ac0 100755 --- a/UaUtilities/DraftDependentMeltParameterisations.m +++ b/UaUtilities/DraftDependentMeltParameterisations.m @@ -11,11 +11,11 @@ % ab is : abMin for F.b>dMin % abMax for F.b3 && ~isempty(ElementList) - connectivity=connectivity(ElementList,:); - if islogical(ElementList) - ElementNumbers=find(ElementList); +if nargin>3 + if isempty(ElementList) + % fprintf("PlotFEmesh:Element list is empty. Not plotting any elements.\n") + hTri=[]; + return else - ElementNumbers=ElementList; + connectivity=connectivity(ElementList,:); + if islogical(ElementList) + ElementNumbers=find(ElementList); + else + ElementNumbers=ElementList; + end end else ElementNumbers=1:size(connectivity,1); diff --git a/UaUtilities/PlotGroundingLines.m b/UaUtilities/PlotGroundingLines.m index a32f393b..fbc542dc 100755 --- a/UaUtilities/PlotGroundingLines.m +++ b/UaUtilities/PlotGroundingLines.m @@ -99,7 +99,7 @@ end if isempty(CtrlVar) - CtrlVar.PlotXYscale=1000; + CtrlVar(1).PlotXYscale=1000; CtrlVar.PlotIndividualGLs=0; CtrlVar.PlotGLs=1; end @@ -137,7 +137,11 @@ if CtrlVar.PlotGLs tt=axis; - plot(xGL/CtrlVar.PlotXYscale,yGL/CtrlVar.PlotXYscale,varargin{:}) ; + if isempty(varargin) + plot(xGL/CtrlVar.PlotXYscale,yGL/CtrlVar.PlotXYscale,'r') ; + else + plot(xGL/CtrlVar.PlotXYscale,yGL/CtrlVar.PlotXYscale,varargin{:}) ; + end ax=gca; ax.DataAspectRatio=[1 1 1]; if ~isequal(tt,[0 1 0 1]) diff --git a/UaUtilities/PlotLatLonGrid.m b/UaUtilities/PlotLatLonGrid.m index 1f9f2d3d..f2d2dc45 100644 --- a/UaUtilities/PlotLatLonGrid.m +++ b/UaUtilities/PlotLatLonGrid.m @@ -8,14 +8,14 @@ %% % Plots a lat lon grid % -% This is written for the Antarctica setting using polar stereographic coordinate system. +% This is written for the Antarctica setting using polar stereo-graphic coordinate system. % % % % [Lat,Lon,X0,Y0,Clat,hlat,Clon,hlon]=PlotLatLonGrid(scale,dlat,dlon,LabelSpacing,Colour,isCircumpolar) % % -% Inputes: +% Inputs: % % scale ; scales the x and the y axis. For example if the x,y units are meters, but you want to plot using km as a % distance units, set scale=1000 @@ -26,21 +26,23 @@ % lon labels. % % Colour: color of the lat, lon lines -% -% isCircumpolar: set to true if the plot area is circumpolar, ie includes the pole itself. + + +% +% isCircumpolar: set to true if the plot area is circumpolar, ie includes the pole itself. % % % Outputs: % % Clat,hlat,Clon,hlon : These are the contour matrices and the contour objects. The contour objects allow the properties -% of the countour plots to be easily edited after the call. +% of the contour plots to be easily edited after the call. % % % % NOTE #1: Do not use figure zoom after this or the lat/lon lin will get misaligned! -% Despite best atempts I have not been able to link the axis and get the right behaviour. +% Despite best attempts I have not been able to link the axis and get the right behavior. % -% NOTE #2: As of Matlab2023b, Note#1 is no longer of relevance, which is good news! +% NOTE #2: As of Matlab2023b, Note#1 is no longer of relevance, which is good news! % % % Example: @@ -129,15 +131,23 @@ %% -% set some plausible values if user has not defined those already -if isCircumpolar && isempty(dlat) && isempty(dlon) && isempty(LabelSpacing) +if nargin ==0 - dlat=10; - dlon=45; - LabelSpacing=200; + % guessing here a bit -else + if (xmax-xmin)< 300 % assuming km as units + dlon=5; + end + if (ymax-ymin)< 400 % assuming km as units + dlat=1; + end + + +end + +% set some plausible values if user has not defined those already +if isempty(dlat) && isempty(dlon) && isempty(LabelSpacing) if isempty(dlat) dlat=5; @@ -163,7 +173,7 @@ climCopy=clim; -[X0,Y0]=meshgrid(linspace(xmin,xmax,400),linspace(ymin,ymax,400)); +[X0,Y0]=meshgrid(linspace(xmin,xmax,800),linspace(ymin,ymax,800)); [Lat,Lon]=pol_to_geog_wgs84_71S(X0*scale,Y0*scale); @@ -171,7 +181,7 @@ I=Lat>-62; Lon(I)=NaN ; Lat(I)=NaN; I=Lat>-64.9; Lon(I)=NaN; I=Lat<-85.1 ; Lon(I)=NaN; - I=Lat<-86 ; Lat(I)=NaN ; + I=Lat<-85.1 ; Lat(I)=NaN ; I=Lon<-171 ; Lon(I)=Lon(I)+360; I=Lon<-170 ; Lon(I)=NaN; end @@ -180,7 +190,7 @@ hold on -[Clat,hlat]=contour(ax1,X0,Y0,Lat,-90:dlat:90,LineColor=lcol,LabelFormat=@mylabelfunLat); +[Clat,hlat]=contour(ax1,X0,Y0,Lat,-85:dlat:85,LineColor=lcol,LabelFormat=@mylabelfunLat); set(hlat,'ShowText','on','TextStep',get(hlat,'LevelStep')*2,'LabelSpacing',LabelSpacing) @@ -203,7 +213,7 @@ clim(climCopy) % set color axis limit to the value at the beginning of the call - % this is done here because the contour functions above might change the existing limites +% this is done here because the contour functions above might change the existing limites function labels=mylabelfunLon(vals) diff --git a/UaUtilities/PlotMuaMesh.m b/UaUtilities/PlotMuaMesh.m index 8d7bf5eb..64225a21 100755 --- a/UaUtilities/PlotMuaMesh.m +++ b/UaUtilities/PlotMuaMesh.m @@ -15,11 +15,11 @@ % Plot Mesh in red: % % load('MUA-PIG-TWG-Example.mat','MUA','BCs','CtrlVar') -% figure ; PlotMuaMesh([],MUA,[],'r') +% figure ; PlotMuaMesh([],MUA,nan,'r') % % or % -% figure ; PlotMuaMesh(CtrlVar,MUA,[],color="r"); +% figure ; PlotMuaMesh(CtrlVar,MUA,nan,color="r"); % % % Plot the first 10000 elements in black: @@ -52,7 +52,9 @@ if isempty(CtrlVar) - CtrlVar.PlotLabels=0; + + CtrlVar.PlotEleLabels=0; + CtrlVar.PlotNodalLabels=0; CtrlVar.MeshColor='k'; CtrlVar.NodeColor='k'; CtrlVar.PlotXYscale=1; @@ -78,7 +80,9 @@ ElementList=1:MUA.Nele; end - +if isnan(ElementList) % this is a special short cut which allows nan to imply that all elements should be plotted + ElementList=1:MUA.Nele; +end if ischar(ElementList) && nargin==3 % silently ignore the fact that the user clearly did not read the comments and @@ -103,7 +107,8 @@ [Emin,Emax,Emean,Emedian]=PrintInfoAboutElementsSizes(CtrlVar,MUA,print=false) ; -title(sprintf("#Ele=%i #Nodes=%i #nod=%i \n (max,mean,median,min)=(%g,%g,%g,%g) ",MUA.Nele,MUA.Nnodes,MUA.nod,Emax,Emean,Emedian,Emin)) + +title(sprintf("\\#Ele=%i \\#Nodes=%i \\#nod=%i \n (max,mean,median,min)=(%g,%g,%g,%g) ",MUA.Nele,MUA.Nnodes,MUA.nod,Emax,Emean,Emedian,Emin),Interpreter="latex") if ~nargout % A trick to suppress any function output if no output requested. No need to suppress output using ; clearvars hTri diff --git a/UaUtilities/PlotNodalBasedQuantities.m b/UaUtilities/PlotNodalBasedQuantities.m index 7d1e4677..6ecabcdb 100755 --- a/UaUtilities/PlotNodalBasedQuantities.m +++ b/UaUtilities/PlotNodalBasedQuantities.m @@ -22,7 +22,7 @@ %% Check inputs if nargin<4 || isempty(CtrlVar) - CtrlVar.PlotXYscale=1; + CtrlVar(1).PlotXYscale=1; CtrlVar.PlotsXaxisLabel=' '; CtrlVar.PlotsYaxisLabel=' '; end diff --git a/UaUtilities/PlotResultsFromInversion.m b/UaUtilities/PlotResultsFromInversion.m index 57f9179f..b96ec172 100755 --- a/UaUtilities/PlotResultsFromInversion.m +++ b/UaUtilities/PlotResultsFromInversion.m @@ -14,6 +14,19 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, % %% +if isstring(UserVar) && isfile(UserVar) + + fprintf("loading and printing results from %s \n",UserVar) + + load(UserVar,"UserVarInRestartFile","CtrlVarInRestartFile","MUA","BCs","F","l","InvStartValues","InvFinalValues","Priors","Meas","BCsAdjoint","RunInfo") ; + + CtrlVar=CtrlVarInRestartFile; + UserVar=UserVarInRestartFile; + +end + +%% + fprintf(' Plotting results from inversion...') CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; @@ -21,7 +34,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, x=MUA.coordinates(:,1); y=MUA.coordinates(:,2); -GLgeo=GLgeometry(MUA.connectivity,MUA.coordinates,GF,CtrlVar); xGL=[] ; yGL=[] ; +GLgeo=GLgeometry(MUA.connectivity,MUA.coordinates,F.GF,CtrlVar); xGL=[] ; yGL=[] ; %% @@ -38,7 +51,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(Iplot,Jplot,Kplot) PlotMeshScalarVariable(CtrlVar,MUA,Meas.us) ; -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,'interpreter','latex'); ylabel(CtrlVar.PlotsYaxisLabel,'interpreter','latex'); @@ -48,17 +61,17 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(Iplot,Jplot,Kplot) PlotMeshScalarVariable(CtrlVar,MUA,Meas.vs) ; hold on ; -[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,'interpreter','latex'); ylabel(CtrlVar.PlotsYaxisLabel,'interpreter','latex'); title('vs Meas on numerical grid') ; -if ~isempty(Meas.dhdt) +if ~isempty(Meas.dhdt) && contains(CtrlVar.Inverse.Measurements,"-dhdt") Kplot=Kplot+1; subplot(Iplot,Jplot,Kplot) PlotMeshScalarVariable(CtrlVar,MUA,Meas.dhdt) ; hold on ; - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,'interpreter','latex'); ylabel(CtrlVar.PlotsYaxisLabel,'interpreter','latex'); @@ -75,22 +88,22 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, PlotMeshScalarVariable(CtrlVar,MUA,usError) ; hold on ; -[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); title('us error on numerical grid') ; Kplot=Kplot+1; subplot(Iplot,Jplot,Kplot) PlotMeshScalarVariable(CtrlVar,MUA,vsError) ; hold on ; -[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); title('vs error on numerical grid') ; -if ~isempty(Meas.dhdt) +if ~isempty(Meas.dhdt) && contains(CtrlVar.Inverse.Measurements,"-dhdt") Kplot=Kplot+1; subplot(Iplot,Jplot,Kplot) PlotMeshScalarVariable(CtrlVar,MUA,dhdtError) ; hold on ; - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); title('dh/dt error on numerical grid') ; @@ -104,7 +117,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, fig=FindOrCreateFigure('A at the end of inversion') ; PlotMeshScalarVariable(CtrlVar,MUA,log10(InvFinalValues.AGlen)); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); CtrlVar.PlotNodes=0 ; % PlotMuaMesh(CtrlVar,MUA,[],'k') ; title("$\log_{10}(A)$ at end of inversion",Interpreter="latex") @@ -117,7 +130,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, title("$\log_{10}(A)$ at start of inversion",Interpreter="latex") cbar=colorbar; title(cbar, '($\mathrm{a}^{-1}$ $\mathrm{kPa}^{-3}$)',interpreter="latex"); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); colormap(othercolor("Mtemperaturemap",1028)) PlotMuaBoundary(CtrlVar,MUA,'k'); @@ -126,7 +139,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, PlotMeshScalarVariable(CtrlVar,MUA,log10(InvFinalValues.AGlen)-log10(InvStartValues.AGlen)); title('log10(InvFinalValues.AGlen)-log10(InvStartValues.AGlen)') ; cbar=colorbar; title(cbar, '($\mathrm{a}^{-1}$ $\mathrm{kPa}^{-3}$)',interpreter="latex"); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") ; ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") colormap(othercolor("Mtemperaturemap",1028)) PlotMuaBoundary(CtrlVar,MUA,'k'); @@ -140,7 +153,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, fig=FindOrCreateFigure('C at the end of inversion') ; PlotMeshScalarVariable(CtrlVar,MUA,log10(InvFinalValues.C)); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") ; ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") CtrlVar.PlotNodes=0 ; % PlotMuaMesh(CtrlVar,MUA,[],'k') ; @@ -154,7 +167,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, title("$\log_{10}(C)$ at start of inversion",Interpreter="latex") cbar=colorbar; title(cbar, '($\mathrm{m}\,\mathrm{yr}^{-1}\,\mathrm{kPa}^{-m}$)','interpreter','latex'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") ; ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") colormap(othercolor("Mtemperaturemap",1028)) PlotMuaBoundary(CtrlVar,MUA,'k'); @@ -164,7 +177,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, title('log10(InvFinalValues.C)-log10(Cstart)') ; cbar=colorbar; title(cbar, '($\mathrm{m}\,\mathrm{yr}^{-1}\,\mathrm{kPa}^{-m}$)','interpreter','latex'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") ; ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") colormap(othercolor("Mtemperaturemap",1028)) PlotMuaBoundary(CtrlVar,MUA,'k'); @@ -175,21 +188,21 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, figure ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.b); title('InvFinalValues.b') ; cbar=colorbar; title(cbar, '(m)'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") ; ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") figure ; PlotMeshScalarVariable(CtrlVar,MUA,InvStartValues.b); title('bstart') ; cbar=colorbar; title(cbar, '(m)'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") ; ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") figure ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.b-InvStartValues.b); title('InvFinalValues.b-bstart') ; cbar=colorbar; title(cbar, '(m)'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") ; ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") %[TRI,DT,LightHandle]=Plot_sbB(CtrlVar,MUA,s,b,B,TRI,DT,AspectRatio,ViewAndLight,LightHandle,sCol,bCol,BCol); @@ -204,19 +217,19 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, figure ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.B); title('InvFinalValues.B') ; cbar=colorbar; title(cbar, '(m)'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); figure ; PlotMeshScalarVariable(CtrlVar,MUA,InvStartValues.B); title('Bstart') ; cbar=colorbar; title(cbar, '(m)'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); figure ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.B-InvStartValues.B); title('InvFinalValues.B-Bstart') ; cbar=colorbar; title(cbar, '(m)'); hold on - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); AspectRatio=1; @@ -237,7 +250,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, title('Basal drag, $\Vert \mathbf{t}_b \Vert$ ','interpreter','latex') ; cbar=colorbar; title(cbar, '($\mathrm{kPa}$)','interpreter','latex'); hold on -[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); clim([0 500]) % Here I'm guessing that this is a reasonable range for plotting, most likely will be the case when using kPa as units for stress %% @@ -247,12 +260,12 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, fig=FindOrCreateFigure('Adjoint variables') ; subplot(1,2,1) PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.uAdjoint); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title(' u Adjoint variable') subplot(1,2,2) PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.vAdjoint); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title(' v Adjoint variable') end end @@ -273,7 +286,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, wsError=sqrt(spdiags(Meas.wsCov)); end if ~exist('GLgeo','var') - GLgeo=GLgeometry(MUA.connectivity,MUA.coordinates,GF,CtrlVar); xGL=[] ; yGL=[] ; + GLgeo=GLgeometry(MUA.connectivity,MUA.coordinates,F.GF,CtrlVar); xGL=[] ; yGL=[] ; end %% @@ -285,24 +298,24 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(2,2,1) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,log10(speedMeas)) ; title('log10(measured speed)') -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); cAxisMeas=caxis; subplot(2,2,2) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,log10(speedCalc)) ; title('log10(calculated speed)') -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); caxis(cAxisMeas); subplot(2,2,3) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,log10(ErrSpeed)) ; title('log10(Meas error in speed)') -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); subplot(2,2,4) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,(speedMeas-speedCalc)./ErrSpeed) ; title('speed residuals: (meas-calc)/error') -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); %% fig=FindOrCreateFigure('velocity misfit') ; @@ -313,7 +326,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, QuiverColorGHG(x,y,(us-Meas.us)./usError,(vs-Meas.vs)./vsError,CtrlVar); title('((us-Meas.us)/usError,(vs-Meas.vs)/vsError)') ; hold on -[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); axis([min(x) max(x) min(y) max(y)]/CtrlVar.PlotXYscale) @@ -321,11 +334,11 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, Kplot=Kplot+1; subplot(Iplot,Jplot,Kplot); QuiverColorGHG(x,y,us-Meas.us,vs-Meas.vs,CtrlVar); axis equal ; title('(us-Meas.us,v-Meas.vs)') ; -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); axis([min(x) max(x) min(y) max(y)]/CtrlVar.PlotXYscale) -if ~isempty(Meas.dhdt) +if ~isempty(Meas.dhdt) && contains(CtrlVar.Inverse.Measurements,"-dhdt") [UserVar,dhdt]=dhdtExplicit(UserVar,CtrlVar,MUA,F,BCs); @@ -333,7 +346,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(Iplot,Jplot,Kplot); PlotMeshScalarVariable(CtrlVar,MUA,(dhdt-Meas.dhdt)./dhdtError); hold on ; - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); axis([min(x) max(x) min(y) max(y)]/CtrlVar.PlotXYscale) @@ -347,7 +360,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, [~,~,QuiverPar]=QuiverColorGHG(x,y,Meas.us,Meas.vs,CtrlVar); axis equal ; title('(Meas.us,Meas.vs)') ; hold on ; -[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +[xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); axis([min(x) max(x) min(y) max(y)]/CtrlVar.PlotXYscale) @@ -356,21 +369,21 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(Iplot,Jplot,Kplot); QuiverPar.QuiverSameVelocityScalingsAsBefore=1; QuiverColorGHG(x,y,us,vs,QuiverPar); axis equal ; title('(us,vs)') ; -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); axis([min(x) max(x) min(y) max(y)]/CtrlVar.PlotXYscale) QuiverPar.QuiverSameVelocityScalingsAsBefore=0; -if ~isempty(Meas.dhdt) +if ~isempty(Meas.dhdt) && contains(CtrlVar.Inverse.Measurements,"-dhdt") Kplot=Kplot+1; subplot(Iplot,Jplot,Kplot); PlotMeshScalarVariable(CtrlVar,MUA,dhdt); title('(dh/dt modelled)') ; hold on ; - [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); PlotMuaBoundary(CtrlVar,MUA,'b') ; xlabel(CtrlVar.PlotsXaxisLabel); ylabel(CtrlVar.PlotsYaxisLabel); axis([min(x) max(x) min(y) max(y)]/CtrlVar.PlotXYscale) @@ -383,7 +396,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, PlotBoundary(MUA.Boundary,MUA.connectivity,MUA.coordinates,CtrlVar,'k') hold on QuiverColorGHG(x,y,us,vs,QuiverPar); axis equal ; title('Calculated horizontal velocities') ; -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); [UserVar,dhdt]=dhdtExplicit(UserVar,CtrlVar,MUA,F,BCs); @@ -392,7 +405,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, hold on PlotMeshScalarVariable(CtrlVar,MUA,dhdt); title('Calculated $dh/dt$ (assuming plug flow)','interpreter','latex') ; -hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); +hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); %% Prior @@ -489,26 +502,26 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(2,2,1) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdC) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('dJdC Adjoint gradient') subplot(2,2,2) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdCTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('$dJ/dC$ Brute force gradient','interpreter','latex') subplot(2,2,3) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdC-InvFinalValues.dJdCTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Difference between adjoint and brute force derivatives') subplot(2,2,4) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdC./InvFinalValues.dJdCTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Ratio between adjoint and brute force derivatives') IFigC.Position=[948.43 41.571 1246.3 1115.4]; @@ -525,26 +538,26 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(2,2,1) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdAGlen) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('dJdAGlen Adjoint gradient') subplot(2,2,2) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdAGlenTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('dJdAGlen Brute force gradient') subplot(2,2,3) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdAGlen-InvFinalValues.dJdAGlenTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Difference between adjoint and brute force derivatives') subplot(2,2,4) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdAGlen./InvFinalValues.dJdAGlenTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Ratio between adjoint and brute force derivatives') IFigAGlen.Position=[1.5714 41.571 1096 1115.4]; @@ -561,26 +574,26 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(2,2,1) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdB) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('dJdB Adjoint gradient') subplot(2,2,2) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdBTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('dJdB Brute force gradient') subplot(2,2,3) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdB-InvFinalValues.dJdBTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Difference between adjoint and brute force derivatives') subplot(2,2,4) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdB./InvFinalValues.dJdBTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Ratio between adjoint and brute force derivatives') IFigAGlen.Position=[1.5714 41.571 1096 1115.4]; @@ -599,26 +612,26 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(2,2,1) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdB) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('dJdB Adjoint gradient') subplot(2,2,2) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdBTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('dJdB Brute force gradient') subplot(2,2,3) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdB-InvFinalValues.dJdBTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Difference between adjoint and brute force derivatives') subplot(2,2,4) ; PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdB./InvFinalValues.dJdBTest) ; hold on PlotMuaMesh(CtrlVar,MUA); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); title('Ratio between adjoint and brute force derivatives') IFigAGlen.Position=[1.5714 41.571 1096 1115.4]; @@ -634,7 +647,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, fig=FindOrCreateFigure('dJdA'); PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdAGlen) ; title('$dJ/dA$','interpreter','latex') - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); end if ~isempty(InvFinalValues.dJdC) @@ -642,7 +655,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, fig=FindOrCreateFigure('dJdC'); PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdC) ; title('$dJ/dC$','interpreter','latex'); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); end if ~isempty(InvFinalValues.dJdB) @@ -650,7 +663,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, fig=FindOrCreateFigure('dJdB'); PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.dJdB) ; title('$dJ/dC$','interpreter','latex'); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); end @@ -759,28 +772,28 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(2,2,1) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.B); - %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); SetLabels(CtrlVar,"km","km","m"); title("Inv. start field: "+CtrlVar.Inverse.InvertFor) colorbar('southoutside') subplot(2,2,2) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.B); - %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); SetLabels(CtrlVar,"km","km","m"); title("Inverted: "+CtrlVar.Inverse.InvertFor) colorbar('southoutside') subplot(2,2,3) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,Priors.TrueB); - %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); SetLabels(CtrlVar,"km","km","m"); title("True: "+CtrlVar.Inverse.InvertFor) colorbar('southoutside') subplot(2,2,4) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,InvFinalValues.B-Priors.TrueB); - %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + %hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); SetLabels(CtrlVar,"km","km","m"); title("Estimated-True: "+CtrlVar.Inverse.InvertFor) colorbar('southoutside') @@ -792,7 +805,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(1,3,1) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,F.s-InvFinalValues.B); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); SetLabels(CtrlVar,"km","km","m"); title("Inverted: h") colorbar('off') @@ -800,7 +813,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(1,3,2) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,F.s-Priors.TrueB) ; % this may need to be adjusted - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); SetLabels(CtrlVar,"km","km","m"); title("True: h") colorbar('off') @@ -808,7 +821,7 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, subplot(1,3,3) [~,cbar]=PlotMeshScalarVariable(CtrlVar,MUA,(F.s-InvFinalValues.B)-(F.s-Priors.TrueB)); - hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,GF,GLgeo,xGL,yGL,'r'); + hold on ; [xGL,yGL,GLgeo]=PlotGroundingLines(CtrlVar,MUA,F.GF,GLgeo,xGL,yGL,'r'); SetLabels(CtrlVar,"km","km","m"); title("Inverted-True: h ") colorbar('off') @@ -859,16 +872,17 @@ function PlotResultsFromInversion(UserVar,CtrlVar,MUA,BCs,F,l,GF,InvStartValues, hold off yyaxis left semilogy(RunInfo.Inverse.Iterations,RunInfo.Inverse.J,'-bo','LineWidth',2) - ylabel('J','interpreter','latex') + ylabel('$J$','interpreter','latex') hold on semilogy(RunInfo.Inverse.Iterations,RunInfo.Inverse.I,'-gx') - ylabel('J and I') + ylabel('$J$ and $I$',Interpreter='latex') yyaxis right semilogy(RunInfo.Inverse.Iterations,RunInfo.Inverse.R,'-r+') - ylabel('R','interpreter','latex') - legend('Objective function','I','R','Location','southwest','interpreter','latex') + ylabel('$R$','interpreter','latex') + xlabel('Inverse iteration','interpreter','latex'); + legend('Objective function','$I$','$R$','Location','southwest','interpreter','latex') end diff --git a/UaUtilities/PlotRunInfo.m b/UaUtilities/PlotRunInfo.m index 453d4f43..1643bf99 100644 --- a/UaUtilities/PlotRunInfo.m +++ b/UaUtilities/PlotRunInfo.m @@ -26,7 +26,7 @@ function PlotRunInfo(RunInfo,FigName) fig=FindOrCreateFigure("RunInfo: time steps and iterations"+FigName) ; clf(fig) ; yyaxis left semilogy(RunInfo.Forward.time,RunInfo.Forward.dt,'o-',DisplayName="time step") ; -ylabel('time step, $\mathrm{d}t$',Interpreter='latex') +ylabel('time step, $\Delta t$',Interpreter='latex') yyaxis right @@ -61,8 +61,8 @@ function PlotRunInfo(RunInfo,FigName) items=numel(find(~isnan( RunInfo.Forward.dt))); nbins=max(10,fix(items/20)); histogram(RunInfo.Forward.dt,nbins,Normalization="probability") ; -xlabel('time step, $\mathrm{d}t$',Interpreter='latex') -title('dt Histogram') +xlabel('time step, $\Delta t$',Interpreter='latex') +title("$\Delta t$ Histogram",Interpreter="latex") @@ -70,7 +70,7 @@ function PlotRunInfo(RunInfo,FigName) yyaxis left semilogy(RunInfo.Forward.dt,'-',DisplayName="time step",LineWidth=2) ; -ylabel('time step, $\mathrm{d}t$',Interpreter='latex') +ylabel('time step, $\Delta t$',Interpreter='latex') yyaxis right plot(RunInfo.Forward.time,'-',DisplayName="time",LineWidth=2) ; diff --git a/UaUtilities/ReadPlotSequenceOfResultFiles2.m b/UaUtilities/ReadPlotSequenceOfResultFiles2.m index a3b180bc..14790532 100755 --- a/UaUtilities/ReadPlotSequenceOfResultFiles2.m +++ b/UaUtilities/ReadPlotSequenceOfResultFiles2.m @@ -959,7 +959,7 @@ if contains(options.PlotType,"-ds-") %ModifyColormap(GrayLevelRange=100) ; - CM=cmocean('balanced',25,'pivor',0) ; colormap(CM); ModifyColormap(100,5,ChangeColormap=false) ; + CM=cmocean('balanced',25,'pivot',0) ; colormap(CM); ModifyColormap(100,5,ChangeColormap=false) ; else colormap(ax1,flipud(othercolor("YlGnBu8",1028))) ; end diff --git a/UaUtilities/UaPlots.m b/UaUtilities/UaPlots.m index 8c4e5f2e..d0178c52 100755 --- a/UaUtilities/UaPlots.m +++ b/UaUtilities/UaPlots.m @@ -1,4 +1,4 @@ -function [cbar,xGL,yGL,xCF,yCF]=UaPlots(CtrlVar,MUA,F,Variable,options) +function [cbar,xGL,yGL,xCF,yCF,CtrlVar]=UaPlots(CtrlVar,MUA,F,Variable,options) %% % @@ -10,6 +10,12 @@ % physical dimensions such as m/yr for velocities, and kPa for stresses. % % +% Note: To produce two velocity plots with the same scaling, use the CtrlVar from previous call again, but in the second +% call set +% +% CtrlVar.QuiverSameVelocityScalingsAsBefore=true; +% +% % Returns grounding lines (xGL,yGL) and calving fronts (xCF,yCF). % % Calving fronts @@ -38,7 +44,7 @@ CtrlVar struct MUA struct F {mustBeA(F,{'struct','UaFields','numeric'})} - Variable {mustBeA(Variable,{'string','numeric'})} + Variable {mustBeA(Variable,{'string','numeric','logical'})} options.PlotGroundingLines logical = true options.PlotCalvingFronts logical = true options.CalvingFrontColor char = "b" @@ -50,7 +56,7 @@ options.PlotMuaBoundary=true; options.FigureTitle string="UaPlots"; % this is the figure title, not the plot title options.CreateNewFigure logical = true ; - options.MeshColor char="w" + options.MeshColor char="k" % options.ColorMap double=othercolor('YlGnBu6',1028) @@ -77,8 +83,6 @@ if islogical(Variable) - - Variable=double(Variable) ; end @@ -154,7 +158,7 @@ if options.PlotOverMesh CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; - PlotMuaMesh(CtrlVar,MUA,[],options.MeshColor) ; + PlotMuaMesh(CtrlVar,MUA,nan,options.MeshColor) ; hold on end @@ -189,7 +193,7 @@ case {"ubvb","-ubvb-","uv","-uv-"} CtrlVar.VelColorMap=jet(100) ; - cbar=QuiverColorGHG(F.x,F.y,F.ub,F.vb,CtrlVar) ; + [cbar,QuiverHandel,CtrlVar]=QuiverColorGHG(F.x,F.y,F.ub,F.vb,CtrlVar) ; title(cbar,"(m/a)",Interpreter="latex") title(sprintf("velocities at t=%g",CtrlVar.time),Interpreter="latex") @@ -210,7 +214,7 @@ % [txzb,tyzb,txx,tyy,txy,exx,eyy,exy,e,eta]=CalcNodalStrainRatesAndStresses(CtrlVar,[],MUA,F) ; CtrlVar.VelColorMap=jet(100) ; - cbar=QuiverColorGHG(F.x,F.y,tbx,tby,CtrlVar) ; + [cbar,~,CtrlVar]=QuiverColorGHG(F.x,F.y,tbx,tby,CtrlVar) ; title(cbar,"(kPa)",Interpreter="latex") title(sprintf("basal drag vectors at t=%g",CtrlVar.time),Interpreter="latex") @@ -251,6 +255,7 @@ end scale=1000 ; + scale=0.1 ; LineWidth=1; nStride=10; xint=xint(1:nStride:end,1); @@ -317,17 +322,11 @@ if options.PlotUnderMesh CtrlVar.WhenPlottingMesh_PlotMeshBoundaryCoordinatesToo=0; - PlotMuaMesh(CtrlVar,MUA,[],options.MeshColor) ; + PlotMuaMesh(CtrlVar,MUA,nan,options.MeshColor) ; hold on end -if isempty(F.GF) - - - - -end @@ -346,10 +345,10 @@ % Just guessing that this might be the most common case, the user can easily change afterwards anyhow. - -xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") -ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") - +if isfield(CtrlVar,"PlotsXaxisLabel") + xlabel(CtrlVar.PlotsXaxisLabel,Interpreter="latex") + ylabel(CtrlVar.PlotsYaxisLabel,Interpreter="latex") +end diff --git a/UpdateMUA.m b/UpdateMUA.m index f6eea4af..a6b7bcac 100755 --- a/UpdateMUA.m +++ b/UpdateMUA.m @@ -162,15 +162,23 @@ [MUA.Dxx,MUA.Dyy]=StiffnessMatrix2D1dof(MUA); end - - % if CtrlVar.Inverse.AdjointGradientPreMultiplier=="M" - % MUA.L=chol(MUA.M,'upper'); - % end - - + + % if CtrlVar.Inverse.AdjointGradientPreMultiplier=="M" + % MUA.L=chol(MUA.M,'upper'); + % end + + [MUA.xEle,MUA.yEle]=ElementCoordinates(MUA.connectivity,MUA.coordinates); - - + + MUA.workers=[]; + + if CtrlVar.Parallel.uvAssembly.spmd.isOn || CtrlVar.Parallel.uvhAssembly.spmd.isOn + + MUA.workers=BuildMuaWorkers(CtrlVar,MUA,MUA.workers) ; + + end + + end @@ -206,7 +214,7 @@ end -if CtrlVar.MUA.DecomposeMassMatrix && ( ~isfield(MUA,'dM') || isempty(MUA.dM) || MUADerivHasChanged) +if CtrlVar.MUA.DecomposeMassMatrix && ( ~isfield(MUA,'dM') ||isempty(MUA.dM) || ~all(MUA.dM.MatrixSize==size(MUA.M)) || MUADerivHasChanged) MUA.dM=decomposition(MUA.M,'chol','upper') ; end @@ -237,6 +245,18 @@ MUA.Area=sum(MUA.EleAreas); % total FE mesh area +if ~isfield(MUA,"workers") + MUA.workers=[]; +end + +if ( CtrlVar.Parallel.uvAssembly.spmd.isOn || CtrlVar.Parallel.uvhAssembly.spmd.isOn ) + + poolobj = gcp; + CtrlVar.Parallel.uvhAssembly.spmd.nWorkers=poolobj.NumWorkers; + + MUA.workers=BuildMuaWorkers(CtrlVar,MUA,MUA.workers) ; + +end diff --git a/WriteAdjointRestartFile.m b/WriteAdjointRestartFile.m index 2b52a99a..657ece2b 100755 --- a/WriteAdjointRestartFile.m +++ b/WriteAdjointRestartFile.m @@ -7,6 +7,9 @@ function WriteAdjointRestartFile(UserVar,CtrlVar,MUA,BCs,F,GF,l,RunInfo,InvStart UserVarInRestartFile=UserVar; time=CtrlVar.time; dt=CtrlVar.dt; + +MUA.workers=[]; % saving composites is not supported, MATLAB 2024 + save(CtrlVar.Inverse.NameOfRestartOutputFile,... 'CtrlVarInRestartFile','UserVarInRestartFile','MUA','BCs','F','GF','l','RunInfo',... 'InvStartValues','Priors','Meas','BCsAdjoint','InvFinalValues','time','dt','-v7.3'); @@ -42,7 +45,7 @@ function WriteAdjointRestartFile(UserVar,CtrlVar,MUA,BCs,F,GF,l,RunInfo,InvStart end if CtrlVar.Inverse.SaveAGlenEstimateInSeperateFile - fprintf(CtrlVar.fidlog,' saving AGlen and m in file %s \n ',CtrlVar.NameOfFileForSavingAGlenEstimate) ; + fprintf(CtrlVar.fidlog,' saving AGlen and n in file %s \n ',CtrlVar.NameOfFileForSavingAGlenEstimate) ; AGlen=F.AGlen; n=F.n; save(CtrlVar.NameOfFileForSavingAGlenEstimate,'AGlen','n','xA','yA','MUA','CtrlVarInRestartFile') diff --git a/WriteForwardRunRestartFile.m b/WriteForwardRunRestartFile.m index 64f5d8c9..525002ad 100755 --- a/WriteForwardRunRestartFile.m +++ b/WriteForwardRunRestartFile.m @@ -6,6 +6,8 @@ function WriteForwardRunRestartFile(UserVar,CtrlVar,MUA,BCs,F,GF,l,RunInfo) +MUA.workers=[]; % saving composites is not supported, MATLAB 2024 + CtrlVarInRestartFile=CtrlVar; UserVarInRestartFile=UserVar; diff --git a/dIdCq.m b/dIdCq.m index 49a33bc5..ed00afab 100755 --- a/dIdCq.m +++ b/dIdCq.m @@ -48,6 +48,12 @@ muknod=mnod*0 ; end +if ~isempty(F.V0) + V0nod=reshape(F.V0(MUA.connectivity,1),MUA.Nele,MUA.nod); +else + V0nod=mnod*0 ; +end + Bnod=reshape(F.B(MUA.connectivity,1),MUA.Nele,MUA.nod); Snod=reshape(F.S(MUA.connectivity,1),MUA.Nele,MUA.nod); @@ -74,6 +80,7 @@ mint=mnod*fun; qint=qnod*fun; mukint=muknod*fun; + V0int=V0nod*fun; Bint=Bnod*fun; Sint=Snod*fun; Hint=Sint-Bint; @@ -94,7 +101,7 @@ % setting this CtrlVar field to true ensures that BasalDrag.m returns the (point) derivative CtrlVar.Inverse.dFuvdClambda=true; Ctemp= ... - BasalDrag(CtrlVar,MUA,Heint,[],hint,Bint,Hint,rhoint,F.rhow,uint,vint,Cint,mint,[],[],[],[],[],[],[],[],qint,F.g,mukint); + BasalDrag(CtrlVar,MUA,Heint,[],hint,Bint,Hint,rhoint,F.rhow,uint,vint,Cint,mint,[],[],[],[],[],[],[],[],qint,F.g,mukint,V0int); CtrlVar.Inverse.dFuvdClambda=false; if ~CtrlVar.DevelopmentVersion diff --git a/decomposition.m b/decompositionUa.m similarity index 99% rename from decomposition.m rename to decompositionUa.m index 55a67336..b52a18f9 100755 --- a/decomposition.m +++ b/decompositionUa.m @@ -1,4 +1,9 @@ -classdef (Sealed) decomposition < matlab.mixin.CustomDisplay & matlab.mixin.internal.Scalar + + + + + +classdef (Sealed) decompositionUa < matlab.mixin.CustomDisplay & matlab.mixin.internal.Scalar %DECOMPOSITION Matrix decomposition % DA = DECOMPOSITION(A) returns a decomposition of matrix A, which % can be used to solve the linear system A*X = B efficiently. The @@ -141,7 +146,7 @@ end methods - function f = decomposition(A, varargin) + function f = decompositionUa(A, varargin) if nargin == 0 A = []; diff --git a/fRK.m b/fRK.m index 25c6d9a1..4d9b069f 100755 --- a/fRK.m +++ b/fRK.m @@ -1,7 +1,8 @@ -function [R,K]=fRK(x,problemtype) +function [R,K,outs]=fRK(x,problemtype) x=x(:) ; +outs=[]; % various other outputs variables can be % nargout switch problemtype diff --git a/html/DeactivateMUAelements.html b/html/DeactivateMUAelements.html index b16f2155..1c0770bf 100755 --- a/html/DeactivateMUAelements.html +++ b/html/DeactivateMUAelements.html @@ -1,168 +1,213 @@ - - - - - DeactivateMUAelements
function  [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated)
-
-%
-% Deactivates elements in the list iDeactivatedElements
-%
-% Nodes that are no longer part of the FE mesh are deleted and the connectivity updated accordingly
-%
-%
-% If CtrlVar.sweep is true, elements and nodes are then renumbered.
-%
-%  k gives me the mapping between new and old node numbers, that is:
-%
-%       j=k(i)
-%
-% gives the old node number j for the new node number i
-%
-% If needed, one can transfer/map the old nodal values, fOld, onto the new subset of nodes using:
-%
-%     fNew=fOld(k) ;
-%
-% and
-%
-%   fNew(i)=fOld(k(i)) ;
-%
-% where fNew are the nodal values over the new mesh MUA (ie MUA returned).
-%
-%  l gives the mapping between old and new nodes numbers, that is:
-%
-%        j=l(i)
-%
-% gives the new node number j for the old node number i.
-%
-%   l(i) is nan where there is no node in the new mesh corresponding to the old node i, ie for all deleted nodes.
-%
-% To get a list of deleted old node numbers use:
-%
-%   find(isnan(l))
-%
-% And to get a logical list of the nodes on the old mesh that were kept in the new:
-%
-%   ~isnan(l)             ;   % logical list of nodes in the old mesh used/kept in the new mesh.
-%
-
-if ~any(ElementsToBeDeactivated)
-    k=[];
-    return
-end
-
-nNodesIn=MUA.Nnodes;
-
-MUA.connectivity(ElementsToBeDeactivated,:)=[];
-
-% eliminate MUA.coordinates that are no longer part of mesh, and update MUA.connectivity accordingly
-[k,~,ic]=unique(MUA.connectivity(:));
-MUA.connectivity=reshape(ic,size(MUA.connectivity));
-MUA.coordinates=MUA.coordinates(k,:);
-
-% What nodes were eliminated
-
-
-
-
-
-% K is the subset of nodes that I keep.
-%
-% Assuming there are no further changes to the nodal numbering, if I wanted to interpolate, I could do xNew=xOld(k) ;
-
-% renumber nodes and elements
-if CtrlVar.sweep
-    [MUA.coordinates,MUA.connectivity,p] = NodalSweep(MUA.coordinates,MUA.connectivity,CtrlVar.SweepAngle);
-    [MUA.coordinates,MUA.connectivity] = ElementSweep(MUA.coordinates,MUA.connectivity,CtrlVar.SweepAngle);
-    k=k(p) ;
-end
-
-if CtrlVar.UpdateMUAafterDeactivating
-    MUA=UpdateMUA(CtrlVar,MUA);
-end
-
-if nargout==3   % create a mapping from old to new node numbers
-    l=1:nNodesIn ; l=l(:)+nan;
-    l(k(1:numel(k)))=1:numel(k);
-end
-
-
-% MUA.RefineMesh=[] ; %  As I now have a new mesh I need to reset the newest vertex bisection data structure.
-%                    %  Therefore no further unrefinement over the previous mesh can be done.
-
-
-
-end
-
+DeactivateMUAelements + + + + + + + +
+
+function  [MUA,k,l]=DeactivateMUAelements(CtrlVar,MUA,ElementsToBeDeactivated,kIn,lIn)
+
+

Deactivates elements in the list

+
ElementsToBeDeactivated
+
+

The variable ElementsToBeDeactivated can be either a logical or an index array.

+

kIn and lIn are optional inputs.

+

Nodes that are no longer part of the FE mesh are deleted and the connectivity updated accordingly

+

If CtrlVar.sweep is true, elements and nodes are then renumbered.

+
k gives me the mapping between new and old node numbers, that is:
+
     j=k(i)
+

gives the old node number j for the new node number i

+

If needed, one can transfer/map the old nodal values, fOld, onto the new subset of nodes using:

+
   fNew=fOld(k) ;
+

and

+
fNew(i)=fOld(k(i)) ;
+
+

where fNew are the nodal values over the new mesh MUA (ie MUA returned).

+
l gives the mapping between old and new nodes numbers, that is:
+
      i=l(j)
+

gives the new node number i for the old node number j.

+
l(j)=nan
+
+

if no node in the new mesh corresponds to the old node j, ie for all deleted nodes.

+

To get a list of deleted old node numbers use:

+
find(isnan(l))
+
+

And to get a logical list of the nodes on the old mesh that were kept in the new:

+
~isnan(l)             ;   % logical list of nodes in the old mesh used/kept in the new mesh.
+
+

If elements are deactivated repeatedly and one needs to know the mapping between the original and the final mesh do:

+
k=k1(k2(k3))     % where k1 results from the first, k2 from the second, etc, deactivations
+
+

and then:

+
   l=1:nNodesIn ; l=l(:)+nan;
+   l(k(1:numel(k)))=1:numel(k);
+

where nNodesIn is the number of nodes in the initial mesh, i.e. before the first round of deactivations. Alternativily, provide k and l from the previous deactivation as an input. These are the optional input variables kIn and lIn. The k and l will then be updated as k=kIn(k), providing the mapping with respect to the original mesh.

+
narginchk(3,5)
+
+
+% This works equally for both logical and index arrays.
+if ~any(ElementsToBeDeactivated)
+    k=1:MUA.Nnodes;
+    l=1:MUA.Nnodes;
+    return
+end
+
+nNodesIn=MUA.Nnodes;
+
+
+
+
+MUA.connectivity(ElementsToBeDeactivated,:)=[];
+
+% eliminate MUA.coordinates that are no longer part of mesh, and update MUA.connectivity accordingly
+[k,~,ic]=unique(MUA.connectivity(:));
+MUA.connectivity=reshape(ic,size(MUA.connectivity));
+MUA.coordinates=MUA.coordinates(k,:);
+
+
+% K is the subset of nodes that I keep.
+%
+% Assuming there are no further changes to the nodal numbering, if I wanted to interpolate, I could do xNew=xOld(k) ;
+
+% renumber nodes and elements
+if CtrlVar.sweep
+    [MUA.coordinates,MUA.connectivity,p] = NodalSweep(MUA.coordinates,MUA.connectivity,CtrlVar.SweepAngle);
+    [MUA.coordinates,MUA.connectivity] = ElementSweep(MUA.coordinates,MUA.connectivity,CtrlVar.SweepAngle);
+    k=k(p) ;   % keep track of how k changes
+end
+
+if CtrlVar.UpdateMUAafterDeactivating
+    MUA=UpdateMUA(CtrlVar,MUA);
+else
+    MUA.M=[];
+    MUA.Deriv=[];
+    MUA.DetJ=[];
+    MUA.TR=[];
+    MUA.Boundary=[];
+    MUA.dM=[];
+    MUA.xEle=[];
+    MUA.yEla=[];
+    MUA.Nnodes=size(MUA.coordinates,1);
+    MUA.Nele=size(MUA.connectivity,1);
+    MUA.EleAreas=TriAreaFE(MUA.coordinates,MUA.connectivity); % areas for each element
+    MUA.Area=sum(MUA.EleAreas);
+
+end
+
+if nargin>4  && ~isempty(kIn)
+    k=kIn(k);
+end
+
+
+
+if nargout==3   % create a mapping from old to new node numbers
+    if nargin==5  && ~isempty(lIn)
+        l=lIn+nan;
+    else
+        %l=1:nNodesIn ; l=l(:)+nan;
+        l=nan(nNodesIn,1) ;
+    end
+    l(k(1:numel(k)))=1:numel(k);
+end
+
+
+% MUA.RefineMesh=[] ; %  As I now have a new mesh I need to reset the newest vertex bisection data structure.
+%                    %  Therefore no further unrefinement over the previous mesh can be done.
+
+
+end
+
+ +
+ \ No newline at end of file +--> + + diff --git a/html/DefineAGlenDistribution.html b/html/DefineAGlenDistribution.html index e597bd7e..7887af11 100755 --- a/html/DefineAGlenDistribution.html +++ b/html/DefineAGlenDistribution.html @@ -7,9 +7,9 @@ To make changes, update the MATLAB code and republish this document. --> DefineAGlenDistribution - + - +
function [ab,dabdh]=DraftDependentMeltParameterisations(UserVar,CtrlVar,F,MRP)
 
[ab,dabdh]=DraftDependentMeltParameterisations(UserVar,CtrlVar,F,MRP)
 

Returns basal melt rates, based on several depth-dependent parameterisations.

ab is :    abMin for F.b>dMin
-           abMax for F.b<dMax
and varies linearly inbetween.

These types of parameterisations have been used in various papers. Labels might not correspond exactly to the labels used in previous publicatioins.

switch MRP
+           abMax for F.b<dMax
and varies linearly inbetween.

These types of parameterisations have been used in various papers. Labels might not correspond exactly to the labels used in previous publicatioins.

Note !!! The user will in addition need to make sure that melt is only applied over floating nodes, downstream of the grounding line This can be done in DefineMassBalance.m as follows:

[LakeNodes,OceanNodes] = LakeOrOcean3(CtrlVar,MUA,F.GF,[],"Strict") ;
+ab(~OceanNodes)=0;
+dabdh(~OceanNodes)=0;
+
switch MRP
 
 
-    case "0"
+    case {"0","l0"}
 
         fprintf(' MeltRate0 \n ');
         dMin=-400 ;  abMin=0 ;
         dMax=-800 ;  abMax=-100  ;
 
-    case "1"
+    case {"1","l1"}
 
         fprintf(' MeltRate1 \n ');
         dMin=-400 ;  abMin=0 ;
         dMax=-800 ;  abMax=-200  ;
 
 
-    case "2"
+    case {"2","l2"}
 
         fprintf(' MeltRate2 \n ');
         dMin=-200 ;  abMin=0 ;
         dMax=-800 ;  abMax=-100  ;
 
 
-    case "3"
+    case {"3","l3"}
 
         fprintf(' MeltRate3 \n ');
         dMin=-200 ;  abMin=0 ;
         dMax=-800 ;  abMax=-200  ;
 
-    case "4"
+    case {"4","l4"}
 
-        fprintf(' MeltRate4 \n ');
+        % fprintf(' MeltRate4 \n ');
         dMin=-400 ;  abMin=0 ;
         dMax=-500 ;  abMax=-50  ;
 
-    case "5"
+    case {"5","l5"}
 
         fprintf(' MeltRate5 \n ');
         dMin=-400 ;  abMin=0 ;
         dMax=-600 ;  abMax=-100  ;
 
+
+
+
+
     otherwise
 
         fprintf("DraftDependentMeltParameterisations : case not found")
@@ -121,18 +128,57 @@
 end
 
 
-dabdh=F.ab;
-ab=F.dabdh;
 
+F.as=zeros(size(F.h)) ;
+F.ab=zeros(size(F.h)) ;
+F.dasdh=zeros(size(F.h)) ;
+F.dabdh=zeros(size(F.h)) ;
+
+
+
+
+
+if contains(MRP,"l")
+
+    b0=(dMin+dMax)/2 ;
+    k=2/(dMin-dMax) ;
+    ab=abMin+    (1-HeavisideApprox(k,F.b,b0))*(abMax-abMin) ;
+
+    dabdh=-DiracDelta(k,F.b,b0).*(abMax-abMin).*(-F.rho/F.rhow) ;
+    %   dab/db  db/dh
 
-I=F.b>dMin ; ab(I)=abMin; dabdh(I)=abMin;        % above dMin
+else
 
-I= F.b< dMin & F.b >= dMax ; ab(I)=abMax*(F.b(I)-dMin)/(dMax-dMin);
-dabdh(I)=(-F.rho(I)/F.rhow)/(abMax/(dMax-dMin));
+    dabdh=zeros(size(F.x)) ;
+    ab=zeros(size(F.x)) ;
 
-I=F.b<dMax ; ab(I)=abMax; dabdh(I)=abMax;        % below dMax
+
+    % Note, the dab/dh calculation is not exact, as it is missing a Dirac delta
+    % term
+
+    I=F.b>dMin ; ab(I)=abMin; dabdh(I)=0;        % above dMin
+
+    I= F.b<= dMin & F.b >= dMax ;
+
+    % b= -h rho/rhow
+    ab(I)=abMax*(F.b(I)-dMin)/(dMax-dMin); % negative values, because it is a basal ablation
+    dabdh(I)=(-F.rho(I)/F.rhow)  .* (abMax/(dMax-dMin));
+
+    I=F.b<dMax ; ab(I)=abMax; dabdh(I)=0;        % below dMax
+
+
+end
+
+% Note !!!
+% The user will in addition need to make sure that melt is only applied over floating nodes, downstream of the grounding line
+% This can be done in DefineMassBalance.m as follows:
+%
+%   [LakeNodes,OceanNodes] = LakeOrOcean3(CtrlVar,MUA,F.GF,[],"Strict") ;
+%   ab(~OceanNodes)=0;
+%   dabdh(~OceanNodes)=0;
+%
 
end
-
IceSheetIceShelves
function [r,nu,kappa,sigma2Helmholtz,Cov,Realisation]=Matern(alpha,rho,d,x,sigma2,DoPlots)
-
[r,nu,kappa,sigma2,Cov,Realisation]=Matern(alpha,rho,d,x,sigma2,DoPlots)

Calculates the Matern covariance defined as

$$ r(x)=\frac{\sigma^2}{2^{\nu-1} \Gamma(\nu)} (\kappa \, x )^{\nu} K_{\nu}(\kappa x)$$

Inputs:

  alpha   :   alpha/2 is the exponent in the fractional Helmholtz eqaution
-  rho     :   distance where correlation falls to 0.1
-  d       :   spatial dimention
  sigma2  :   marginal variance, (optional input)
- DoPlots  :   plots of realisations if set to true (optional input)

Outputs:

     nu              :   nu=alpha-d/2;
-  kappa              :   the wave-number inthe Helmholtz equation
-  sigma2Helmholtz    :   marginal variance of the Helmholtz equation for the given
-                         kappa and alpha values
-  Cov                :   covariance matrix with the marginal covariance
-                         sigma2, if sigma2 is provided, otherwise with the
-                         marginal covariance sigma2Helmholtz
-  Realisation        :   One realisation of a Matern process.

$$\nu=\alpha-d/2$$

for d=2 (i.e. two spatial dimentions) we have nu=2-1=1

rho=sqrt(8 nu)/kappa then given rho

$$\kappa=\frac{\sqrt{8 \nu}}{\rho}$$

If sigma2 is not given on input, it is calculated based on expression in: Lindgren, F., Rue, H., & Lindström, J. (2011).

Note that if $\sigma^2$ is specified, the marginal variance of the Helmoltz equation with the specified alpha, rho and dimention will still be sigma2 as given

$$ \sigma^2=\frac{\Gamma(\nu) }{\Gamma(\nu+d/2) (4 \pi)^{d/2} \kappa^{2 \nu} } $$

by the equation above!

Only input sigma2 if you interested in returning and using the covariance matrix Cov and the Realisation.

Example :

d=2; alpha=2 ; rho=4e3 ;
-dist=linspace(0,1e4,1e3) ; [r,nu,kappa,sigma2]=Matern(alpha,rho,d,dist);
-figure ; plot(dist,r) ; xlabel('distance') ; ylabel('Matern')
-title(['$$ \sigma^2= $$',num2str(sigma2),' $$ \rho=$$',num2str(rho)],'interpreter','latex')
-
if nargin<6
-    DoPlots=false;
-end
-
-Cov=[] ; Realisation=[] ;
-
-% this gives a correlation of about 0.1 at the distance r
-nu=alpha-d/2;  % ie nu=1 for alpha=2 and dimention=2
-
-kappa=sqrt(8*nu)/rho;
-
-sigma2Helmholtz=gamma(nu) /  ( gamma(nu+d/2)*(4*pi)^(d/2)*kappa^(2*nu));
-
-if nargin<5
-    % Eq 1
-    sigma2=sigma2Helmholtz ;
-end
-
-x=kappa * x ;
-
-% this sigma2 should be referred to as sigma^2
-% some other sources appear to use a different defintion of rho
-% for example rho in https://en.wikipedia.org/wiki/Mat%C3%A9rn_covariance_function
-% appear to be 1/2 of the rho I use here
-% My notation is based on:
-%   Lindgren, F., Rue, H., & Lindström, J. (2011).
-%   An explicit link between Gaussian fields and Gaussian Markov random fields: the stochastic partial differential equation approach. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 73(4), 423–498. https://doi.org/10.1111/j.1467-9868.2011.00777.x
-r = real(sigma2 * x.^nu .* besselk(nu,x)  / (2^(nu-1)*gamma(nu)) );
-
if nargout>4 || DoPlots
-    F = griddedInterpolant(x,r) ;
-    D=ndgrid(x,x) ;
-    D=abs(D-D') ;
-
-    Cov=F(D) ;
-    R=sqrtm(Cov);
-    Realisation=R*randn(numel(x),1) ;
-
-    if DoPlots
-        figure;
-        for I=1:3
-            y=R*randn(numel(x),1) ;
-            plot(x/1000,y) ; ylabel('Matern realisation') ; xlabel('distance (km)')
-            hold on
-            fprintf(' Expected variance %f  \t  estimated variance %f \n ',sigma2,var(y))
-        end
-        title(sprintf(' A few examples of Matern realisations with rho=%i and sigma=%i',rho,sigma2))
-    end
-
-end
-
end
-
+Matern + + + + + + + +
+
+function [r,nu,kappa,sigma2Helmholtz,Cov,Realisation]=Matern(alpha,rho,d,x,sigma2,DoPlots)
+
+
[r,nu,kappa,sigma2,Cov,Realisation]=Matern(alpha,rho,d,x,sigma2,DoPlots)
+

Calculates the Matern covariance defined as

+

+$$ r(x)=\frac{\sigma^2}{2^{\nu-1} \Gamma(\nu)} (\kappa \, x )^{\nu} K_{\nu}(\kappa x)$$

+

Inputs:

+
  alpha   :   alpha/2 is the exponent in the fractional Helmholtz eqaution
+  rho     :   distance where correlation falls to 0.1
+  d       :   spatial dimention
+
  sigma2  :   marginal variance, (optional input)
+ DoPlots  :   plots of realisations if set to true (optional input)
+

Outputs:

+
     nu              :   nu=alpha-d/2;
+  kappa              :   the wave-number inthe Helmholtz equation
+  sigma2Helmholtz    :   marginal variance of the Helmholtz equation for the given
+                         kappa and alpha values
+  Cov                :   covariance matrix with the marginal covariance
+                         sigma2, if sigma2 is provided, otherwise with the
+                         marginal covariance sigma2Helmholtz
+  Realisation        :   One realisation of a Matern process.
+

+$$\nu=\alpha-d/2$$

+

for d=2 (i.e. two spatial dimentions) we have nu=2-1=1

+
rho=sqrt(8 nu)/kappa then given rho
+

+$$\kappa=\frac{\sqrt{8 \nu}}{\rho}$$

+

If sigma2 is not given on input, it is calculated based on expression in: Lindgren, F., Rue, H., & Lindström, J. (2011).

+

Note that if $\sigma^2$ is specified, the marginal variance of the Helmoltz equation with the specified alpha, rho and dimention will still be sigma2 as given

+

+$$ \sigma^2=\frac{\Gamma(\nu) }{\Gamma(\nu+d/2) (4 \pi)^{d/2} \kappa^{2 \nu} } $$

+

by the equation above!

+

Only input sigma2 if you interested in returning and using the covariance matrix Cov and the Realisation.

+

Example :

+
d=2; alpha=2 ; rho=4e3 ;
+dist=linspace(0,1e4,1e3) ; [r,nu,kappa,sigma2]=Matern(alpha,rho,d,dist);
+figure ; plot(dist,r) ; xlabel('distance') ; ylabel('Matern')
+title(['$$ \sigma^2= $$',num2str(sigma2),' $$ \rho=$$',num2str(rho)],'interpreter','latex')
+
+
+if nargin<6
+    DoPlots=false;
+end
+
+Cov=[] ; Realisation=[] ;
+
+% this gives a correlation of about 0.1 at the distance r
+nu=alpha-d/2;  % ie nu=1 for alpha=2 and dimention=2
+
+kappa=sqrt(8*nu)/rho;
+
+sigma2Helmholtz=gamma(nu) /  ( gamma(nu+d/2)*(4*pi)^(d/2)*kappa^(2*nu));
+
+if nargin<5
+    % Eq 1
+    sigma2=sigma2Helmholtz ;
+end
+
+x=kappa * x ;
+
+% this sigma2 should be referred to as sigma^2
+% some other sources appear to use a different defintion of rho
+% for example rho in https://en.wikipedia.org/wiki/Mat%C3%A9rn_covariance_function
+% appear to be 1/2 of the rho I use here
+% My notation is based on:
+%   Lindgren, F., Rue, H., & Lindström, J. (2011).
+%   An explicit link between Gaussian fields and Gaussian Markov random fields: the stochastic partial differential equation approach. Journal of the Royal Statistical Society: Series B (Statistical Methodology), 73(4), 423–498. https://doi.org/10.1111/j.1467-9868.2011.00777.x
+r = real(sigma2 * x.^nu .* besselk(nu,x)  / (2^(nu-1)*gamma(nu)) );
+
+
+if nargout>4 || DoPlots
+    F = griddedInterpolant(x,r) ;
+    D=ndgrid(x,x) ;
+    D=abs(D-D') ;
+
+    Cov=F(D) ;
+    R=sqrtm(Cov);
+    Realisation=R*randn(numel(x),1) ;
+
+    if DoPlots
+        figure;
+        for I=1:3
+            y=R*randn(numel(x),1) ;
+            plot(x/1000,y) ; ylabel('Matern realisation') ; xlabel('distance (km)')
+            hold on
+            fprintf(' Expected variance %f  \t  estimated variance %f \n ',sigma2,var(y))
+        end
+        title(sprintf(' A few examples of Matern realisations with rho=%i and sigma=%i',rho,sigma2))
+    end
+
+end
+
+
+end
+
+ +
+ \ No newline at end of file +--> + + diff --git a/html/PlotLatLonGrid.html b/html/PlotLatLonGrid.html index f8f9ff43..fc5e0d8a 100755 --- a/html/PlotLatLonGrid.html +++ b/html/PlotLatLonGrid.html @@ -1,180 +1,333 @@ - - - - - PlotLatLonGrid

Contents

function [Lat,Lon,X0,Y0,Clat,hlat,Clon,hlon,ax1,ax2]=PlotLatLonGrid(scale,dlat,dlon,LabelSpacing,Colour,isCircumpolar)
-

Plots a lat lon grid

[Lat,Lon,X0,Y0,Clat,hlat,Clon,hlon]=PlotLatLonGrid(scale,dlat,dlon,LabelSpacing,Colour,isCircumpolar)

NOTE: Do not use figure zoom after this or the lat/lon lin will get misaligned! Despite best atempts I have not been able to link the axis and get the right behaviour.

Example:

load('PIG-TWG-RestartFile.mat','CtrlVarInRestartFile','MUA','F')
-Fig=FindOrCreateFigure("PIG-TWG lat/lon") ;
-CtrlVar=CtrlVarInRestartFile ;
-cbar=UaPlots(CtrlVar,MUA,F,"-speed-") ;
-hold on ;
-[~,~,~,~,~,hlat,~,hlon]=PlotLatLonGrid(1000)   ; % often the colormap will have to be redefined after this call
-axis([-2000 -1000 -900 100])
-hlat.LineStyle="--"; hlon.LineStyle="--";
-clim([0 4000])
-ModifyColormap;
-
fig = gcf;
-ax1 = fig.CurrentAxes ;
-tt=axis;
-
-xmin=tt(1) ; xmax=tt(2) ; ymin=tt(3) ; ymax=tt(4) ;
-

create new axes for the lat/lon lines (never got this to work)

   ax2=axes ;
   ax2.Visible = 'off';
-   ax2.XTick = [];
-   ax2.YTick = [];
-   hold on
-   ax2.Position=ax1.Position;
-   ax2.XLim=ax1.XLim;
-   ax2.YLim=ax1.YLim;
ax=[] ;
-
if nargin<2 || isempty(dlat)
-    dlat=5;
-end
-
-if nargin<3 || isempty(dlon)
-    dlon=10;
-end
-
-if nargin<4 || isempty(LabelSpacing)
-    LabelSpacing=400;
-end
-
-if nargin<4 || isempty(Colour)
-   Colour='black';
-end
-
-
-if nargin<6
-    isCircumpolar=0;
-end
-
-lcol='k';
-
-
-
-[X0,Y0]=meshgrid(linspace(xmin,xmax,200),linspace(ymin,ymax,200));
-
-[Lat,Lon]=pol_to_geog_wgs84_71S(X0*scale,Y0*scale);
-
-if isCircumpolar
-    I=Lat>-62; Lon(I)=NaN ; Lat(I)=NaN;
-    I=Lat>-64.9;  Lon(I)=NaN;
-    I=Lat<-85.1 ; Lon(I)=NaN;
-    I=Lat<-86 ; Lat(I)=NaN ;
-    I=Lon<-175 ; Lon(I)=Lon(I)+360;
-    I=Lon<-170 ; Lon(I)=NaN;
-end
-
-
-hold on
-[Clat,hlat]=contour(ax1,X0,Y0,Lat,[-90:dlat:0],'LineColor',lcol);
-set(hlat,'ShowText','on','TextStep',get(hlat,'LevelStep')*2,'LabelSpacing',LabelSpacing)
-
-[Clon,hlon]=contour(ax1,X0,Y0,Lon,[-180+dlon:dlon:180],'LineColor',lcol);
-set(hlon,'ShowText','on','TextStep',get(hlon,'LevelStep')*2,'LabelSpacing',LabelSpacing)
-
-hlon.LineColor=Colour ;
-hlat.LineColor=Colour ;
-clabel(Clat,hlat,'Color',Colour)
-clabel(Clon,hlon,'Color',Colour)
-
-%linkaxes([ax1,ax2],"xy") ; %  For some reason this is not having the desired effect...?!
-%fig.CurrentAxes = ax1;
-%ax2.Position=ax1.Position;
-% revert back to original axes
-
end
-
+PlotLatLonGrid + + + + + + + +
+

Contents

+ +
+function [Lat,Lon,X0,Y0,Clat,hlat,Clon,hlon,ax1,ax2]=PlotLatLonGrid(scale,dlat,dlon,LabelSpacing,Colour,isCircumpolar)
+
+

Plots a lat lon grid

+

This is written for the Antarctica setting using polar stereographic coordinate system.

+

[Lat,Lon,X0,Y0,Clat,hlat,Clon,hlon]=PlotLatLonGrid(scale,dlat,dlon,LabelSpacing,Colour,isCircumpolar)

+

Inputes:

+
scale   ;    scales the x and the y axis. For example if the x,y units are meters, but you want to plot using km as a
+             distance units, set scale=1000
+
dlat, dlon : distance between lat and lon lines, in degrees
+
LableSpacing :   affects the spacing between labels, default is LableSpacing=400. Increase to increase spacing between lat
+                 lon labels.
+

Colour: color of the lat, lon lines

+

isCircumpolar: set to true if the plot area is circumpolar, ie includes the pole itself.

+

Outputs:

+
   Clat,hlat,Clon,hlon  : These are the contour matrices and the contour objects. The contour objects allow the properties
+   of the countour plots to be easily edited after the call.
+

NOTE #1: Do not use figure zoom after this or the lat/lon lin will get misaligned! Despite best atempts I have not been able to link the axis and get the right behaviour.

+

NOTE #2: As of Matlab2023b, Note#1 is no longer of relevance, which is good news!

+

Example:

+
load('PIG-TWG-RestartFile.mat','CtrlVarInRestartFile','MUA','F')
+CtrlVar=CtrlVarInRestartFile ;
+cbar=UaPlots(CtrlVar,MUA,F,"-speed-") ;
+hold on ;
+[~,~,~,~,~,hlat,~,hlon]=PlotLatLonGrid(1000)   ; % often the colormap will have to be redefined after this call
+axis([-2000 -1000 -900 100])
+hlat.LineStyle="--"; hlon.LineStyle="--";
+clim([0 4000])
+ModifyColormap;
+
+
fig = gcf;
+ax1 = fig.CurrentAxes ;
+tt=axis;
+
+xmin=tt(1) ; xmax=tt(2) ; ymin=tt(3) ; ymax=tt(4) ;
+
+

create new axes for the lat/lon lines (never got this to work)

+
   ax2=axes ;
+
   ax2.Visible = 'off';
+   ax2.XTick = [];
+   ax2.YTick = [];
+   hold on
+   ax2.Position=ax1.Position;
+   ax2.XLim=ax1.XLim;
+   ax2.YLim=ax1.YLim;
+
ax2=[] ;
+
+
+if nargin < 6
+    isCircumpolar=false;
+    if nargin < 5
+        Colour='black';
+        if nargin< 4
+            LabelSpacing=400;
+            if nargin< 3
+                dlon=10;
+                if nargin< 2
+                    dlat=2.5 ;
+                    if nargin==0
+                        scale=1000 ;
+                    end
+                end
+            end
+        end
+    end
+end
+
+
+% set some plausible values if user has not defined those already
+if isCircumpolar && isempty(dlat) &&  isempty(dlon)  &&  isempty(LabelSpacing)
+
+    dlat=10;
+    dlon=45;
+    LabelSpacing=200;
+
+else
+
+
+    if isempty(dlat)
+        dlat=5;
+    end
+
+    if isempty(dlon)
+        dlon=10;
+    end
+
+    if isempty(LabelSpacing)
+        LabelSpacing=400;
+    end
+
+    if isempty(Colour)
+        Colour='black';
+    end
+
+
+end
+
+lcol='k';
+
+climCopy=clim;
+
+
+[X0,Y0]=meshgrid(linspace(xmin,xmax,400),linspace(ymin,ymax,400));
+
+[Lat,Lon]=pol_to_geog_wgs84_71S(X0*scale,Y0*scale);
+
+if isCircumpolar
+    I=Lat>-62; Lon(I)=NaN ; Lat(I)=NaN;
+    I=Lat>-64.9;  Lon(I)=NaN;
+    I=Lat<-85.1 ; Lon(I)=NaN;
+    I=Lat<-86 ; Lat(I)=NaN ;
+    I=Lon<-171 ; Lon(I)=Lon(I)+360;
+    I=Lon<-170 ; Lon(I)=NaN;
+end
+
+
+hold on
+
+if isCircumpolar
+    [Clat,hlat]=contour(ax1,X0,Y0,Lat,[5:dlat:90],LineColor=lcol,LabelFormat=@mylabelfunLat);
+else
+    [Clat,hlat]=contour(ax1,X0,Y0,Lat,[-90:dlat:90],LineColor=lcol,LabelFormat=@mylabelfunLat);
+end
+
+set(hlat,'ShowText','on','TextStep',get(hlat,'LevelStep')*2,'LabelSpacing',LabelSpacing)
+
+
+[Clon,hlon]=contour(ax1,X0,Y0,Lon,[-180+dlon:dlon:185],LineColor=lcol,LabelFormat=@mylabelfunLon);
+set(hlon,'ShowText','on','TextStep',get(hlon,'LevelStep')*2,'LabelSpacing',LabelSpacing)
+
+
+hlon.LineColor=Colour ;
+hlat.LineColor=Colour ;
+clabel(Clat,hlat,Color=Colour,fontsize=9);
+clabel(Clon,hlon,Color=Colour,fontsize=9)
+
+
+%linkaxes([ax1,ax2],"xy") ; %  For some reason this is not having the desired effect...?!
+%fig.CurrentAxes = ax1;
+%ax2.Position=ax1.Position;
+% revert back to original axes
+
+
+clim(climCopy) % set color axis limit to the value at the beginning of the call
+               % this is done here because the contour functions above might change the existing limites
+
+    function labels=mylabelfunLon(vals)
+
+        % Degree=string(char(176))
+
+        labels= vals +"°E" ;
+        I=vals<0  ;  labels(I) = -vals(I) + "°W" ;
+        I=vals==0 ;  labels(I) = vals(I)  ;
+
+
+    end
+
+
+
+    function labels=mylabelfunLat(vals)
+
+
+        labels= vals +"°N" ;
+        I=vals<0  ;  labels(I) = -vals(I) + "°S" ;
+        I=vals==0 ;  labels(I) = vals(I)  ;
+
+
+    end
+
+
+end
+
+ +
+ \ No newline at end of file +--> + + diff --git a/html/ReleaseNotes.html b/html/ReleaseNotes.html index a94a3048..bdf22937 100755 --- a/html/ReleaseNotes.html +++ b/html/ReleaseNotes.html @@ -7,9 +7,9 @@ To make changes, update the MATLAB code and republish this document. --> ReleaseNotes - + - +