Mercurial > repos > public > sbplib
comparison +scheme/Elastic2dVariable.m @ 1062:e512714fb890 feature/laplace_curvilinear_test
Merge with feature/getBoundaryOp
author | Martin Almquist <malmquist@stanford.edu> |
---|---|
date | Mon, 14 Jan 2019 18:14:44 -0800 |
parents | a2fcc4cf2298 |
children | adbb80e60b10 |
comparison
equal
deleted
inserted
replaced
988:a72038b1f709 | 1062:e512714fb890 |
---|---|
28 | 28 |
29 % Traction operators used for BC | 29 % Traction operators used for BC |
30 T_l, T_r | 30 T_l, T_r |
31 tau_l, tau_r | 31 tau_l, tau_r |
32 | 32 |
33 H, Hi % Inner products | 33 H, Hi, H_1D % Inner products |
34 | |
35 phi % Borrowing constant for (d1 - e^T*D1) from R | |
36 gamma % Borrowing constant for d1 from M | |
37 H11 % First element of H | |
38 | |
39 % Borrowing from H, M, and R | |
40 thH | |
41 thM | |
42 thR | |
43 | |
44 e_l, e_r | 34 e_l, e_r |
35 | |
36 | |
45 d1_l, d1_r % Normal derivatives at the boundary | 37 d1_l, d1_r % Normal derivatives at the boundary |
46 E % E{i}^T picks out component i | 38 E % E{i}^T picks out component i |
47 | 39 |
48 H_boundary % Boundary inner products | 40 H_boundary % Boundary inner products |
49 | 41 |
50 % Kroneckered norms and coefficients | 42 % Kroneckered norms and coefficients |
51 RHOi_kron | 43 RHOi_kron |
52 Hi_kron | 44 Hi_kron |
45 | |
46 % Borrowing constants of the form gamma*h, where gamma is a dimensionless constant. | |
47 theta_R % Borrowing (d1- D1)^2 from R | |
48 theta_H % First entry in norm matrix | |
49 theta_M % Borrowing d1^2 from M. | |
50 | |
51 % Structures used for adjoint optimization | |
52 B | |
53 end | 53 end |
54 | 54 |
55 methods | 55 methods |
56 | 56 |
57 function obj = Elastic2dVariable(g ,order, lambda_fun, mu_fun, rho_fun, opSet) | 57 % The coefficients can either be function handles or grid functions |
58 function obj = Elastic2dVariable(g ,order, lambda, mu, rho, opSet) | |
58 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable}); | 59 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable}); |
59 default_arg('lambda_fun', @(x,y) 0*x+1); | 60 default_arg('lambda', @(x,y) 0*x+1); |
60 default_arg('mu_fun', @(x,y) 0*x+1); | 61 default_arg('mu', @(x,y) 0*x+1); |
61 default_arg('rho_fun', @(x,y) 0*x+1); | 62 default_arg('rho', @(x,y) 0*x+1); |
62 dim = 2; | 63 dim = 2; |
63 | 64 |
64 assert(isa(g, 'grid.Cartesian')) | 65 assert(isa(g, 'grid.Cartesian')) |
65 | 66 |
66 lambda = grid.evalOn(g, lambda_fun); | 67 if isa(lambda, 'function_handle') |
67 mu = grid.evalOn(g, mu_fun); | 68 lambda = grid.evalOn(g, lambda); |
68 rho = grid.evalOn(g, rho_fun); | 69 end |
70 if isa(mu, 'function_handle') | |
71 mu = grid.evalOn(g, mu); | |
72 end | |
73 if isa(rho, 'function_handle') | |
74 rho = grid.evalOn(g, rho); | |
75 end | |
76 | |
69 m = g.size(); | 77 m = g.size(); |
70 m_tot = g.N(); | 78 m_tot = g.N(); |
71 | 79 |
72 h = g.scaling(); | 80 h = g.scaling(); |
73 lim = g.lim; | 81 lim = g.lim; |
85 ops{i} = opSet{i}(m(i), lim{i}, order); | 93 ops{i} = opSet{i}(m(i), lim{i}, order); |
86 end | 94 end |
87 | 95 |
88 % Borrowing constants | 96 % Borrowing constants |
89 for i = 1:dim | 97 for i = 1:dim |
90 beta = ops{i}.borrowing.R.delta_D; | 98 obj.theta_R{i} = h(i)*ops{i}.borrowing.R.delta_D; |
91 obj.H11{i} = ops{i}.borrowing.H11; | 99 obj.theta_H{i} = h(i)*ops{i}.borrowing.H11; |
92 obj.phi{i} = beta/obj.H11{i}; | 100 obj.theta_M{i} = h(i)*ops{i}.borrowing.M.d1; |
93 obj.gamma{i} = ops{i}.borrowing.M.d1; | |
94 | |
95 % Better names | |
96 obj.thR{i} = ops{i}.borrowing.R.delta_D; | |
97 obj.thM{i} = ops{i}.borrowing.M.d1; | |
98 obj.thH{i} = ops{i}.borrowing.H11; | |
99 end | 101 end |
100 | 102 |
101 I = cell(dim,1); | 103 I = cell(dim,1); |
102 D1 = cell(dim,1); | 104 D1 = cell(dim,1); |
103 D2 = cell(dim,1); | 105 D2 = cell(dim,1); |
181 obj.H = kron(H{1},H{2}); | 183 obj.H = kron(H{1},H{2}); |
182 obj.Hi = inv(obj.H); | 184 obj.Hi = inv(obj.H); |
183 obj.H_boundary = cell(dim,1); | 185 obj.H_boundary = cell(dim,1); |
184 obj.H_boundary{1} = H{2}; | 186 obj.H_boundary{1} = H{2}; |
185 obj.H_boundary{2} = H{1}; | 187 obj.H_boundary{2} = H{1}; |
188 obj.H_1D = {H{1}, H{2}}; | |
186 | 189 |
187 % E{i}^T picks out component i. | 190 % E{i}^T picks out component i. |
188 E = cell(dim,1); | 191 E = cell(dim,1); |
189 I = speye(m_tot,m_tot); | 192 I = speye(m_tot,m_tot); |
190 for i = 1:dim | 193 for i = 1:dim |
211 D2_mu{j}*E{i}' ... | 214 D2_mu{j}*E{i}' ... |
212 ); | 215 ); |
213 end | 216 end |
214 end | 217 end |
215 obj.D = D; | 218 obj.D = D; |
216 %=========================================% | 219 %=========================================%' |
217 | 220 |
218 % Numerical traction operators for BC. | 221 % Numerical traction operators for BC. |
219 % Because d1 =/= e0^T*D1, the numerical tractions are different | 222 % Because d1 =/= e0^T*D1, the numerical tractions are different |
220 % at every boundary. | 223 % at every boundary. |
221 T_l = cell(dim,1); | 224 T_l = cell(dim,1); |
235 T_l{j} = cell(dim,dim); | 238 T_l{j} = cell(dim,dim); |
236 T_r{j} = cell(dim,dim); | 239 T_r{j} = cell(dim,dim); |
237 tau_l{j} = cell(dim,1); | 240 tau_l{j} = cell(dim,1); |
238 tau_r{j} = cell(dim,1); | 241 tau_r{j} = cell(dim,1); |
239 | 242 |
243 LAMBDA_l = e_l{j}'*LAMBDA*e_l{j}; | |
244 LAMBDA_r = e_r{j}'*LAMBDA*e_r{j}; | |
245 MU_l = e_l{j}'*MU*e_l{j}; | |
246 MU_r = e_r{j}'*MU*e_r{j}; | |
247 | |
248 [~, n_l] = size(e_l{j}); | |
249 [~, n_r] = size(e_r{j}); | |
250 | |
240 % Loop over components | 251 % Loop over components |
241 for i = 1:dim | 252 for i = 1:dim |
242 tau_l{j}{i} = sparse(m_tot,dim*m_tot); | 253 tau_l{j}{i} = sparse(n_l, dim*m_tot); |
243 tau_r{j}{i} = sparse(m_tot,dim*m_tot); | 254 tau_r{j}{i} = sparse(n_r, dim*m_tot); |
244 for k = 1:dim | 255 for k = 1:dim |
245 T_l{j}{i,k} = ... | 256 T_l{j}{i,k} = ... |
246 -d(i,j)*LAMBDA*(d(i,k)*e_l{k}*d1_l{k}' + db(i,k)*D1{k})... | 257 -d(i,j)*LAMBDA_l*(d(i,k)*d1_l{j}' + db(i,k)*e_l{j}'*D1{k})... |
247 -d(j,k)*MU*(d(i,j)*e_l{i}*d1_l{i}' + db(i,j)*D1{i})... | 258 -d(j,k)*MU_l*(d(i,j)*d1_l{j}' + db(i,j)*e_l{j}'*D1{i})... |
248 -d(i,k)*MU*e_l{j}*d1_l{j}'; | 259 -d(i,k)*MU_l*d1_l{j}'; |
249 | 260 |
250 T_r{j}{i,k} = ... | 261 T_r{j}{i,k} = ... |
251 d(i,j)*LAMBDA*(d(i,k)*e_r{k}*d1_r{k}' + db(i,k)*D1{k})... | 262 d(i,j)*LAMBDA_r*(d(i,k)*d1_r{j}' + db(i,k)*e_r{j}'*D1{k})... |
252 +d(j,k)*MU*(d(i,j)*e_r{i}*d1_r{i}' + db(i,j)*D1{i})... | 263 +d(j,k)*MU_r*(d(i,j)*d1_r{j}' + db(i,j)*e_r{j}'*D1{i})... |
253 +d(i,k)*MU*e_r{j}*d1_r{j}'; | 264 +d(i,k)*MU_r*d1_r{j}'; |
254 | 265 |
255 tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}'; | 266 tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}'; |
256 tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}'; | 267 tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}'; |
257 end | 268 end |
258 | 269 |
259 end | 270 end |
260 end | 271 end |
272 | |
273 % Transpose T and tau to match boundary operator convention | |
274 for i = 1:dim | |
275 for j = 1:dim | |
276 tau_l{i}{j} = transpose(tau_l{i}{j}); | |
277 tau_r{i}{j} = transpose(tau_r{i}{j}); | |
278 for k = 1:dim | |
279 T_l{i}{j,k} = transpose(T_l{i}{j,k}); | |
280 T_r{i}{j,k} = transpose(T_r{i}{j,k}); | |
281 end | |
282 end | |
283 end | |
284 | |
261 obj.T_l = T_l; | 285 obj.T_l = T_l; |
262 obj.T_r = T_r; | 286 obj.T_r = T_r; |
263 obj.tau_l = tau_l; | 287 obj.tau_l = tau_l; |
264 obj.tau_r = tau_r; | 288 obj.tau_r = tau_r; |
265 | 289 |
272 obj.m = m; | 296 obj.m = m; |
273 obj.h = h; | 297 obj.h = h; |
274 obj.order = order; | 298 obj.order = order; |
275 obj.grid = g; | 299 obj.grid = g; |
276 obj.dim = dim; | 300 obj.dim = dim; |
301 | |
302 % B, used for adjoint optimization | |
303 B = cell(dim, 1); | |
304 for i = 1:dim | |
305 B{i} = cell(m_tot, 1); | |
306 end | |
307 | |
308 for i = 1:dim | |
309 for j = 1:m_tot | |
310 B{i}{j} = sparse(m_tot, m_tot); | |
311 end | |
312 end | |
313 | |
314 ind = grid.funcToMatrix(g, 1:m_tot); | |
315 | |
316 % Direction 1 | |
317 for k = 1:m(1) | |
318 c = sparse(m(1),1); | |
319 c(k) = 1; | |
320 [~, B_1D] = ops{1}.D2(c); | |
321 for l = 1:m(2) | |
322 p = ind(:,l); | |
323 B{1}{(k-1)*m(2) + l}(p, p) = B_1D; | |
324 end | |
325 end | |
326 | |
327 % Direction 2 | |
328 for k = 1:m(2) | |
329 c = sparse(m(2),1); | |
330 c(k) = 1; | |
331 [~, B_1D] = ops{2}.D2(c); | |
332 for l = 1:m(1) | |
333 p = ind(l,:); | |
334 B{2}{(l-1)*m(2) + k}(p, p) = B_1D; | |
335 end | |
336 end | |
337 | |
338 obj.B = B; | |
277 | 339 |
278 end | 340 end |
279 | 341 |
280 | 342 |
281 % Closure functions return the operators applied to the own domain to close the boundary | 343 % Closure functions return the operators applied to the own domain to close the boundary |
293 comp = bc{1}; | 355 comp = bc{1}; |
294 type = bc{2}; | 356 type = bc{2}; |
295 | 357 |
296 % j is the coordinate direction of the boundary | 358 % j is the coordinate direction of the boundary |
297 j = obj.get_boundary_number(boundary); | 359 j = obj.get_boundary_number(boundary); |
298 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); | 360 [e, T, tau, H_gamma] = obj.getBoundaryOperator({'e','T','tau','H'}, boundary); |
361 | |
299 | 362 |
300 E = obj.E; | 363 E = obj.E; |
301 Hi = obj.Hi; | 364 Hi = obj.Hi; |
302 LAMBDA = obj.LAMBDA; | 365 LAMBDA = obj.LAMBDA; |
303 MU = obj.MU; | 366 MU = obj.MU; |
314 switch type | 377 switch type |
315 | 378 |
316 % Dirichlet boundary condition | 379 % Dirichlet boundary condition |
317 case {'D','d','dirichlet','Dirichlet'} | 380 case {'D','d','dirichlet','Dirichlet'} |
318 | 381 |
319 phi = obj.phi{j}; | 382 alpha = obj.getBoundaryOperator('alpha', boundary); |
320 h = obj.h(j); | |
321 h11 = obj.H11{j}*h; | |
322 gamma = obj.gamma{j}; | |
323 | |
324 a_lambda = dim/h11 + 1/(h11*phi); | |
325 a_mu_i = 2/(gamma*h); | |
326 a_mu_ij = 2/h11 + 1/(h11*phi); | |
327 | |
328 d = @kroneckerDelta; % Kronecker delta | |
329 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta | |
330 alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ... | |
331 + d(i,j)* a_mu_i*MU ... | |
332 + db(i,j)*a_mu_ij*MU ); | |
333 | 383 |
334 % Loop over components that Dirichlet penalties end up on | 384 % Loop over components that Dirichlet penalties end up on |
335 for i = 1:dim | 385 for i = 1:dim |
336 C = T{k,i}; | 386 C = transpose(T{k,i}); |
337 A = -d(i,k)*alpha(i,j); | 387 A = -tuning*e*transpose(alpha{i,k}); |
338 B = A + C; | 388 B = A + e*C; |
339 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' ); | 389 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' ); |
340 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma; | 390 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma; |
341 end | 391 end |
342 | 392 |
343 % Free boundary condition | 393 % Free boundary condition |
344 case {'F','f','Free','free','traction','Traction','t','T'} | 394 case {'F','f','Free','free','traction','Traction','t','T'} |
345 closure = closure - E{k}*RHOi*Hi*e*H_gamma* (e'*tau{k} ); | 395 closure = closure - E{k}*RHOi*Hi*e*H_gamma*tau{k}'; |
346 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma; | 396 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma; |
347 | 397 |
348 % Unknown boundary condition | 398 % Unknown boundary condition |
349 otherwise | 399 otherwise |
350 error('No such boundary condition: type = %s',type); | 400 error('No such boundary condition: type = %s',type); |
351 end | 401 end |
352 end | 402 end |
353 | 403 |
354 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary) | 404 % type Struct that specifies the interface coupling. |
405 % Fields: | |
406 % -- tuning: penalty strength, defaults to 1.2 | |
407 % -- interpolation: type of interpolation, default 'none' | |
408 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
409 | |
410 defaultType.tuning = 1.2; | |
411 defaultType.interpolation = 'none'; | |
412 default_struct('type', defaultType); | |
413 | |
414 switch type.interpolation | |
415 case {'none', ''} | |
416 [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type); | |
417 case {'op','OP'} | |
418 [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type); | |
419 otherwise | |
420 error('Unknown type of interpolation: %s ', type.interpolation); | |
421 end | |
422 end | |
423 | |
424 function [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type) | |
425 tuning = type.tuning; | |
426 | |
355 % u denotes the solution in the own domain | 427 % u denotes the solution in the own domain |
356 % v denotes the solution in the neighbour domain | 428 % v denotes the solution in the neighbour domain |
357 % Operators without subscripts are from the own domain. | 429 % Operators without subscripts are from the own domain. |
358 tuning = 1.2; | |
359 | |
360 % j is the coordinate direction of the boundary | |
361 j = obj.get_boundary_number(boundary); | |
362 j_v = neighbour_scheme.get_boundary_number(neighbour_boundary); | |
363 | 430 |
364 % Get boundary operators | 431 % Get boundary operators |
365 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); | 432 [e, tau] = obj.getBoundaryOperator({'e_tot','tau_tot'}, boundary); |
366 [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary); | 433 [e_v, tau_v] = neighbour_scheme.getBoundaryOperator({'e_tot','tau_tot'}, neighbour_boundary); |
434 H_gamma = obj.getBoundaryQuadrature(boundary); | |
367 | 435 |
368 % Operators and quantities that correspond to the own domain only | 436 % Operators and quantities that correspond to the own domain only |
369 Hi = obj.Hi; | 437 Hi = obj.Hi_kron; |
370 RHOi = obj.RHOi; | 438 RHOi = obj.RHOi_kron; |
371 dim = obj.dim; | 439 |
372 | 440 % Penalty strength operators |
373 %--- Other operators ---- | 441 alpha_u = 1/4*tuning*obj.getBoundaryOperator('alpha_tot', boundary); |
374 m_tot_u = obj.grid.N(); | 442 alpha_v = 1/4*tuning*neighbour_scheme.getBoundaryOperator('alpha_tot', neighbour_boundary); |
375 E = obj.E; | 443 |
376 LAMBDA_u = obj.LAMBDA; | 444 closure = -RHOi*Hi*e*H_gamma*(alpha_u' + alpha_v'*e_v*e'); |
377 MU_u = obj.MU; | 445 penalty = RHOi*Hi*e*H_gamma*(alpha_u'*e*e_v' + alpha_v'); |
378 lambda_u = e'*LAMBDA_u*e; | 446 |
379 mu_u = e'*MU_u*e; | 447 closure = closure - 1/2*RHOi*Hi*e*H_gamma*tau'; |
380 | 448 penalty = penalty - 1/2*RHOi*Hi*e*H_gamma*tau_v'; |
381 m_tot_v = neighbour_scheme.grid.N(); | 449 |
382 E_v = neighbour_scheme.E; | 450 closure = closure + 1/2*RHOi*Hi*tau*H_gamma*e'; |
383 LAMBDA_v = neighbour_scheme.LAMBDA; | 451 penalty = penalty - 1/2*RHOi*Hi*tau*H_gamma*e_v'; |
384 MU_v = neighbour_scheme.MU; | 452 |
385 lambda_v = e_v'*LAMBDA_v*e_v; | 453 end |
386 mu_v = e_v'*MU_v*e_v; | 454 |
387 %------------------------- | 455 function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type) |
388 | 456 error('Non-conforming interfaces not implemented yet.'); |
389 % Borrowing constants | |
390 h_u = obj.h(j); | |
391 thR_u = obj.thR{j}*h_u; | |
392 thM_u = obj.thM{j}*h_u; | |
393 thH_u = obj.thH{j}*h_u; | |
394 | |
395 h_v = neighbour_scheme.h(j_v); | |
396 thR_v = neighbour_scheme.thR{j_v}*h_v; | |
397 thH_v = neighbour_scheme.thH{j_v}*h_v; | |
398 thM_v = neighbour_scheme.thM{j_v}*h_v; | |
399 | |
400 % alpha = penalty strength for normal component, beta for tangential | |
401 alpha_u = dim*lambda_u/(4*thH_u) + lambda_u/(4*thR_u) + mu_u/(2*thM_u); | |
402 alpha_v = dim*lambda_v/(4*thH_v) + lambda_v/(4*thR_v) + mu_v/(2*thM_v); | |
403 beta_u = mu_u/(2*thH_u) + mu_u/(4*thR_u); | |
404 beta_v = mu_v/(2*thH_v) + mu_v/(4*thR_v); | |
405 alpha = alpha_u + alpha_v; | |
406 beta = beta_u + beta_v; | |
407 | |
408 d = @kroneckerDelta; % Kronecker delta | |
409 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta | |
410 strength = @(i,j) tuning*(d(i,j)*alpha + db(i,j)*beta); | |
411 | |
412 % Preallocate | |
413 closure = sparse(dim*m_tot_u, dim*m_tot_u); | |
414 penalty = sparse(dim*m_tot_u, dim*m_tot_v); | |
415 | |
416 % Loop over components that penalties end up on | |
417 for i = 1:dim | |
418 closure = closure - E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e'*E{i}'; | |
419 penalty = penalty + E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e_v'*E_v{i}'; | |
420 | |
421 closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*e'*tau{i}; | |
422 penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*e_v'*tau_v{i}; | |
423 | |
424 % Loop over components that we have interface conditions on | |
425 for k = 1:dim | |
426 closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}'; | |
427 penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}'; | |
428 end | |
429 end | |
430 end | 457 end |
431 | 458 |
432 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. | 459 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. |
433 function [j, nj] = get_boundary_number(obj, boundary) | 460 function [j, nj] = get_boundary_number(obj, boundary) |
434 | 461 |
449 end | 476 end |
450 end | 477 end |
451 | 478 |
452 % Returns the boundary operator op for the boundary specified by the string boundary. | 479 % Returns the boundary operator op for the boundary specified by the string boundary. |
453 % op: may be a cell array of strings | 480 % op: may be a cell array of strings |
454 function [varargout] = get_boundary_operator(obj, op, boundary) | 481 % Only operators with name *_tot can be used with multiblock.DiffOp.getBoundaryOperator() |
482 function [varargout] = getBoundaryOperator(obj, op, boundary) | |
455 | 483 |
456 switch boundary | 484 switch boundary |
457 case {'w','W','west','West', 'e', 'E', 'east', 'East'} | 485 case {'w','W','west','West', 'e', 'E', 'east', 'East'} |
458 j = 1; | 486 j = 1; |
459 case {'s','S','south','South', 'n', 'N', 'north', 'North'} | 487 case {'s','S','south','South', 'n', 'N', 'north', 'North'} |
464 | 492 |
465 if ~iscell(op) | 493 if ~iscell(op) |
466 op = {op}; | 494 op = {op}; |
467 end | 495 end |
468 | 496 |
469 for i = 1:length(op) | 497 for k = 1:length(op) |
470 switch op{i} | 498 switch op{k} |
471 case 'e' | 499 case 'e' |
472 switch boundary | 500 switch boundary |
473 case {'w','W','west','West','s','S','south','South'} | 501 case {'w','W','west','West','s','S','south','South'} |
474 varargout{i} = obj.e_l{j}; | 502 varargout{k} = obj.e_l{j}; |
475 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} | 503 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} |
476 varargout{i} = obj.e_r{j}; | 504 varargout{k} = obj.e_r{j}; |
477 end | 505 end |
506 | |
507 case 'e_tot' | |
508 e = obj.getBoundaryOperator('e', boundary); | |
509 I_dim = speye(obj.dim, obj.dim); | |
510 varargout{k} = kron(e, I_dim); | |
511 | |
478 case 'd' | 512 case 'd' |
479 switch boundary | 513 switch boundary |
480 case {'w','W','west','West','s','S','south','South'} | 514 case {'w','W','west','West','s','S','south','South'} |
481 varargout{i} = obj.d1_l{j}; | 515 varargout{k} = obj.d1_l{j}; |
482 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} | 516 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} |
483 varargout{i} = obj.d1_r{j}; | 517 varargout{k} = obj.d1_r{j}; |
484 end | 518 end |
485 case 'H' | 519 |
486 varargout{i} = obj.H_boundary{j}; | |
487 case 'T' | 520 case 'T' |
488 switch boundary | 521 switch boundary |
489 case {'w','W','west','West','s','S','south','South'} | 522 case {'w','W','west','West','s','S','south','South'} |
490 varargout{i} = obj.T_l{j}; | 523 varargout{k} = obj.T_l{j}; |
491 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} | 524 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} |
492 varargout{i} = obj.T_r{j}; | 525 varargout{k} = obj.T_r{j}; |
493 end | 526 end |
527 | |
494 case 'tau' | 528 case 'tau' |
495 switch boundary | 529 switch boundary |
496 case {'w','W','west','West','s','S','south','South'} | 530 case {'w','W','west','West','s','S','south','South'} |
497 varargout{i} = obj.tau_l{j}; | 531 varargout{k} = obj.tau_l{j}; |
498 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} | 532 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} |
499 varargout{i} = obj.tau_r{j}; | 533 varargout{k} = obj.tau_r{j}; |
500 end | 534 end |
535 | |
536 case 'tau_tot' | |
537 [e, tau] = obj.getBoundaryOperator({'e', 'tau'}, boundary); | |
538 | |
539 I_dim = speye(obj.dim, obj.dim); | |
540 e_tot = kron(e, I_dim); | |
541 E = obj.E; | |
542 tau_tot = (e_tot'*E{1}*e*tau{1}')'; | |
543 for i = 2:obj.dim | |
544 tau_tot = tau_tot + (e_tot'*E{i}*e*tau{i}')'; | |
545 end | |
546 varargout{k} = tau_tot; | |
547 | |
548 case 'H' | |
549 varargout{k} = obj.H_boundary{j}; | |
550 | |
551 case 'alpha' | |
552 % alpha = alpha(i,j) is the penalty strength for displacement BC. | |
553 e = obj.getBoundaryOperator('e', boundary); | |
554 | |
555 LAMBDA = obj.LAMBDA; | |
556 MU = obj.MU; | |
557 | |
558 dim = obj.dim; | |
559 theta_R = obj.theta_R{j}; | |
560 theta_H = obj.theta_H{j}; | |
561 theta_M = obj.theta_M{j}; | |
562 | |
563 a_lambda = dim/theta_H + 1/theta_R; | |
564 a_mu_i = 2/theta_M; | |
565 a_mu_ij = 2/theta_H + 1/theta_R; | |
566 | |
567 d = @kroneckerDelta; % Kronecker delta | |
568 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta | |
569 alpha = cell(obj.dim, obj.dim); | |
570 | |
571 alpha_func = @(i,j) d(i,j)* a_lambda*LAMBDA ... | |
572 + d(i,j)* a_mu_i*MU ... | |
573 + db(i,j)*a_mu_ij*MU; | |
574 for i = 1:obj.dim | |
575 for l = 1:obj.dim | |
576 alpha{i,l} = d(i,l)*alpha_func(i,j)*e; | |
577 end | |
578 end | |
579 | |
580 varargout{k} = alpha; | |
581 | |
582 case 'alpha_tot' | |
583 % alpha = alpha(i,j) is the penalty strength for displacement BC. | |
584 [e, e_tot, alpha] = obj.getBoundaryOperator({'e', 'e_tot', 'alpha'}, boundary); | |
585 E = obj.E; | |
586 [m, n] = size(alpha{1,1}); | |
587 alpha_tot = sparse(m*obj.dim, n*obj.dim); | |
588 for i = 1:obj.dim | |
589 for l = 1:obj.dim | |
590 alpha_tot = alpha_tot + (e_tot'*E{i}*e*alpha{i,l}'*E{l}')'; | |
591 end | |
592 end | |
593 varargout{k} = alpha_tot; | |
594 | |
501 otherwise | 595 otherwise |
502 error(['No such operator: operator = ' op{i}]); | 596 error(['No such operator: operator = ' op{k}]); |
503 end | 597 end |
504 end | 598 end |
505 | 599 |
600 end | |
601 | |
602 function H = getBoundaryQuadrature(obj, boundary) | |
603 switch boundary | |
604 case {'w','W','west','West', 'e', 'E', 'east', 'East'} | |
605 j = 1; | |
606 case {'s','S','south','South', 'n', 'N', 'north', 'North'} | |
607 j = 2; | |
608 otherwise | |
609 error('No such boundary: boundary = %s',boundary); | |
610 end | |
611 H = obj.H_boundary{j}; | |
612 I_dim = speye(obj.dim, obj.dim); | |
613 H = kron(H, I_dim); | |
506 end | 614 end |
507 | 615 |
508 function N = size(obj) | 616 function N = size(obj) |
509 N = obj.dim*prod(obj.m); | 617 N = obj.dim*prod(obj.m); |
510 end | 618 end |