Mercurial > repos > public > sbplib
diff +sbp/D2Nonequidistant.m @ 1325:1b0f2415237f feature/D2_boundary_opt
Add variable coefficient boundary-optimized second derivatives.
author | Vidar Stiernström <vidar.stiernstrom@it.uu.se> |
---|---|
date | Sun, 13 Feb 2022 19:32:34 +0100 |
parents | |
children | 7ab7d42a5b24 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/+sbp/D2Nonequidistant.m Sun Feb 13 19:32:34 2022 +0100 @@ -0,0 +1,97 @@ +classdef D2Nonequidistant < sbp.OpSet + % Implements the boundary optimized variable coefficient + % second derivative. + % + % The boundary closure uses the first and last rows of the + % boundary-optimized D1 operator, i.e. the operators are + % fully compatible. + properties + H % Norm matrix + HI % H^-1 + D1 % SBP operator approximating first derivative + D2 % SBP operator approximating first derivative + DI % Dissipation operator + e_l % Left boundary operator + e_r % Right boundary operator + d1_l % Left boundary first derivative + d1_r % Right boundary first derivative + m % Number of grid points. + h % Step size + x % grid + borrowing % Struct with borrowing limits for different norm matrices + options % Struct holding options used to create the operator + end + + methods + + function obj = D2Nonequidistant(m, lim, order, options) + % m - number of gridpoints + % lim - cell array holding the limits of the domain + % order - order of the operator + % options - struct holding options used to construct the operator + % struct.stencil_width: {'minimal', 'nonminimal', 'wide'} + % minimal: minimal compatible stencil width (default) + % nonminimal: a few additional stencil points compared to minimal + % wide: wide stencil obtained by applying D1 twice + % struct.AD: {'op', 'upwind'} + % 'op': order-preserving AD (preserving interior stencil order) (default) + % 'upwind': upwind AD (order-1 upwind interior stencil) + % struct.variable_coeffs: {true, false} + % true: obj.D2 is a function handle D2(c) returning a matrix + % for coefficient vector c (default) + % false: obj.D2 is a matrix. + default_arg('options', struct); + default_field(options,'stencil_width','minimal'); + default_field(options,'AD','op'); + default_field(options,'variable_coeffs',true); + [x, h] = sbp.grid.accurateBoundaryOptimizedGrid(lim, m, order); + switch order + case 4 + [obj.H, obj.HI, obj.D1, obj.D2, obj.DI] = sbp.implementations.d2_noneq_variable_4(m, h, options); + case 6 + % [obj.H, obj.HI, obj.D1, D2, M, Q, obj.e_l, obj.e_r, obj.d1_l, obj.d1_r] = sbp.implementations.d2_noneq_6(m,h,2); + % obj.D2 = @(c)D2; + [obj.H, obj.HI, obj.D1, obj.D2, obj.DI] = sbp.implementations.d2_noneq_variable_6(m, h, options); + case 8 + % [obj.H, obj.HI, obj.D1, D2, M, Q, obj.e_l, obj.e_r, obj.d1_l, obj.d1_r] = sbp.implementations.d2_noneq_8(m,h,1); + % obj.D2 = @(c)D2; + [obj.H, obj.HI, obj.D1, obj.D2, obj.DI] = sbp.implementations.d2_noneq_variable_8(m, h, options); + case 10 + [obj.H, obj.HI, obj.D1, obj.D2, obj.DI] = sbp.implementations.d2_noneq_variable_10(m, h, options); + case 12 + [obj.H, obj.HI, obj.D1, obj.D2, obj.DI] = sbp.implementations.d2_noneq_variable_12(m, h, options); + otherwise + error('Invalid operator order %d.', order); + end + + if ~options.variable_coeffs + obj.D2 = obj.D2(ones(m,1)); + end + + % Boundary operators + obj.e_l = sparse(m, 1); obj.e_l(1) = 1; + obj.e_r = sparse(m, 1); obj.e_r(m) = 1; + obj.d1_l = (obj.e_l' * obj.D1)'; + obj.d1_r = (obj.e_r' * obj.D1)'; + + % Borrowing coefficients + obj.borrowing.H11 = obj.H(1, 1) / h; % First element in H/h, + obj.borrowing.M.d1 = obj.H(1, 1) / h; % First element in H/h is borrowing also for M + obj.borrowing.R.delta_D = inf; + + % grid data + obj.x = x; + obj.h = h; + obj.m = m; + + % misc + obj.options = options; + end + + function str = string(obj) + str = [class(obj) '_' num2str(obj.order)]; + end + + end + +end