Mercurial > repos > public > sbplib
comparison +scheme/Heat2dCurvilinear.m @ 997:78db023a7fe3 feature/getBoundaryOp
Add getBoundaryOperator method to all 2d schemes, except obsolete Wave2dCurve and ElastiCurve, which needs a big makeover.
author | Martin Almquist <malmquist@stanford.edu> |
---|---|
date | Sat, 12 Jan 2019 11:57:50 -0800 |
parents | 08f3ffe63f48 |
children | 8d73fcdb07a5 |
comparison
equal
deleted
inserted
replaced
982:a0b3161e44f3 | 997:78db023a7fe3 |
---|---|
1 classdef Heat2dCurvilinear < scheme.Scheme | 1 classdef Heat2dCurvilinear < scheme.Scheme |
2 | 2 |
3 % Discretizes the Laplacian with variable coefficent, curvilinear, | 3 % Discretizes the Laplacian with variable coefficent, curvilinear, |
4 % in the Heat equation way (i.e., the discretization matrix is not necessarily | 4 % in the Heat equation way (i.e., the discretization matrix is not necessarily |
5 % symmetric) | 5 % symmetric) |
6 % u_t = div * (kappa * grad u ) | 6 % u_t = div * (kappa * grad u ) |
7 % opSet should be cell array of opSets, one per dimension. This | 7 % opSet should be cell array of opSets, one per dimension. This |
8 % is useful if we have periodic BC in one direction. | 8 % is useful if we have periodic BC in one direction. |
9 | 9 |
10 properties | 10 properties |
11 m % Number of points in each direction, possibly a vector | 11 m % Number of points in each direction, possibly a vector |
27 | 27 |
28 H, Hi % Inner products | 28 H, Hi % Inner products |
29 e_l, e_r | 29 e_l, e_r |
30 d1_l, d1_r % Normal derivatives at the boundary | 30 d1_l, d1_r % Normal derivatives at the boundary |
31 alpha % Vector of borrowing constants | 31 alpha % Vector of borrowing constants |
32 | 32 |
33 % Boundary inner products | 33 % Boundary inner products |
34 H_boundary_l, H_boundary_r | 34 H_boundary_l, H_boundary_r |
35 | 35 |
36 % Metric coefficients | 36 % Metric coefficients |
37 b % Cell matrix of size dim x dim | 37 b % Cell matrix of size dim x dim |
38 J, Ji | 38 J, Ji |
39 beta % Cell array of scale factors | 39 beta % Cell array of scale factors |
107 xmax = max(ops{1}.x); | 107 xmax = max(ops{1}.x); |
108 ymax = max(ops{2}.x); | 108 ymax = max(ops{2}.x); |
109 opSetMetric{1} = sbp.D2Variable(m(1), {0, xmax}, order); | 109 opSetMetric{1} = sbp.D2Variable(m(1), {0, xmax}, order); |
110 opSetMetric{2} = sbp.D2Variable(m(2), {0, ymax}, order); | 110 opSetMetric{2} = sbp.D2Variable(m(2), {0, ymax}, order); |
111 D1Metric{1} = kron(opSetMetric{1}.D1, I{2}); | 111 D1Metric{1} = kron(opSetMetric{1}.D1, I{2}); |
112 D1Metric{2} = kron(I{1}, opSetMetric{2}.D1); | 112 D1Metric{2} = kron(I{1}, opSetMetric{2}.D1); |
113 | 113 |
114 x_xi = D1Metric{1}*x; | 114 x_xi = D1Metric{1}*x; |
115 x_eta = D1Metric{2}*x; | 115 x_eta = D1Metric{2}*x; |
116 y_xi = D1Metric{1}*y; | 116 y_xi = D1Metric{1}*y; |
117 y_eta = D1Metric{2}*y; | 117 y_eta = D1Metric{2}*y; |
155 obj.d1_r{2} = kron(I{1},d1_r{2}); | 155 obj.d1_r{2} = kron(I{1},d1_r{2}); |
156 | 156 |
157 % D2 coefficients | 157 % D2 coefficients |
158 kappa_coeff = cell(dim,dim); | 158 kappa_coeff = cell(dim,dim); |
159 for j = 1:dim | 159 for j = 1:dim |
160 obj.D2_kappa{j} = sparse(m_tot,m_tot); | 160 obj.D2_kappa{j} = sparse(m_tot,m_tot); |
161 kappa_coeff{j} = sparse(m_tot,1); | 161 kappa_coeff{j} = sparse(m_tot,1); |
162 for i = 1:dim | 162 for i = 1:dim |
163 kappa_coeff{j} = kappa_coeff{j} + b{i,j}*J*b{i,j}*kappa; | 163 kappa_coeff{j} = kappa_coeff{j} + b{i,j}*J*b{i,j}*kappa; |
164 end | 164 end |
165 end | 165 end |
268 function [closure, penalty] = boundary_condition(obj, boundary, type, symmetric, tuning) | 268 function [closure, penalty] = boundary_condition(obj, boundary, type, symmetric, tuning) |
269 default_arg('type','Neumann'); | 269 default_arg('type','Neumann'); |
270 default_arg('symmetric', false); | 270 default_arg('symmetric', false); |
271 default_arg('tuning',1.2); | 271 default_arg('tuning',1.2); |
272 | 272 |
273 % j is the coordinate direction of the boundary | 273 % nj: outward unit normal component. |
274 % nj: outward unit normal component. | |
275 % nj = -1 for west, south, bottom boundaries | 274 % nj = -1 for west, south, bottom boundaries |
276 % nj = 1 for east, north, top boundaries | 275 % nj = 1 for east, north, top boundaries |
277 [j, nj] = obj.get_boundary_number(boundary); | 276 nj = obj.getBoundarySign(boundary); |
278 switch nj | 277 |
279 case 1 | 278 Hi = obj.Hi; |
280 e = obj.e_r{j}; | 279 [e, flux] = obj.getBoundaryOperator({'e', 'flux'}, boundary); |
281 flux = obj.flux_r{j}; | 280 H_gamma = obj.getBoundaryQuadrature(boundary); |
282 H_gamma = obj.H_boundary_r{j}; | 281 alpha = obj.getBoundaryBorrowing(boundary); |
283 case -1 | |
284 e = obj.e_l{j}; | |
285 flux = obj.flux_l{j}; | |
286 H_gamma = obj.H_boundary_l{j}; | |
287 end | |
288 | 282 |
289 Hi = obj.Hi; | 283 Hi = obj.Hi; |
290 Ji = obj.Ji; | 284 Ji = obj.Ji; |
291 KAPPA = obj.KAPPA; | 285 KAPPA = obj.KAPPA; |
292 kappa_gamma = e'*KAPPA*e; | 286 kappa_gamma = e'*KAPPA*e; |
293 h = obj.h(j); | |
294 alpha = h*obj.alpha(j); | |
295 | 287 |
296 switch type | 288 switch type |
297 | 289 |
298 % Dirichlet boundary condition | 290 % Dirichlet boundary condition |
299 case {'D','d','dirichlet','Dirichlet'} | 291 case {'D','d','dirichlet','Dirichlet'} |
300 | 292 |
301 if ~symmetric | 293 if ~symmetric |
302 closure = -Ji*Hi*flux'*e*H_gamma*(e' ); | 294 closure = -Ji*Hi*flux'*e*H_gamma*(e' ); |
303 penalty = Ji*Hi*flux'*e*H_gamma; | 295 penalty = Ji*Hi*flux'*e*H_gamma; |
304 else | 296 else |
305 closure = Ji*Hi*flux'*e*H_gamma*(e' )... | 297 closure = Ji*Hi*flux'*e*H_gamma*(e' )... |
306 -tuning*2/alpha*Ji*Hi*e*kappa_gamma*H_gamma*(e' ) ; | 298 -tuning*2/alpha*Ji*Hi*e*kappa_gamma*H_gamma*(e' ) ; |
307 penalty = -Ji*Hi*flux'*e*H_gamma ... | 299 penalty = -Ji*Hi*flux'*e*H_gamma ... |
308 +tuning*2/alpha*Ji*Hi*e*kappa_gamma*H_gamma; | 300 +tuning*2/alpha*Ji*Hi*e*kappa_gamma*H_gamma; |
309 end | 301 end |
310 | 302 |
311 % Normal flux boundary condition | 303 % Normal flux boundary condition |
312 case {'N','n','neumann','Neumann'} | 304 case {'N','n','neumann','Neumann'} |
313 closure = -Ji*Hi*e*H_gamma*(e'*flux ); | 305 closure = -Ji*Hi*e*H_gamma*(e'*flux ); |
314 penalty = Ji*Hi*e*H_gamma; | 306 penalty = Ji*Hi*e*H_gamma; |
315 | 307 |
316 % Unknown boundary condition | 308 % Unknown boundary condition |
317 otherwise | 309 otherwise |
318 error('No such boundary condition: type = %s',type); | 310 error('No such boundary condition: type = %s',type); |
319 end | 311 end |
323 % u denotes the solution in the own domain | 315 % u denotes the solution in the own domain |
324 % v denotes the solution in the neighbour domain | 316 % v denotes the solution in the neighbour domain |
325 error('Interface not implemented'); | 317 error('Interface not implemented'); |
326 end | 318 end |
327 | 319 |
328 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. | 320 % Returns the boundary operator op for the boundary specified by the string boundary. |
329 function [j, nj] = get_boundary_number(obj, boundary) | 321 % op -- string or a cell array of strings |
322 % boundary -- string | |
323 function varargout = getBoundaryOperator(obj, op, boundary) | |
324 | |
325 if ~iscell(op) | |
326 op = {op}; | |
327 end | |
328 | |
329 for i = 1:numel(op) | |
330 switch op{i} | |
331 case 'e' | |
332 switch boundary | |
333 case 'w' | |
334 e = obj.e_l{1}; | |
335 case 'e' | |
336 e = obj.e_r{1}; | |
337 case 's' | |
338 e = obj.e_l{2}; | |
339 case 'n' | |
340 e = obj.e_r{2}; | |
341 otherwise | |
342 error('No such boundary: boundary = %s',boundary); | |
343 end | |
344 varargout{i} = e; | |
345 | |
346 case 'd' | |
347 switch boundary | |
348 case 'w' | |
349 d = obj.d1_l{1}; | |
350 case 'e' | |
351 d = obj.d1_r{1}; | |
352 case 's' | |
353 d = obj.d1_l{2}; | |
354 case 'n' | |
355 d = obj.d1_r{2}; | |
356 otherwise | |
357 error('No such boundary: boundary = %s',boundary); | |
358 end | |
359 varargout{i} = d; | |
360 | |
361 case 'flux' | |
362 switch boundary | |
363 case 'w' | |
364 flux = obj.flux_l{1}; | |
365 case 'e' | |
366 flux = obj.flux_r{1}; | |
367 case 's' | |
368 flux = obj.flux_l{2}; | |
369 case 'n' | |
370 flux = obj.flux_r{2}; | |
371 otherwise | |
372 error('No such boundary: boundary = %s',boundary); | |
373 end | |
374 varargout{i} = flux; | |
375 end | |
376 end | |
377 end | |
378 | |
379 % Returns square boundary quadrature matrix, of dimension | |
380 % corresponding to the number of boundary points | |
381 % | |
382 % boundary -- string | |
383 function H_b = getBoundaryQuadrature(obj, boundary) | |
330 | 384 |
331 switch boundary | 385 switch boundary |
332 case {'w','W','west','West', 'e', 'E', 'east', 'East'} | 386 case 'w' |
333 j = 1; | 387 H_b = obj.H_boundary_l{1}; |
334 case {'s','S','south','South', 'n', 'N', 'north', 'North'} | 388 case 'e' |
335 j = 2; | 389 H_b = obj.H_boundary_r{1}; |
390 case 's' | |
391 H_b = obj.H_boundary_l{2}; | |
392 case 'n' | |
393 H_b = obj.H_boundary_r{2}; | |
336 otherwise | 394 otherwise |
337 error('No such boundary: boundary = %s',boundary); | 395 error('No such boundary: boundary = %s',boundary); |
338 end | 396 end |
339 | 397 end |
398 | |
399 % Returns the boundary sign. The right boundary is considered the positive boundary | |
400 % boundary -- string | |
401 function s = getBoundarySign(obj, boundary) | |
340 switch boundary | 402 switch boundary |
341 case {'w','W','west','West','s','S','south','South'} | 403 case {'e','n'} |
342 nj = -1; | 404 s = 1; |
343 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} | 405 case {'w','s'} |
344 nj = 1; | 406 s = -1; |
345 end | |
346 end | |
347 | |
348 % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. | |
349 function [return_op] = get_boundary_operator(obj, op, boundary) | |
350 | |
351 switch boundary | |
352 case {'w','W','west','West', 'e', 'E', 'east', 'East'} | |
353 j = 1; | |
354 case {'s','S','south','South', 'n', 'N', 'north', 'North'} | |
355 j = 2; | |
356 otherwise | 407 otherwise |
357 error('No such boundary: boundary = %s',boundary); | 408 error('No such boundary: boundary = %s',boundary); |
358 end | 409 end |
359 | 410 end |
360 switch op | 411 |
361 case 'e' | 412 % Returns borrowing constant gamma*h |
362 switch boundary | 413 % boundary -- string |
363 case {'w','W','west','West','s','S','south','South'} | 414 function gamm = getBoundaryBorrowing(obj, boundary) |
364 return_op = obj.e_l{j}; | 415 switch boundary |
365 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} | 416 case {'w','e'} |
366 return_op = obj.e_r{j}; | 417 gamm = obj.h(1)*obj.alpha(1); |
367 end | 418 case {'s','n'} |
368 case 'd' | 419 gamm = obj.h(2)*obj.alpha(2); |
369 switch boundary | |
370 case {'w','W','west','West','s','S','south','South'} | |
371 return_op = obj.d1_l{j}; | |
372 case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} | |
373 return_op = obj.d1_r{j}; | |
374 end | |
375 otherwise | 420 otherwise |
376 error(['No such operator: operatr = ' op]); | 421 error('No such boundary: boundary = %s',boundary); |
377 end | 422 end |
378 | |
379 end | 423 end |
380 | 424 |
381 function N = size(obj) | 425 function N = size(obj) |
382 N = prod(obj.m); | 426 N = prod(obj.m); |
383 end | 427 end |