source: issm/trunk/src/m/solutions/macayeal/diagnostic.m@ 67

Last change on this file since 67 was 67, checked in by Mathieu Morlighem, 16 years ago

Fixed convergence when absolute convergence criterion

File size: 12.6 KB
Line 
1function md=diagnostic(md)
2%DIAGNOSTIC - compute the velocity field of a 2d model using MacAyeal solution
3%
4% this routine solves the problem using MacAyeal's model. It calculates the velocity
5% field corresponding to the parameters and the geometry given by the model md
6%
7% Usage:
8% md=diagnostic(md)
9
10%First check we do have the correct argument number
11if ((nargin~=1) || (nargout~=1)),
12 macayealdiagnosticusage();
13 error('macayealdiagnostic error message: incorrect number of input and output arguments');
14end
15
16if ~isa(md,'model'),
17 macayealdiagnosticusage();
18 error('macayealdiagnostic error message: input argument is not a @model object');
19end
20
21%start timing
22t1=clock;
23
24%Transfer model fields into matlab variables
25x=md.x;
26y=md.y;
27
28index=md.elements;index=sort(index,2); %necessary
29nods=md.numberofgrids;
30nel=md.numberofelements;
31z_thick=md.thickness;
32z_surf=md.surface;
33z_bed=md.bed;
34z_thick_bar=(z_thick(index(:,1))+z_thick(index(:,2))+z_thick(index(:,3)))/3;
35rho_ice=md.rho_ice;
36rho_water=md.rho_water;
37g=md.g;
38viscosity_overshoot=md.viscosity_overshoot;
39index_icefront=md.segmentonneumann_diag; index_icefront=index_icefront(:,1:2); %we strip the last column, which holds the element number for the boundary segment
40nodes_on_boundary=md.gridonboundary;
41nodes_on_icefront=zeros(nods,1); nodes_on_icefront(index_icefront)=1;
42node_on_dirichlet=md.gridondirichlet_diag;
43nodes_on_icesheet=md.gridonicesheet;
44element_on_icesheet=md.elementonicesheet;
45qcoeff=md.q;
46pcoeff=md.p;
47drag_type=md.drag_type;
48drag=md.drag;
49
50criterion_rel=md.eps_rel;
51criterion_abs=md.eps_abs;
52yts=md.yts;
53B=md.B; B_bar=(B(index(:,1))+B(index(:,2))+B(index(:,3)))/3;
54glen_coeff=md.n;
55
56%average of p and q over the grids (size nel->nods)
57pcoeff_grid=zeros(nods,1);
58qcoeff_grid=zeros(nods,1);
59for i=1:nods
60 %1: find the elements that contain the grid i
61 neighbors_gridi=[];
62 for j=1:3
63 neighbors_gridi=[neighbors_gridi find(index(:,j)==i)'];
64 end
65 numberofneighbors_gridi=length(neighbors_gridi);
66 %2 retrieve the value of p and q over each of these elements. The average is
67 %plugged into dbx_grid
68 qcoeff_grid(i)=sum(qcoeff(neighbors_gridi))/numberofneighbors_gridi;
69 pcoeff_grid(i)=sum(pcoeff(neighbors_gridi))/numberofneighbors_gridi;
70end
71
72%Build length_icefront and normal_icefront:
73[length_icefront,normal_icefront]=buildicefrontnormal(x,y,index_icefront);
74
75%Start building areas
76aire=zeros(md.numberofelements,1);
77
78for n=1:nel
79 aire(n)=1/2 * det([1 1 1;x(index(n,:))';y(index(n,:))']);
80end
81
82aire=abs(aire); % if index is sorted from its original value, then aire could be negative
83
84alpha=zeros(nel,3);
85beta=zeros(nel,3);
86gamma=zeros(nel,3);
87
88for n=1:nel
89 X=inv([x(index(n,:)) y(index(n,:)) ones(3,1)]);
90 alpha(n,:)=X(1,:);
91 beta(n,:)=X(2,:);
92 gamma(n,:)=X(3,:);
93end
94
95clear X
96
97%Initialize viscosity
98nu_bar=viscosity(index,nel,alpha,beta,{},{},B_bar,glen_coeff);
99
100
101 % Do once and for all the initial computation of matrix-locations:
102
103row_location=zeros(nel*3*3,1);
104col_location=zeros(nel*3*3,1);
105row_location_AD=zeros(nel*6,1);
106col_location_AD=zeros(nel*6,1);
107
108count=-nel+1;
109
110for i=1:3
111 for j=1:3
112 count=count+nel;
113 row_location(count:count+nel-1)=index(:,i);
114 col_location(count:count+nel-1)=index(:,j);
115 end
116end
117
118
119count=-nel+1;
120
121for i=1:3
122 for j=i:3
123 count=count+nel;
124 row_location_AD(count:count+nel-1)=index(:,i);
125 col_location_AD(count:count+nel-1)=index(:,j);
126 end
127end
128
129
130
131permanent_pieces_of_A=zeros(nel*6,1);
132permanent_pieces_of_B=zeros(nel*3*3,1);
133permanent_pieces_of_C=zeros(nel*3*3,1);
134permanent_pieces_of_D=zeros(nel*6,1);
135
136count=-nel+1;
137
138for i=1:3
139 for j=i:3
140 count=count+nel;
141 permanent_pieces_of_A(count:count+nel-1)= z_thick_bar .* aire ...
142 .*(2*alpha(:,i).*alpha(:,j) + 1/2*beta(:,i).*beta(:,j));
143 % This loop structure works only when index is sorted
144 permanent_pieces_of_D(count:count+nel-1)= z_thick_bar .* aire ...
145 .*(2*beta(:,i).*beta(:,j) + 1/2*alpha(:,i).*alpha(:,j));
146
147 end
148end
149
150count=-nel+1;
151
152for i=1:3
153 for j=1:3
154 count=count+nel;
155
156 permanent_pieces_of_B(count:count+nel-1)= z_thick_bar .* aire ...
157 .*(alpha(:,j).*beta(:,i) + 1/2*beta(:,j).*alpha(:,i));
158
159 permanent_pieces_of_C(count:count+nel-1)= z_thick_bar .* aire ...
160 .*(beta(:,j).*alpha(:,i) + 1/2*alpha(:,j).*beta(:,i));
161
162
163 end
164end
165
166% Step 3 -- Set up right-hand side of the problem.
167
168% (Note to myself: to avoid vector dependency problem, yet still vectorize,
169% I treat the Rhs vector as a sparse matrix
170
171Rhs_x=zeros(nel*27,1);
172Rhs_y=zeros(nel*27,1);
173Rhs_y=ones(nel*27,1);
174row_rhs=zeros(nel*27,1);
175
176
177count=-nel+1;
178for i=1:3
179 for n=1:3
180 for m=1:3
181 count=count+nel;
182
183 Rhs_x(count:count+nel-1)= -rho_ice * g * ...
184 z_thick(index(:,n)).*z_surf(index(:,m)) ...
185 .* aire(:) .* alpha(:,m) * ( (n==i)/6 + (n~=i)/12 );
186
187 Rhs_y(count:count+nel-1)= -rho_ice * g * ...
188 z_thick(index(:,n)).*z_surf(index(:,m)) ...
189 .* aire(:) .* beta(:,m) .* ( (n==i)/6 + (n~=i)/12 );
190
191 row_rhs(count:count+nel-1)=index(:,i);
192
193 end
194 end
195end
196
197Rhs=full([sparse(row_rhs,ones(nel*27,1),Rhs_x,nods,1)
198 sparse(row_rhs,ones(nel*27,1),Rhs_y,nods,1)]);
199
200for k=1:2
201 for l=1:2
202 for j=1:2
203 Rhs(index_icefront(:,k))=Rhs(index_icefront(:,k)) + ...
204(rho_ice*g/2*z_thick(index_icefront(:,l)).*z_thick(index_icefront(:,j)) ...
205+ rho_water*g/2*(md.gridoniceshelf(index_icefront(:,k))) ...
206.*(-min(0,z_bed(index_icefront(:,l))).*min(0,z_bed(index_icefront(:,j))) ...
207+min(0,z_thick(index_icefront(:,l))+z_bed(index_icefront(:,l)))...
208.*min(0,z_thick(index_icefront(:,j))+z_bed(index_icefront(:,j)))))...
209.*normal_icefront(:,1).*length_icefront(:) ...
210/(4*(l==k & j==k) + 12*(l~=k | j~=k) );
211
212 Rhs(index_icefront(:,k)+nods)=Rhs(index_icefront(:,k)+nods) + ...
213(rho_ice*g/2*z_thick(index_icefront(:,l)).*z_thick(index_icefront(:,j)) ...
214+ rho_water*g/2*(md.gridoniceshelf(index_icefront(:,k))) ...
215.*(-min(0,z_bed(index_icefront(:,l))).*min(0,z_bed(index_icefront(:,j))) ...
216+min(0,z_thick(index_icefront(:,l))+z_bed(index_icefront(:,l)))...
217.*min(0,z_thick(index_icefront(:,j))+z_bed(index_icefront(:,j)))))...
218.*normal_icefront(:,2).*length_icefront(:) ...
219/(4*(l==k & j==k) + 12*(l~=k | j~=k) );
220
221 end
222 end
223end
224
225clear Rhs_x Rhs_y row_rhs
226
227% Step 4 -- Create the parsing matrix to "wring out"
228% the known boundary conditions
229
230% kinematic condition (u,v=0) specified at non-ice-front boundaries;
231num_specified= 2*sum(node_on_dirichlet);
232row=zeros(2*nods-num_specified,1);
233col=zeros(2*nods-num_specified,1);
234value=zeros(2*nods-num_specified,1);
235count=0;
236for n=1:nods
237 if(~node_on_dirichlet(n))
238 count=count+1;
239 row(count)=count;
240 col(count)=n;
241 value(count)=1;
242 end
243end
244for n=1:nods
245 if (~node_on_dirichlet(n))
246 count=count+1;
247 row(count)=count;
248 col(count)=nods+n;
249 value(count)=1;
250 end
251end
252
253P=sparse(row,col,value,2*nods-num_specified,2*nods);
254
255
256specified_velocity=zeros(2*nods,1);
257pos=find(node_on_dirichlet);
258specified_velocity(pos)=md.dirichletvalues_diag(pos,1)/md.yts;
259specified_velocity(nods+pos)=md.dirichletvalues_diag(pos,2)/md.yts;
260
261
262% ######## an attention grabbing break ########
263% Iterate on flow law till converged
264
265converged_yet=0;
266loop=0;
267
268u_old=zeros(nods,1);
269v_old=zeros(nods,1);
270convergence_count=1;
271
272while (~converged_yet)
273
274 if (loop>(100))
275 warning('Maximum Viscosity Iterations Reached.')
276 break;
277 end;
278 loop=loop+1;
279
280 nu_bar_oldvalue=nu_bar;
281
282 % Step 4 -- Set up stress-balance matrix (whos solution is the velocity
283 % field):
284
285 matrix_value_A=zeros(nel*6,1);
286 matrix_value_B=zeros(nel*3*3,1);
287 matrix_value_C=zeros(nel*3*3,1);
288 matrix_value_D=zeros(nel*6,1);
289
290 count=-nel+1;
291
292 for i=1:3
293 for j=i:3
294 count=count+nel;
295
296 matrix_value_A(count:count+nel-1)=nu_bar .* ...
297 permanent_pieces_of_A(count:count+nel-1);
298
299 matrix_value_D(count:count+nel-1)=nu_bar .* ...
300 permanent_pieces_of_D(count:count+nel-1);
301
302
303 end
304 end
305
306 count=-nel+1;
307
308 for i=1:3
309 for j=1:3
310 count=count+nel;
311
312 matrix_value_B(count:count+nel-1)=nu_bar .* ...
313 permanent_pieces_of_B(count:count+nel-1);
314
315 matrix_value_C(count:count+nel-1)=nu_bar .* ...
316 permanent_pieces_of_C(count:count+nel-1);
317
318
319 end
320 end
321
322
323
324 A=sparse(row_location_AD,col_location_AD,matrix_value_A,nods,nods);
325 A=A+triu(A,1)';
326 B=sparse(row_location,col_location,matrix_value_B,nods,nods);
327 C=sparse(row_location,col_location,matrix_value_C,nods,nods);
328 D=sparse(row_location_AD,col_location_AD,matrix_value_D,nods,nods);
329 D=D+triu(D,1)';
330
331
332 F=[A C
333 B D];
334
335 %Now, take care of the basal friction if there is any: to make things easier, we translate u = k *Neff^(-q)* sigma^p into
336 % sigma= drag^2 * Neff ^(r) * u^s with r=q/p and s=1/p : */
337
338 if (drag_type==2),
339 %compute coeffs:
340 rcoeff=qcoeff_grid./pcoeff_grid;
341 scoeff=1./pcoeff_grid;
342
343 %initialization of basal drag stiffness
344 Dragoperator=spalloc(2*nods,2*nods,0);
345
346 if loop~=1,
347
348 %retrieve the velocity magnitude
349 velocity_mag=sqrt(solution(1:nods).^2+solution(nods+1:2*nods).^2);
350
351 %Computation of the effective pressure
352 Neff=g*(rho_ice*z_thick+rho_water*z_bed);
353
354 %If effective pressure becomes negative, sliding becomes unstable (Paterson 4th edition p 148). This is because
355 %the water pressure is so high, the ice sheet elevates over its ice bumps and slides. But the limit behaviour
356 %for this should be an ice shelf sliding (no basal drag). Therefore, for any effective pressure Neff < 0, we should
357 %replace it by Neff=0 (ie, equival it to an ice shelf)*/
358 pos=find(Neff<0);
359 Neff(pos)=0;
360
361 %Basal drag coefficient: Tau_x=-alpha^2 u, Tau_y=-alpha^2 v (See
362 %MacAyeal)
363 alpha2=(drag.^2).*(Neff.^rcoeff).*(velocity_mag.^(scoeff-1));
364
365 %stiffness due to basal drag
366 %initialization
367 count=0;
368 value=zeros(nel,27);
369 row=zeros(nel,27);
370 col=zeros(nel,27);
371
372 for m=1:3
373 for k=1:3
374 for l=1:3
375 if ( (m==k) + (m==l) + (l==k) )==3
376 fac=1/10;
377 elseif ( (m==k) + (m==l) + (l==k) )==1
378 fac=1/30;
379 else
380 fac=1/60;
381 end
382
383 count=count+1;
384 row(:,count)=index(:,m);
385 col(:,count)=index(:,k);
386 value(:,count)=fac*aire(:).* ...
387 (alpha2(index(:,l)));%.*element_on_icesheet(index(:,l));
388
389 end
390 end
391 end
392
393 Dragoperator=[sparse(row,col,value,nods,nods) spalloc(nods,nods,0)
394 spalloc(nods,nods,0) sparse(row,col,value,nods,nods)];
395 end
396
397 F=F+Dragoperator; %plug into the global stiffness matrix
398
399 end
400
401
402 Rhs_parsed=P*(Rhs - F*specified_velocity);
403 F=P*F*P';
404
405
406 % Step 5 -- Solve the problem:
407
408 % Digression: if need be clear up some memory:
409
410 clear matrix_value_A ...
411 matrix_value_B matrix_value_C matrix_value_D A B C D
412
413 % We can use either the LU or the Cholesky decomposition, but the
414 % Cholesky decomposition is twice as efficient as LU for symmetric
415 % definite positive matrix
416
417 if strcmpi(md.solver_type,'lu'),
418 % Solve by LU decomposition.
419 [L,U] = lu(F);
420 solution= U\(L\Rhs_parsed);
421 elseif strcmpi(md.solver_type,'cholesky'),
422 % Solve by Choleski decomposition.
423 L = chol(F);
424 solution= L\(L'\Rhs_parsed);
425 else
426 % use matlab's generic solver
427 solution = F\Rhs_parsed;
428 end
429
430
431
432 %Add spcs to the calculated solution
433 solution=P'*solution + specified_velocity;
434
435 %Recover solution vector
436 u=solution(1:nods);
437 v=solution(nods+1:2*nods);
438
439 %Compute viscosity
440 nu_bar=viscosity(index,nel,alpha,beta,u,v,B_bar,glen_coeff);
441 change=1 - nu_bar_oldvalue./nu_bar;
442
443 %Update viscosity
444 nu_bar=nu_bar.*(1+viscosity_overshoot*change);
445 location=find(nu_bar<=0);
446 nu_bar(location)=-nu_bar(location);
447
448 %Test for direct shooting convergence
449 if convergence_count>1,
450
451 ug=[u_old;v_old];
452 nug=norm(ug,2);
453 dug=[u; v]-[u_old; v_old];
454 ndug=norm(dug,2);
455 relative_change=ndug/nug;
456
457
458 %Figure out if viscosity converged
459 if relative_change<criterion_rel,
460 disp(sprintf('%s %g %s %g %s',' Convergence criterion: norm(du)/norm(u)=',relative_change,' < ',criterion_rel,' m/yr'));
461 converged_yet=1;
462 else
463 disp(sprintf('%s %g %s %g %s',' Convergence criterion: norm(du)/norm(u)=',relative_change,' > ',criterion_rel,' m/yr'));
464 converged_yet=0;
465 end
466
467 if ~isnan(criterion_abs),
468 change=max(abs(dug))*yts;
469 if change<criterion_abs
470 disp(sprintf('%s %g %s %g %s',' Convergence criterion: max(du)=',change,' < ',criterion_abs,' m/yr'));
471 else
472 disp(sprintf('%s %g %s %g %s',' Convergence criterion: max(du)=',change,' > ',criterion_abs,' m/yr'));
473 converged_yet=0;
474 end
475 end
476 else
477 converged_yet=0;
478 end
479
480 u_old=u;
481 v_old=v;
482
483 convergence_count=convergence_count+1;
484
485end % This end statement terminates the "while" command way above
486
487%Load results onto md:
488md.vx=u*yts;
489md.vy=v*yts;
490md.vel=sqrt(md.vx.^2+md.vy.^2);
491
492%stop timing
493t2=clock;
494
495disp(sprintf('\n%s\n',['solution converged in ' num2str(etime(t2,t1)) ' seconds']));
496
497function macayealdiagnosticusage();
498disp('md=macayealdiagnostic(md)');
499disp(' where md is a structure of class @model');
Note: See TracBrowser for help on using the repository browser.