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

Last change on this file since 1759 was 1759, checked in by seroussi, 16 years ago

fixed macayeal

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