comparison +scheme/Elastic2dVariable.m @ 890:c70131daaa6e feature/d1_staggered

Merge with feature/poroelastic.
author Martin Almquist <malmquist@stanford.edu>
date Wed, 21 Nov 2018 18:29:29 -0800
parents 14fee299ada2
children e30aaa4a3e09 386ef449df51
comparison
equal deleted inserted replaced
885:18e10217dca9 890:c70131daaa6e
1 classdef Elastic2dVariable < scheme.Scheme 1 classdef Elastic2dVariable < scheme.Scheme
2 2
3 % Discretizes the elastic wave equation: 3 % Discretizes the elastic wave equation:
4 % rho u_{i,tt} = di lambda dj u_j + dj mu di u_j + dj mu dj u_i 4 % rho u_{i,tt} = di lambda dj u_j + dj mu di u_j + dj mu dj u_i
5 % opSet should be cell array of opSets, one per dimension. This 5 % opSet should be cell array of opSets, one per dimension. This
6 % is useful if we have periodic BC in one direction. 6 % is useful if we have periodic BC in one direction.
7 7
8 properties 8 properties
9 m % Number of points in each direction, possibly a vector 9 m % Number of points in each direction, possibly a vector
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 phi % Borrowing constant for (d1 - e^T*D1) from R
35 gamma % Borrowing constant for d1 from M
36 H11 % First element of H
37 e_l, e_r 34 e_l, e_r
38 d1_l, d1_r % Normal derivatives at the boundary 35 d1_l, d1_r % Normal derivatives at the boundary
39 E % E{i}^T picks out component i 36 E % E{i}^T picks out component i
40 37
41 H_boundary % Boundary inner products 38 H_boundary % Boundary inner products
42 39
43 % Kroneckered norms and coefficients 40 % Kroneckered norms and coefficients
44 RHOi_kron 41 RHOi_kron
45 Hi_kron 42 Hi_kron
43
44 % Borrowing constants of the form gamma*h, where gamma is a dimensionless constant.
45 theta_R % Borrowing (d1- D1)^2 from R
46 theta_H % First entry in norm matrix
47 theta_M % Borrowing d1^2 from M.
48
49 % Structures used for adjoint optimization
50 B
46 end 51 end
47 52
48 methods 53 methods
49 54
50 function obj = Elastic2dVariable(g ,order, lambda_fun, mu_fun, rho_fun, opSet) 55 % The coefficients can either be function handles or grid functions
56 function obj = Elastic2dVariable(g ,order, lambda, mu, rho, opSet)
51 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable}); 57 default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable});
52 default_arg('lambda_fun', @(x,y) 0*x+1); 58 default_arg('lambda', @(x,y) 0*x+1);
53 default_arg('mu_fun', @(x,y) 0*x+1); 59 default_arg('mu', @(x,y) 0*x+1);
54 default_arg('rho_fun', @(x,y) 0*x+1); 60 default_arg('rho', @(x,y) 0*x+1);
55 dim = 2; 61 dim = 2;
56 62
57 assert(isa(g, 'grid.Cartesian')) 63 assert(isa(g, 'grid.Cartesian'))
58 64
59 lambda = grid.evalOn(g, lambda_fun); 65 if isa(lambda, 'function_handle')
60 mu = grid.evalOn(g, mu_fun); 66 lambda = grid.evalOn(g, lambda);
61 rho = grid.evalOn(g, rho_fun); 67 end
68 if isa(mu, 'function_handle')
69 mu = grid.evalOn(g, mu);
70 end
71 if isa(rho, 'function_handle')
72 rho = grid.evalOn(g, rho);
73 end
74
62 m = g.size(); 75 m = g.size();
63 m_tot = g.N(); 76 m_tot = g.N();
64 77
65 h = g.scaling(); 78 h = g.scaling();
66 lim = g.lim; 79 lim = g.lim;
80 if isempty(lim)
81 x = g.x;
82 lim = cell(length(x),1);
83 for i = 1:length(x)
84 lim{i} = {min(x{i}), max(x{i})};
85 end
86 end
67 87
68 % 1D operators 88 % 1D operators
69 ops = cell(dim,1); 89 ops = cell(dim,1);
70 for i = 1:dim 90 for i = 1:dim
71 ops{i} = opSet{i}(m(i), lim{i}, order); 91 ops{i} = opSet{i}(m(i), lim{i}, order);
72 end 92 end
73 93
74 % Borrowing constants 94 % Borrowing constants
75 for i = 1:dim 95 for i = 1:dim
76 beta = ops{i}.borrowing.R.delta_D; 96 obj.theta_R{i} = h(i)*ops{i}.borrowing.R.delta_D;
77 obj.H11{i} = ops{i}.borrowing.H11; 97 obj.theta_H{i} = h(i)*ops{i}.borrowing.H11;
78 obj.phi{i} = beta/obj.H11{i}; 98 obj.theta_M{i} = h(i)*ops{i}.borrowing.M.d1;
79 obj.gamma{i} = ops{i}.borrowing.M.d1;
80 end 99 end
81 100
82 I = cell(dim,1); 101 I = cell(dim,1);
83 D1 = cell(dim,1); 102 D1 = cell(dim,1);
84 D2 = cell(dim,1); 103 D2 = cell(dim,1);
162 obj.H = kron(H{1},H{2}); 181 obj.H = kron(H{1},H{2});
163 obj.Hi = inv(obj.H); 182 obj.Hi = inv(obj.H);
164 obj.H_boundary = cell(dim,1); 183 obj.H_boundary = cell(dim,1);
165 obj.H_boundary{1} = H{2}; 184 obj.H_boundary{1} = H{2};
166 obj.H_boundary{2} = H{1}; 185 obj.H_boundary{2} = H{1};
186 obj.H_1D = {H{1}, H{2}};
167 187
168 % E{i}^T picks out component i. 188 % E{i}^T picks out component i.
169 E = cell(dim,1); 189 E = cell(dim,1);
170 I = speye(m_tot,m_tot); 190 I = speye(m_tot,m_tot);
171 for i = 1:dim 191 for i = 1:dim
192 D2_mu{j}*E{i}' ... 212 D2_mu{j}*E{i}' ...
193 ); 213 );
194 end 214 end
195 end 215 end
196 obj.D = D; 216 obj.D = D;
197 %=========================================% 217 %=========================================%'
198 218
199 % Numerical traction operators for BC. 219 % Numerical traction operators for BC.
200 % Because d1 =/= e0^T*D1, the numerical tractions are different 220 % Because d1 =/= e0^T*D1, the numerical tractions are different
201 % at every boundary. 221 % at every boundary.
202 T_l = cell(dim,1); 222 T_l = cell(dim,1);
221 % Loop over components 241 % Loop over components
222 for i = 1:dim 242 for i = 1:dim
223 tau_l{j}{i} = sparse(m_tot,dim*m_tot); 243 tau_l{j}{i} = sparse(m_tot,dim*m_tot);
224 tau_r{j}{i} = sparse(m_tot,dim*m_tot); 244 tau_r{j}{i} = sparse(m_tot,dim*m_tot);
225 for k = 1:dim 245 for k = 1:dim
226 T_l{j}{i,k} = ... 246 T_l{j}{i,k} = ...
227 -d(i,j)*LAMBDA*(d(i,k)*e_l{k}*d1_l{k}' + db(i,k)*D1{k})... 247 -d(i,j)*LAMBDA*(d(i,k)*e_l{k}*d1_l{k}' + db(i,k)*D1{k})...
228 -d(j,k)*MU*(d(i,j)*e_l{i}*d1_l{i}' + db(i,j)*D1{i})... 248 -d(j,k)*MU*(d(i,j)*e_l{i}*d1_l{i}' + db(i,j)*D1{i})...
229 -d(i,k)*MU*e_l{j}*d1_l{j}'; 249 -d(i,k)*MU*e_l{j}*d1_l{j}';
230 250
231 T_r{j}{i,k} = ... 251 T_r{j}{i,k} = ...
232 d(i,j)*LAMBDA*(d(i,k)*e_r{k}*d1_r{k}' + db(i,k)*D1{k})... 252 d(i,j)*LAMBDA*(d(i,k)*e_r{k}*d1_r{k}' + db(i,k)*D1{k})...
233 +d(j,k)*MU*(d(i,j)*e_r{i}*d1_r{i}' + db(i,j)*D1{i})... 253 +d(j,k)*MU*(d(i,j)*e_r{i}*d1_r{i}' + db(i,j)*D1{i})...
234 +d(i,k)*MU*e_r{j}*d1_r{j}'; 254 +d(i,k)*MU*e_r{j}*d1_r{j}';
235 255
236 tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}'; 256 tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}';
237 tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}'; 257 tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}';
238 end 258 end
254 obj.h = h; 274 obj.h = h;
255 obj.order = order; 275 obj.order = order;
256 obj.grid = g; 276 obj.grid = g;
257 obj.dim = dim; 277 obj.dim = dim;
258 278
279 % Used for adjoint optimization
280 obj.B = cell(1,dim);
281 for i = 1:dim
282 obj.B{i} = zeros(m(i),m(i),m(i));
283 for k = 1:m(i)
284 c = sparse(m(i),1);
285 c(k) = 1;
286 [~, obj.B{i}(:,:,k)] = ops{i}.D2(c);
287 end
288 end
289
259 end 290 end
260 291
261 292
262 % Closure functions return the operators applied to the own domain to close the boundary 293 % Closure functions return the operators applied to the own domain to close the boundary
263 % Penalty functions return the operators to force the solution. In the case of an interface it returns the operator applied to the other doamin. 294 % Penalty functions return the operators to force the solution. In the case of an interface it returns the operator applied to the other doamin.
264 % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'. 295 % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'.
265 % type is a cell array of strings specifying the type of boundary condition for each component. 296 % bc is a cell array of component and bc type, e.g. {1, 'd'} for Dirichlet condition
297 % on the first component.
266 % data is a function returning the data that should be applied at the boundary. 298 % data is a function returning the data that should be applied at the boundary.
267 % neighbour_scheme is an instance of Scheme that should be interfaced to. 299 % neighbour_scheme is an instance of Scheme that should be interfaced to.
268 % neighbour_boundary is a string specifying which boundary to interface to. 300 % neighbour_boundary is a string specifying which boundary to interface to.
269 function [closure, penalty] = boundary_condition(obj, boundary, type, parameter) 301 function [closure, penalty] = boundary_condition(obj, boundary, bc, tuning)
270 default_arg('type',{'free','free'}); 302 default_arg('tuning', 1.2);
271 default_arg('parameter', []); 303
304 assert( iscell(bc), 'The BC type must be a 2x1 cell array' );
305 comp = bc{1};
306 type = bc{2};
272 307
273 % j is the coordinate direction of the boundary 308 % j is the coordinate direction of the boundary
274 % nj: outward unit normal component. 309 j = obj.get_boundary_number(boundary);
275 % nj = -1 for west, south, bottom boundaries 310 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
276 % nj = 1 for east, north, top boundaries
277 [j, nj] = obj.get_boundary_number(boundary);
278 switch nj
279 case 1
280 e = obj.e_r;
281 d = obj.d1_r;
282 tau = obj.tau_r{j};
283 T = obj.T_r{j};
284 case -1
285 e = obj.e_l;
286 d = obj.d1_l;
287 tau = obj.tau_l{j};
288 T = obj.T_l{j};
289 end
290 311
291 E = obj.E; 312 E = obj.E;
292 Hi = obj.Hi; 313 Hi = obj.Hi;
293 H_gamma = obj.H_boundary{j};
294 LAMBDA = obj.LAMBDA; 314 LAMBDA = obj.LAMBDA;
295 MU = obj.MU; 315 MU = obj.MU;
296 RHOi = obj.RHOi; 316 RHOi = obj.RHOi;
297 317
298 dim = obj.dim; 318 dim = obj.dim;
299 m_tot = obj.grid.N(); 319 m_tot = obj.grid.N();
300 320
301 RHOi_kron = obj.RHOi_kron;
302 Hi_kron = obj.Hi_kron;
303
304 % Preallocate 321 % Preallocate
305 closure = sparse(dim*m_tot, dim*m_tot); 322 closure = sparse(dim*m_tot, dim*m_tot);
306 penalty = cell(dim,1); 323 penalty = sparse(dim*m_tot, m_tot/obj.m(j));
307 for k = 1:dim 324
308 penalty{k} = sparse(dim*m_tot, m_tot/obj.m(j)); 325 k = comp;
309 end 326 switch type
310 327
311 % Loop over components that we (potentially) have different BC on 328 % Dirichlet boundary condition
312 for k = 1:dim 329 case {'D','d','dirichlet','Dirichlet'}
313 switch type{k} 330
314 331 theta_R = obj.theta_R{j};
315 % Dirichlet boundary condition 332 theta_H = obj.theta_H{j};
316 case {'D','d','dirichlet','Dirichlet'} 333 theta_M = obj.theta_M{j};
317 334
318 tuning = 1.2; 335 a_lambda = dim/theta_H + 1/theta_R;
319 phi = obj.phi{j}; 336 a_mu_i = 2/theta_M;
320 h = obj.h(j); 337 a_mu_ij = 2/theta_H + 1/theta_R;
321 h11 = obj.H11{j}*h; 338
322 gamma = obj.gamma{j}; 339 d = @kroneckerDelta; % Kronecker delta
323 340 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
324 a_lambda = dim/h11 + 1/(h11*phi); 341 alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ...
325 a_mu_i = 2/(gamma*h); 342 + d(i,j)* a_mu_i*MU ...
326 a_mu_ij = 2/h11 + 1/(h11*phi); 343 + db(i,j)*a_mu_ij*MU );
327 344
328 d = @kroneckerDelta; % Kronecker delta 345 % Loop over components that Dirichlet penalties end up on
329 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta 346 for i = 1:dim
330 alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ... 347 C = T{k,i};
331 + d(i,j)* a_mu_i*MU ... 348 A = -d(i,k)*alpha(i,j);
332 + db(i,j)*a_mu_ij*MU ); 349 B = A + C;
333 350 closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' );
334 % Loop over components that Dirichlet penalties end up on 351 penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma;
335 for i = 1:dim 352 end
336 C = T{k,i}; 353
337 A = -d(i,k)*alpha(i,j); 354 % Free boundary condition
338 B = A + C; 355 case {'F','f','Free','free','traction','Traction','t','T'}
339 closure = closure + E{i}*RHOi*Hi*B'*e{j}*H_gamma*(e{j}'*E{k}' ); 356 closure = closure - E{k}*RHOi*Hi*e*H_gamma* (e'*tau{k} );
340 penalty{k} = penalty{k} - E{i}*RHOi*Hi*B'*e{j}*H_gamma; 357 penalty = penalty + E{k}*RHOi*Hi*e*H_gamma;
341 end 358
342 359 % Unknown boundary condition
343 % Free boundary condition 360 otherwise
344 case {'F','f','Free','free','traction','Traction','t','T'} 361 error('No such boundary condition: type = %s',type);
345 closure = closure - E{k}*RHOi*Hi*e{j}*H_gamma* (e{j}'*tau{k} );
346 penalty{k} = penalty{k} + E{k}*RHOi*Hi*e{j}*H_gamma;
347
348 % Unknown boundary condition
349 otherwise
350 error('No such boundary condition: type = %s',type);
351 end
352 end 362 end
353 end 363 end
354 364
355 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary) 365 function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
356 % u denotes the solution in the own domain 366 % u denotes the solution in the own domain
357 % v denotes the solution in the neighbour domain 367 % v denotes the solution in the neighbour domain
368 % Operators without subscripts are from the own domain.
358 tuning = 1.2; 369 tuning = 1.2;
359 % tuning = 20.2; 370
360 error('Interface not implemented'); 371 % j is the coordinate direction of the boundary
372 j = obj.get_boundary_number(boundary);
373 j_v = neighbour_scheme.get_boundary_number(neighbour_boundary);
374
375 % Get boundary operators
376 [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
377 [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary);
378
379 % Operators and quantities that correspond to the own domain only
380 Hi = obj.Hi;
381 RHOi = obj.RHOi;
382 dim = obj.dim;
383
384 %--- Other operators ----
385 m_tot_u = obj.grid.N();
386 E = obj.E;
387 LAMBDA_u = obj.LAMBDA;
388 MU_u = obj.MU;
389 lambda_u = e'*LAMBDA_u*e;
390 mu_u = e'*MU_u*e;
391
392 m_tot_v = neighbour_scheme.grid.N();
393 E_v = neighbour_scheme.E;
394 LAMBDA_v = neighbour_scheme.LAMBDA;
395 MU_v = neighbour_scheme.MU;
396 lambda_v = e_v'*LAMBDA_v*e_v;
397 mu_v = e_v'*MU_v*e_v;
398 %-------------------------
399
400 % Borrowing constants
401 theta_R_u = obj.theta_R{j};
402 theta_H_u = obj.theta_H{j};
403 theta_M_u = obj.theta_M{j};
404
405 theta_R_v = neighbour_scheme.theta_R{j_v};
406 theta_H_v = neighbour_scheme.theta_H{j_v};
407 theta_M_v = neighbour_scheme.theta_M{j_v};
408
409 function [alpha_ii, alpha_ij] = computeAlpha(th_R, th_H, th_M, lambda, mu)
410 alpha_ii = dim*lambda/(4*th_H) + lambda/(4*th_R) + mu/(2*th_M);
411 alpha_ij = mu/(2*th_H) + mu/(4*th_R);
412 end
413
414 [alpha_ii_u, alpha_ij_u] = computeAlpha(theta_R_u, theta_H_u, theta_M_u, lambda_u, mu_u);
415 [alpha_ii_v, alpha_ij_v] = computeAlpha(theta_R_v, theta_H_v, theta_M_v, lambda_v, mu_v);
416 sigma_ii = tuning*(alpha_ii_u + alpha_ii_v);
417 sigma_ij = tuning*(alpha_ij_u + alpha_ij_v);
418
419 d = @kroneckerDelta; % Kronecker delta
420 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
421 sigma = @(i,j) tuning*(d(i,j)*sigma_ii + db(i,j)*sigma_ij);
422
423 % Preallocate
424 closure = sparse(dim*m_tot_u, dim*m_tot_u);
425 penalty = sparse(dim*m_tot_u, dim*m_tot_v);
426
427 % Loop over components that penalties end up on
428 for i = 1:dim
429 closure = closure - E{i}*RHOi*Hi*e*sigma(i,j)*H_gamma*e'*E{i}';
430 penalty = penalty + E{i}*RHOi*Hi*e*sigma(i,j)*H_gamma*e_v'*E_v{i}';
431
432 closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*e'*tau{i};
433 penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*e_v'*tau_v{i};
434
435 % Loop over components that we have interface conditions on
436 for k = 1:dim
437 closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}';
438 penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}';
439 end
440 end
361 end 441 end
362 442
363 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. 443 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary.
364 function [j, nj] = get_boundary_number(obj, boundary) 444 function [j, nj] = get_boundary_number(obj, boundary)
365 445
378 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 458 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
379 nj = 1; 459 nj = 1;
380 end 460 end
381 end 461 end
382 462
383 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. 463 % Returns the boundary operator op for the boundary specified by the string boundary.
384 function [return_op] = get_boundary_operator(obj, op, boundary) 464 % op: may be a cell array of strings
465 function [varargout] = get_boundary_operator(obj, op, boundary)
385 466
386 switch boundary 467 switch boundary
387 case {'w','W','west','West', 'e', 'E', 'east', 'East'} 468 case {'w','W','west','West', 'e', 'E', 'east', 'East'}
388 j = 1; 469 j = 1;
389 case {'s','S','south','South', 'n', 'N', 'north', 'North'} 470 case {'s','S','south','South', 'n', 'N', 'north', 'North'}
390 j = 2; 471 j = 2;
391 otherwise 472 otherwise
392 error('No such boundary: boundary = %s',boundary); 473 error('No such boundary: boundary = %s',boundary);
393 end 474 end
394 475
395 switch op 476 if ~iscell(op)
396 case 'e' 477 op = {op};
397 switch boundary 478 end
398 case {'w','W','west','West','s','S','south','South'} 479
399 return_op = obj.e_l{j}; 480 for i = 1:length(op)
400 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 481 switch op{i}
401 return_op = obj.e_r{j}; 482 case 'e'
402 end 483 switch boundary
403 case 'd' 484 case {'w','W','west','West','s','S','south','South'}
404 switch boundary 485 varargout{i} = obj.e_l{j};
405 case {'w','W','west','West','s','S','south','South'} 486 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
406 return_op = obj.d1_l{j}; 487 varargout{i} = obj.e_r{j};
407 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} 488 end
408 return_op = obj.d1_r{j}; 489 case 'd'
409 end 490 switch boundary
410 otherwise 491 case {'w','W','west','West','s','S','south','South'}
411 error(['No such operator: operatr = ' op]); 492 varargout{i} = obj.d1_l{j};
493 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
494 varargout{i} = obj.d1_r{j};
495 end
496 case 'H'
497 varargout{i} = obj.H_boundary{j};
498 case 'T'
499 switch boundary
500 case {'w','W','west','West','s','S','south','South'}
501 varargout{i} = obj.T_l{j};
502 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
503 varargout{i} = obj.T_r{j};
504 end
505 case 'tau'
506 switch boundary
507 case {'w','W','west','West','s','S','south','South'}
508 varargout{i} = obj.tau_l{j};
509 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
510 varargout{i} = obj.tau_r{j};
511 end
512 case 'alpha'
513 % alpha = alpha(i,j) is the penalty strength for displacement BC.
514 tuning = 1.2;
515 LAMBDA = obj.LAMBDA;
516 MU = obj.MU;
517
518 phi = obj.phi{j};
519 h = obj.h(j);
520 h11 = obj.H11{j}*h;
521 gamma = obj.gamma{j};
522 dim = obj.dim;
523
524 a_lambda = dim/h11 + 1/(h11*phi);
525 a_mu_i = 2/(gamma*h);
526 a_mu_ij = 2/h11 + 1/(h11*phi);
527
528 d = @kroneckerDelta; % Kronecker delta
529 db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
530 alpha = @(i,k) d(i,k)*tuning*( d(i,j)* a_lambda*LAMBDA ...
531 + d(i,j)* a_mu_i*MU ...
532 + db(i,j)*a_mu_ij*MU );
533 varargout{i} = alpha;
534 otherwise
535 error(['No such operator: operator = ' op{i}]);
536 end
412 end 537 end
413 538
414 end 539 end
415 540
416 function N = size(obj) 541 function N = size(obj)
417 N = prod(obj.m); 542 N = obj.dim*prod(obj.m);
418 end 543 end
419 end 544 end
420 end 545 end