Mercurial > repos > public > sbplib
changeset 1197:433c89bf19e0 feature/rv
Merge with default
author | Vidar Stiernström <vidar.stiernstrom@it.uu.se> |
---|---|
date | Wed, 07 Aug 2019 15:23:42 +0200 |
parents | f6c571d8f22f (current diff) 33c378e508d2 (diff) |
children | 5271c4670733 |
files | +rv/+diffops/constructSymmetricD2.m +scheme/Beam2d.m +scheme/Burgers1d.m +scheme/Burgers2d.m +scheme/TODO.txt +scheme/Utux.m +scheme/Utux2d.m +scheme/Wave2dCurve.m +scheme/error1d.m +scheme/error2d.m +scheme/errorMax.m +scheme/errorRelative.m +scheme/errorSbp.m +scheme/errorVector.m +time/+cdiff/cdiff.m |
diffstat | 42 files changed, 1681 insertions(+), 1408 deletions(-) [+] |
line wrap: on
line diff
diff -r f6c571d8f22f -r 433c89bf19e0 +multiblock/+domain/Line.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/+multiblock/+domain/Line.m Wed Aug 07 15:23:42 2019 +0200 @@ -0,0 +1,153 @@ +classdef Line < multiblock.Definition + properties + + xlims + blockNames % Cell array of block labels + nBlocks + connections % Cell array specifying connections between blocks + boundaryGroups % Structure of boundaryGroups + + end + + + methods + % Creates a divided line + % x is a vector of boundary and interface positions. + % blockNames: cell array of labels. The id is default. + function obj = Line(x,blockNames) + default_arg('blockNames',[]); + + N = length(x)-1; % number of blocks in the x direction. + + if ~issorted(x) + error('The elements of x seem to be in the wrong order'); + end + + % Dimensions of blocks and number of points + blockTi = cell(N,1); + xlims = cell(N,1); + for i = 1:N + xlims{i} = {x(i), x(i+1)}; + end + + % Interface couplings + conn = cell(N,N); + for i = 1:N + conn{i,i+1} = {'r','l'}; + end + + % Block names (id number as default) + if isempty(blockNames) + obj.blockNames = cell(1, N); + for i = 1:N + obj.blockNames{i} = sprintf('%d', i); + end + else + assert(length(blockNames) == N); + obj.blockNames = blockNames; + end + nBlocks = N; + + % Boundary groups + boundaryGroups = struct(); + L = { {1, 'l'} }; + R = { {N, 'r'} }; + boundaryGroups.L = multiblock.BoundaryGroup(L); + boundaryGroups.R = multiblock.BoundaryGroup(R); + boundaryGroups.all = multiblock.BoundaryGroup([L,R]); + + obj.connections = conn; + obj.nBlocks = nBlocks; + obj.boundaryGroups = boundaryGroups; + obj.xlims = xlims; + + end + + + % Returns a multiblock.Grid given some parameters + % ms: cell array of m values + % For same m in every block, just input one scalar. + function g = getGrid(obj, ms, varargin) + + default_arg('ms',21) + + % Extend ms if input is a single scalar + if (numel(ms) == 1) && ~iscell(ms) + m = ms; + ms = cell(1,obj.nBlocks); + for i = 1:obj.nBlocks + ms{i} = m; + end + end + + grids = cell(1, obj.nBlocks); + for i = 1:obj.nBlocks + grids{i} = grid.equidistant(ms{i}, obj.xlims{i}); + end + + g = multiblock.Grid(grids, obj.connections, obj.boundaryGroups); + end + + % Returns a multiblock.Grid given some parameters + % ms: cell array of m values + % For same m in every block, just input one scalar. + function g = getStaggeredGrid(obj, ms, varargin) + + default_arg('ms',21) + + % Extend ms if input is a single scalar + if (numel(ms) == 1) && ~iscell(ms) + m = ms; + ms = cell(1,obj.nBlocks); + for i = 1:obj.nBlocks + ms{i} = m; + end + end + + grids = cell(1, obj.nBlocks); + for i = 1:obj.nBlocks + [g_primal, g_dual] = grid.primalDual1D(ms{i}, obj.xlims{i}); + grids{i} = grid.Staggered1d(g_primal, g_dual); + end + + g = multiblock.Grid(grids, obj.connections, obj.boundaryGroups); + end + + % label is the type of label used for plotting, + % default is block name, 'id' show the index for each block. + function show(obj, label) + default_arg('label', 'name') + + m = 10; + figure + for i = 1:obj.nBlocks + x = linspace(obj.xlims{i}{1}, obj.xlims{i}{2}, m); + y = 0*x + 0.05* ( (-1)^i + 1 ) ; + plot(x,y,'+'); + hold on + end + hold off + + switch label + case 'name' + labels = obj.blockNames; + case 'id' + labels = {}; + for i = 1:obj.nBlocks + labels{i} = num2str(i); + end + otherwise + axis equal + return + end + + legend(labels) + axis equal + end + + % Returns the grid size of each block in a cell array + % The input parameters are determined by the subclass + function ms = getGridSizes(obj, varargin) + end + end +end
diff -r f6c571d8f22f -r 433c89bf19e0 +multiblock/DiffOp.m --- a/+multiblock/DiffOp.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+multiblock/DiffOp.m Wed Aug 07 15:23:42 2019 +0200 @@ -129,11 +129,11 @@ % Get a boundary operator specified by opName for the given boundary/BoundaryGroup function op = getBoundaryOperator(obj, opName, boundary) + switch class(boundary) case 'cell' - localOpName = [opName '_' boundary{2}]; blockId = boundary{1}; - localOp = obj.diffOps{blockId}.(localOpName); + localOp = obj.diffOps{blockId}.getBoundaryOperator(opName, boundary{2}); div = {obj.blockmatrixDiv{1}, size(localOp,2)}; blockOp = blockmatrix.zero(div); @@ -151,13 +151,10 @@ end function op = getBoundaryQuadrature(obj, boundary) - opName = 'H'; switch class(boundary) case 'cell' - localOpName = [opName '_' boundary{2}]; blockId = boundary{1}; - op = obj.diffOps{blockId}.(localOpName); - + op = obj.diffOps{blockId}.getBoundaryQuadrature(boundary{2}); return case 'multiblock.BoundaryGroup' N = length(boundary);
diff -r f6c571d8f22f -r 433c89bf19e0 +multiblock/LaplaceSquared.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/+multiblock/LaplaceSquared.m Wed Aug 07 15:23:42 2019 +0200 @@ -0,0 +1,105 @@ +classdef LaplaceSquared < scheme.Scheme + properties + grid + order + laplaceDiffOp + + D + H + Hi + + a,b + end + + methods + % Discretisation of a*nabla*b*nabla + function obj = LaplaceSquared(g, order, a, b, opGen) + default_arg('order', 4); + default_arg('a', 1); + default_arg('b', 1); + default_arg('opGen', @sbp.D4Variable); + + if isscalar(a) + a = grid.evalOn(g, a); + end + + if isscalar(b) + b = grid.evalOn(g, b); + end + + obj.grid = g; + obj.order = order; + obj.a = a; + obj.b = b; + + obj.laplaceDiffOp = multiblock.Laplace(g, order, 1, 1, opGen); + + obj.H = obj.laplaceDiffOp.H; + obj.Hi = spdiag(1./diag(obj.H)); + + A = spdiag(a); + B = spdiag(b); + + D_laplace = obj.laplaceDiffOp.D; + obj.D = A*D_laplace*B*D_laplace; + end + + function s = size(obj) + s = size(obj.laplaceDiffOp); + end + + function op = getBoundaryOperator(obj, opName, boundary) + switch opName + case 'e' + op = getBoundaryOperator(obj.laplaceDiffOp, 'e', boundary); + case 'd1' + op = getBoundaryOperator(obj.laplaceDiffOp, 'd', boundary); + case 'd2' + e = getBoundaryOperator(obj.laplaceDiffOp, 'e', boundary); + op = (e'*obj.laplaceDiffOp.D)'; + case 'd3' + d1 = getBoundaryOperator(obj.laplaceDiffOp, 'd', boundary); + op = (d1'*spdiag(obj.b)*obj.laplaceDiffOp.D)'; + end + end + + function op = getBoundaryQuadrature(obj, boundary) + op = getBoundaryQuadrature(obj.laplaceDiffOp, boundary); + end + + function [closure, penalty] = boundary_condition(obj,boundary,type) % TODO: Change name to boundaryCondition + switch type + case 'e' + error('Bc of type ''e'' not implemented') + case 'd1' + error('Bc of type ''d1'' not implemented') + case 'd2' + e = obj.getBoundaryOperator('e', boundary); + d1 = obj.getBoundaryOperator('d1', boundary); + d2 = obj.getBoundaryOperator('d2', boundary); + H_b = obj.getBoundaryQuadrature(boundary); + + A = spdiag(obj.a); + B_b = spdiag(e'*obj.b); + + tau = obj.Hi*A*d1*B_b*H_b; + closure = tau*d2'; + penalty = -tau; + case 'd3' + e = obj.getBoundaryOperator('e', boundary); + d3 = obj.getBoundaryOperator('d3', boundary); + H_b = obj.getBoundaryQuadrature(boundary); + + A = spdiag(obj.a); + + tau = -obj.Hi*A*e*H_b; + closure = tau*d3'; + penalty = -tau; + end + end + + function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary) + error('Not implemented') + end + end +end
diff -r f6c571d8f22f -r 433c89bf19e0 +parametrization/Curve.m --- a/+parametrization/Curve.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+parametrization/Curve.m Wed Aug 07 15:23:42 2019 +0200 @@ -103,7 +103,10 @@ % Construct arcLength function using splines tvec = linspace(0,1,N); arcVec = obj.arcLength(0,tvec); - tFunc = spline(arcVec,tvec); % t as a function of arcLength + + % t as a function of arcLength. Monotonicity-preserving cubic splines. + tFunc = @(arcLen) pchip(arcVec,tvec,arcLen); + L = obj.arcLength(0,1); arcPar = @(s) tFunc(s*L); @@ -349,8 +352,6 @@ end end - - function g_norm = normalize(g0) g1 = g0(1,:); g2 = g0(2,:);
diff -r f6c571d8f22f -r 433c89bf19e0 +parametrization/dataSpline.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/+parametrization/dataSpline.m Wed Aug 07 15:23:42 2019 +0200 @@ -0,0 +1,19 @@ +% dataSpline calculates a Curve through the points f_i using cubic spline interpolation. +% The spline curve is parametrized with the arc length parametrization +% to facilitate better grids. +% +% f - m x D matrix of m points in D dimensions +function C = dataSpline(f) + m = size(f, 1); + + t = linspace(0,1,m); + + pp_g = spapi(4, t, f'); + pp_gp = fnder(pp_g); + + g = @(t) fnval(pp_g, t); + gp = @(t) fnval(pp_gp, t); + + C = parametrization.Curve(g, gp); + C = C.arcLengthParametrization(); +end
diff -r f6c571d8f22f -r 433c89bf19e0 +rv/+diffops/constructSymmetricD2.m --- a/+rv/+diffops/constructSymmetricD2.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+rv/+diffops/constructSymmetricD2.m Wed Aug 07 15:23:42 2019 +0200 @@ -20,9 +20,10 @@ M = Dm - Hi*B; D2 = @(Viscosity) M*Viscosity*Dp; else - % TODO: Fix closure for D2Variable % TODO: Fix Viscosity not being vector - D2 = @(Viscosity)ops{1}.D2(diag(Viscosity)); + d1_r = ops{1}.d1_r'; + d1_l = ops{1}.d1_l'; + D2 = @(Viscosity)ops{1}.D2(diag(Viscosity)) + Hi*(Viscosity(1,1)*e_l*d1_l - e_r*Viscosity(end,end)*d1_r); end case 2 % TODO:
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Beam.m --- a/+scheme/Beam.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Beam.m Wed Aug 07 15:23:42 2019 +0200 @@ -86,7 +86,11 @@ function [closure, penalty] = boundary_condition(obj,boundary,type) default_arg('type','dn'); - [e, d1, d2, d3, s] = obj.get_boundary_ops(boundary); + e = obj.getBoundaryOperator('e', boundary); + d1 = obj.getBoundaryOperator('d1', boundary); + d2 = obj.getBoundaryOperator('d2', boundary); + d3 = obj.getBoundaryOperator('d3', boundary); + s = obj.getBoundarySign(boundary); gamm = obj.gamm; delt = obj.delt; @@ -124,7 +128,7 @@ closure = obj.Hi*(tau*d2' + sig*d3'); penalty{1} = -obj.Hi*tau; - penalty{1} = -obj.Hi*sig; + penalty{2} = -obj.Hi*sig; case 'e' alpha = obj.alpha; @@ -173,14 +177,21 @@ function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary, type) % u denotes the solution in the own domain % v denotes the solution in the neighbour domain - [e_u,d1_u,d2_u,d3_u,s_u] = obj.get_boundary_ops(boundary); - [e_v,d1_v,d2_v,d3_v,s_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); + e_u = obj.getBoundaryOperator('e', boundary); + d1_u = obj.getBoundaryOperator('d1', boundary); + d2_u = obj.getBoundaryOperator('d2', boundary); + d3_u = obj.getBoundaryOperator('d3', boundary); + s_u = obj.getBoundarySign(boundary); + e_v = neighbour_scheme.getBoundaryOperator('e', neighbour_boundary); + d1_v = neighbour_scheme.getBoundaryOperator('d1', neighbour_boundary); + d2_v = neighbour_scheme.getBoundaryOperator('d2', neighbour_boundary); + d3_v = neighbour_scheme.getBoundaryOperator('d3', neighbour_boundary); + s_v = neighbour_scheme.getBoundarySign(neighbour_boundary); alpha_u = obj.alpha; alpha_v = neighbour_scheme.alpha; - switch boundary case 'l' interface_opt = obj.opt.interface_l; @@ -234,24 +245,37 @@ penalty = -obj.Hi*(tau*e_v' + sig*d1_v' + phi*alpha_v*d2_v' + psi*alpha_v*d3_v'); end - % Returns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e, d1, d2, d3, s] = get_boundary_ops(obj,boundary) + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string + % boundary -- string + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e', 'd1', 'd2', 'd3'}) + assertIsMember(boundary, {'l', 'r'}) + + o = obj.([op, '_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + % Note: for 1d diffOps, the boundary quadrature is the scalar 1. + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + + H_b = 1; + end + + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + switch boundary - case 'l' - e = obj.e_l; - d1 = obj.d1_l; - d2 = obj.d2_l; - d3 = obj.d3_l; + case {'r'} + s = 1; + case {'l'} s = -1; - case 'r' - e = obj.e_r; - d1 = obj.d1_r; - d2 = obj.d2_r; - d3 = obj.d3_r; - s = 1; - otherwise - error('No such boundary: boundary = %s',boundary); end end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Beam2d.m --- a/+scheme/Beam2d.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,245 +0,0 @@ -classdef Beam2d < scheme.Scheme - properties - grid - order % Order accuracy for the approximation - - D % non-stabalized scheme operator - M % Derivative norm - alpha - - H % Discrete norm - Hi - H_x, H_y % Norms in the x and y directions - Hx,Hy % Kroneckerd norms. 1'*Hx*v corresponds to integration in the x dir. - Hi_x, Hi_y - Hix, Hiy - e_w, e_e, e_s, e_n - d1_w, d1_e, d1_s, d1_n - d2_w, d2_e, d2_s, d2_n - d3_w, d3_e, d3_s, d3_n - gamm_x, gamm_y - delt_x, delt_y - end - - methods - function obj = Beam2d(m,lim,order,alpha,opsGen) - default_arg('alpha',1); - default_arg('opsGen',@sbp.Higher); - - if ~isa(grid, 'grid.Cartesian') || grid.D() ~= 2 - error('Grid must be 2d cartesian'); - end - - obj.grid = grid; - obj.alpha = alpha; - obj.order = order; - - m_x = grid.m(1); - m_y = grid.m(2); - - h = grid.scaling(); - h_x = h(1); - h_y = h(2); - - ops_x = opsGen(m_x,h_x,order); - ops_y = opsGen(m_y,h_y,order); - - I_x = speye(m_x); - I_y = speye(m_y); - - D4_x = sparse(ops_x.derivatives.D4); - H_x = sparse(ops_x.norms.H); - Hi_x = sparse(ops_x.norms.HI); - e_l_x = sparse(ops_x.boundary.e_1); - e_r_x = sparse(ops_x.boundary.e_m); - d1_l_x = sparse(ops_x.boundary.S_1); - d1_r_x = sparse(ops_x.boundary.S_m); - d2_l_x = sparse(ops_x.boundary.S2_1); - d2_r_x = sparse(ops_x.boundary.S2_m); - d3_l_x = sparse(ops_x.boundary.S3_1); - d3_r_x = sparse(ops_x.boundary.S3_m); - - D4_y = sparse(ops_y.derivatives.D4); - H_y = sparse(ops_y.norms.H); - Hi_y = sparse(ops_y.norms.HI); - e_l_y = sparse(ops_y.boundary.e_1); - e_r_y = sparse(ops_y.boundary.e_m); - d1_l_y = sparse(ops_y.boundary.S_1); - d1_r_y = sparse(ops_y.boundary.S_m); - d2_l_y = sparse(ops_y.boundary.S2_1); - d2_r_y = sparse(ops_y.boundary.S2_m); - d3_l_y = sparse(ops_y.boundary.S3_1); - d3_r_y = sparse(ops_y.boundary.S3_m); - - - D4 = kr(D4_x, I_y) + kr(I_x, D4_y); - - % Norms - obj.H = kr(H_x,H_y); - obj.Hx = kr(H_x,I_x); - obj.Hy = kr(I_x,H_y); - obj.Hix = kr(Hi_x,I_y); - obj.Hiy = kr(I_x,Hi_y); - obj.Hi = kr(Hi_x,Hi_y); - - % Boundary operators - obj.e_w = kr(e_l_x,I_y); - obj.e_e = kr(e_r_x,I_y); - obj.e_s = kr(I_x,e_l_y); - obj.e_n = kr(I_x,e_r_y); - obj.d1_w = kr(d1_l_x,I_y); - obj.d1_e = kr(d1_r_x,I_y); - obj.d1_s = kr(I_x,d1_l_y); - obj.d1_n = kr(I_x,d1_r_y); - obj.d2_w = kr(d2_l_x,I_y); - obj.d2_e = kr(d2_r_x,I_y); - obj.d2_s = kr(I_x,d2_l_y); - obj.d2_n = kr(I_x,d2_r_y); - obj.d3_w = kr(d3_l_x,I_y); - obj.d3_e = kr(d3_r_x,I_y); - obj.d3_s = kr(I_x,d3_l_y); - obj.d3_n = kr(I_x,d3_r_y); - - obj.D = alpha*D4; - - obj.gamm_x = h_x*ops_x.borrowing.N.S2/2; - obj.delt_x = h_x^3*ops_x.borrowing.N.S3/2; - - obj.gamm_y = h_y*ops_y.borrowing.N.S2/2; - obj.delt_y = h_y^3*ops_y.borrowing.N.S3/2; - end - - - % Closure functions return the opertors applied to the own doamin to close the boundary - % Penalty functions return the opertors to force the solution. In the case of an interface it returns the operator applied to the other doamin. - % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'. - % type is a string specifying the type of boundary condition if there are several. - % data is a function returning the data that should be applied at the boundary. - % neighbour_scheme is an instance of Scheme that should be interfaced to. - % neighbour_boundary is a string specifying which boundary to interface to. - function [closure, penalty_e,penalty_d] = boundary_condition(obj,boundary,type,data) - default_arg('type','dn'); - default_arg('data',0); - - [e,d1,d2,d3,s,gamm,delt,halfnorm_inv] = obj.get_boundary_ops(boundary); - - switch type - % Dirichlet-neumann boundary condition - case {'dn'} - alpha = obj.alpha; - - % tau1 < -alpha^2/gamma - tuning = 1.1; - - tau1 = tuning * alpha/delt; - tau4 = s*alpha; - - sig2 = tuning * alpha/gamm; - sig3 = -s*alpha; - - tau = tau1*e+tau4*d3; - sig = sig2*d1+sig3*d2; - - closure = halfnorm_inv*(tau*e' + sig*d1'); - - pp_e = halfnorm_inv*tau; - pp_d = halfnorm_inv*sig; - switch class(data) - case 'double' - penalty_e = pp_e*data; - penalty_d = pp_d*data; - case 'function_handle' - penalty_e = @(t)pp_e*data(t); - penalty_d = @(t)pp_d*data(t); - otherwise - error('Wierd data argument!') - end - - % Unknown, boundary condition - otherwise - error('No such boundary condition: type = %s',type); - end - end - - function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary, type) - % u denotes the solution in the own domain - % v denotes the solution in the neighbour domain - [e_u,d1_u,d2_u,d3_u,s_u,gamm_u,delt_u, halfnorm_inv] = obj.get_boundary_ops(boundary); - [e_v,d1_v,d2_v,d3_v,s_v,gamm_v,delt_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); - - tuning = 2; - - alpha_u = obj.alpha; - alpha_v = neighbour_scheme.alpha; - - tau1 = ((alpha_u/2)/delt_u + (alpha_v/2)/delt_v)/2*tuning; - % tau1 = (alpha_u/2 + alpha_v/2)/(2*delt_u)*tuning; - tau4 = s_u*alpha_u/2; - - sig2 = ((alpha_u/2)/gamm_u + (alpha_v/2)/gamm_v)/2*tuning; - sig3 = -s_u*alpha_u/2; - - phi2 = s_u*1/2; - - psi1 = -s_u*1/2; - - tau = tau1*e_u + tau4*d3_u; - sig = sig2*d1_u + sig3*d2_u ; - phi = phi2*d1_u ; - psi = psi1*e_u ; - - closure = halfnorm_inv*(tau*e_u' + sig*d1_u' + phi*alpha_u*d2_u' + psi*alpha_u*d3_u'); - penalty = -halfnorm_inv*(tau*e_v' + sig*d1_v' + phi*alpha_v*d2_v' + psi*alpha_v*d3_v'); - end - - % Ruturns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e,d1,d2,d3,s,gamm, delt, halfnorm_inv] = get_boundary_ops(obj,boundary) - switch boundary - case 'w' - e = obj.e_w; - d1 = obj.d1_w; - d2 = obj.d2_w; - d3 = obj.d3_w; - s = -1; - gamm = obj.gamm_x; - delt = obj.delt_x; - halfnorm_inv = obj.Hix; - case 'e' - e = obj.e_e; - d1 = obj.d1_e; - d2 = obj.d2_e; - d3 = obj.d3_e; - s = 1; - gamm = obj.gamm_x; - delt = obj.delt_x; - halfnorm_inv = obj.Hix; - case 's' - e = obj.e_s; - d1 = obj.d1_s; - d2 = obj.d2_s; - d3 = obj.d3_s; - s = -1; - gamm = obj.gamm_y; - delt = obj.delt_y; - halfnorm_inv = obj.Hiy; - case 'n' - e = obj.e_n; - d1 = obj.d1_n; - d2 = obj.d2_n; - d3 = obj.d3_n; - s = 1; - gamm = obj.gamm_y; - delt = obj.delt_y; - halfnorm_inv = obj.Hiy; - otherwise - error('No such boundary: boundary = %s',boundary); - end - end - - function N = size(obj) - N = prod(obj.m); - end - - end -end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Burgers1d.m --- a/+scheme/Burgers1d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Burgers1d.m Wed Aug 07 15:23:42 2019 +0200 @@ -68,7 +68,9 @@ % type is a string specifying the type of boundary condition if there are several. function [closure, penalty] = boundary_condition(obj, boundary, type) default_arg('type','dirichlet'); - [e, index, s] = obj.get_boundary_ops(boundary); + s = obj.getBoundarySign(boundary); + e = obj.getBoundaryOperator('e', boundary); + index = obj.getBoundaryIndex(boundary); switch type % Stable dirchlet-like boundary conditions (u+-abs(u))*u/3 % with +- at left/right boundaries @@ -77,8 +79,8 @@ % closure = @(v) obj.Hi*tau*(((v(index)-s*abs(v(index)))/3)*v(index)); % penalty = -obj.Hi*tau; - magnitude = 2/3; - tau = @(v) s*magnitude*obj.Hi*e*(v(index)-s*abs(v(index)))/2; + penalty_parameter = 1/3; + tau = @(v) s*penalty_parameter*obj.Hi*e*(v(index)-s*abs(v(index)))/2; closure = @(v) tau(v)*v(index); penalty = @(v) -tau(v); otherwise @@ -86,20 +88,49 @@ end end - % Returns the boundary ops, boundary index and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e, index, s] = get_boundary_ops(obj,boundary) + + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + switch boundary - case {'l','L','left','Left'} - e = obj.e_l; + case {'r'} + s = 1; + case {'l'} + s = -1; + end + end + + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string + % boundary -- string + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e'}) + assertIsMember(boundary, {'l', 'r'}) + + o = obj.([op, '_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + % Note: for 1d diffOps, the boundary quadrature is the scalar 1. + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + H_b = 1; + end + + % Returns the boundary index. The right boundary has the last index + % boundary -- string + function index = getBoundaryIndex(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + switch boundary + case {'r'} + index = length(obj.e_r); + case {'l'} index = 1; - s = -1; - case {'r','R','right','Right'} - e = obj.e_r; - index = length(e); - s = 1; - otherwise - error('No such boundary: boundary = %s',boundary); end end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Burgers2d.m --- a/+scheme/Burgers2d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Burgers2d.m Wed Aug 07 15:23:42 2019 +0200 @@ -101,17 +101,17 @@ % type is a string specifying the type of boundary condition if there are several. function [closure, penalty] = boundary_condition(obj,boundary,type) default_arg('type','dirichlet'); - [e, H_b, index, s] = obj.get_boundary_ops(boundary); + s = obj.getBoundarySign(boundary); + e = obj.getBoundaryOperator('e', boundary); + indices = obj.getBoundaryIndices(boundary); + H_1d = obj.getOneDirectionalNorm(boundary); switch type - % Stable dirchlet-like boundary conditions (u+-abs(u))*u/3 - % with +- at left/right boundaries in each coordinate direction case {'D', 'd', 'dirichlet', 'Dirichlet'} - - magnitude = 1/3; - Tau = s*magnitude*obj.Hi*e*H_b/2; - m = length(index); - tau = @(v) Tau*spdiags((v(index)-s*abs(v(index))),0,m,m); - closure = @(v) Tau*((v(index)-s*abs(v(index))).*v(index)); + penalty_parameter = 1/3; + Tau = s*penalty_parameter*obj.Hi*e*H_1d/2; + m = obj.grid.m; + tau = @(v) Tau*spdiags((v(indices)-s*abs(v(indices))),0,m(1),m(2)); + closure = @(v) Tau*((v(indices)-s*abs(v(indices))).*v(indices)); penalty = @(v) -tau(v); otherwise error('No such boundary condition: type = %s',type); @@ -120,33 +120,66 @@ end - % Ruturns the boundary ops, half-norm, boundary indices and sign for the boundary specified by the string boundary. - % The right boundary for each coordinate direction is considered the positive boundary - function [e, H_b, index, s] = get_boundary_ops(obj, boundary) - ind = grid.funcToMatrix(obj.grid, 1:obj.grid.N()); + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) switch boundary - case {'w', 'W', 'west', 'West'} - e = obj.e_w; - H_b = obj.H_y; - index = ind(1,:); + case {'e','n'} + s = 1; + case {'w','s'} s = -1; - case {'e', 'E', 'east', 'East'} - e = obj.e_e; - H_b = obj.H_y; - index = ind(end,:); - s = 1; - case {'s', 'S', 'south', 'South'} - e = obj.e_s; - H_b = obj.H_x; - index = ind(:,1); - s = -1; - case {'n', 'N', 'north', 'North'} - e = obj.e_n; - H_b = obj.H_x; - index = ind(:,end); - s = 1; - otherwise - error('No such boundary: boundary = %s',boundary); + end + end + + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string + % boundary -- string + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e'}) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + o = obj.([op, '_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + H_b = obj.(['H_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_1d = getOneDirectionalNorm(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + switch boundary + case {'w','e'} + H_1d = obj.H_y; + case {'s','n'} + H_1d = obj.H_x; + end + end + + % Returns the indices of the boundary points in the grid matrix + % boundary -- string + function I = getBoundaryIndices(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + ind = grid.funcToMatrix(obj.grid, 1:prod(obj.grid.m)); + switch boundary + case 'w' + I = ind(1,:); + case 'e' + I = ind(end,:); + case 's' + I = ind(:,1)'; + case 'n' + I = ind(:,end)'; end end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Elastic2dCurvilinear.m --- a/+scheme/Elastic2dCurvilinear.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Elastic2dCurvilinear.m Wed Aug 07 15:23:42 2019 +0200 @@ -3,12 +3,12 @@ % Discretizes the elastic wave equation in curvilinear coordinates. % % Untransformed equation: -% rho u_{i,tt} = di lambda dj u_j + dj mu di u_j + dj mu dj u_i +% rho u_{i,tt} = di lambda dj u_j + dj mu di u_j + dj mu dj u_i % % Transformed equation: -% J*rho u_{i,tt} = dk J b_ik lambda b_jl dl u_j -% + dk J b_jk mu b_il dl u_j -% + dk J b_jk mu b_jl dl u_i +% J*rho u_{i,tt} = dk J b_ik lambda b_jl dl u_j +% + dk J b_jk mu b_il dl u_j +% + dk J b_jk mu b_jl dl u_i % opSet should be cell array of opSets, one per dimension. This % is useful if we have periodic BC in one direction. @@ -49,7 +49,7 @@ e_l, e_r d1_l, d1_r % Normal derivatives at the boundary E % E{i}^T picks out component i - + H_boundary_l, H_boundary_r % Boundary inner products % Kroneckered norms and coefficients @@ -145,7 +145,7 @@ opSetMetric{1} = sbp.D2Variable(m(1), {0, xmax}, order); opSetMetric{2} = sbp.D2Variable(m(2), {0, ymax}, order); D1Metric{1} = kron(opSetMetric{1}.D1, I{2}); - D1Metric{2} = kron(I{1}, opSetMetric{2}.D1); + D1Metric{2} = kron(I{1}, opSetMetric{2}.D1); x_xi = D1Metric{1}*x; x_eta = D1Metric{2}*x; @@ -327,12 +327,12 @@ for m = 1:dim for l = 1:dim - T_l{j}{i,k} = T_l{j}{i,k} + ... + T_l{j}{i,k} = T_l{j}{i,k} + ... -d(k,l)* J*b{i,j}*b{k,m}*LAMBDA*(d(m,j)*e_l{m}*d1_l{m}' + db(m,j)*D1{m}) ... -d(k,l)* J*b{k,j}*b{i,m}*MU*(d(m,j)*e_l{m}*d1_l{m}' + db(m,j)*D1{m}) ... -d(i,k)* J*b{l,j}*b{l,m}*MU*(d(m,j)*e_l{m}*d1_l{m}' + db(m,j)*D1{m}); - T_r{j}{i,k} = T_r{j}{i,k} + ... + T_r{j}{i,k} = T_r{j}{i,k} + ... d(k,l)* J*b{i,j}*b{k,m}*LAMBDA*(d(m,j)*e_r{m}*d1_r{m}' + db(m,j)*D1{m}) + ... d(k,l)* J*b{k,j}*b{i,m}*MU*(d(m,j)*e_r{m}*d1_r{m}' + db(m,j)*D1{m}) + ... d(i,k)* J*b{l,j}*b{l,m}*MU*(d(m,j)*e_r{m}*d1_r{m}' + db(m,j)*D1{m}); @@ -340,7 +340,7 @@ end T_l{j}{i,k} = inv(beta{j})*T_l{j}{i,k}; - T_r{j}{i,k} = inv(beta{j})*T_r{j}{i,k}; + T_r{j}{i,k} = inv(beta{j})*T_r{j}{i,k}; tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}'; tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}'; @@ -387,7 +387,7 @@ % j is the coordinate direction of the boundary j = obj.get_boundary_number(boundary); - [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); + [e, T, tau, H_gamma] = obj.getBoundaryOperator({'e','T','tau','H'}, boundary); E = obj.E; Hi = obj.Hi; @@ -423,20 +423,20 @@ db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ... + d(i,j)* a_mu_i*MU ... - + db(i,j)*a_mu_ij*MU ); + + db(i,j)*a_mu_ij*MU ); % Loop over components that Dirichlet penalties end up on for i = 1:dim C = T{k,i}; A = -d(i,k)*alpha(i,j); B = A + C; - closure = closure + E{i}*RHOi*Hi*Ji*B'*e*H_gamma*(e'*E{k}' ); + closure = closure + E{i}*RHOi*Hi*Ji*B'*e*H_gamma*(e'*E{k}' ); penalty = penalty - E{i}*RHOi*Hi*Ji*B'*e*H_gamma; - end + end % Free boundary condition case {'F','f','Free','free','traction','Traction','t','T'} - closure = closure - E{k}*RHOi*Ji*Hi*e*H_gamma* (e'*tau{k} ); + closure = closure - E{k}*RHOi*Ji*Hi*e*H_gamma* (e'*tau{k} ); penalty = penalty + E{k}*RHOi*Ji*Hi*e*H_gamma; % Unknown boundary condition @@ -457,14 +457,14 @@ j_v = neighbour_scheme.get_boundary_number(neighbour_boundary); % Get boundary operators - [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); - [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary); + [e, T, tau, H_gamma] = obj.getBoundaryOperator({'e','T','tau','H'}, boundary); + [e_v, tau_v] = neighbour_scheme.getBoundaryOperator({'e','tau'}, neighbour_boundary); % Operators and quantities that correspond to the own domain only Hi = obj.Hi; RHOi = obj.RHOi; dim = obj.dim; - + %--- Other operators ---- m_tot_u = obj.grid.N(); E = obj.E; @@ -480,7 +480,7 @@ lambda_v = e_v'*LAMBDA_v*e_v; mu_v = e_v'*MU_v*e_v; %------------------------- - + % Borrowing constants phi_u = obj.phi{j}; h_u = obj.h(j); @@ -493,7 +493,7 @@ gamma_v = neighbour_scheme.gamma{j_v}; % E > sum_i 1/(2*alpha_ij)*(tau_i)^2 - function [alpha_ii, alpha_ij] = computeAlpha(phi,h,h11,gamma,lambda,mu) + function [alpha_ii, alpha_ij] = computeAlpha(phi,h,h11,gamma,lambda,mu) th1 = h11/(2*dim); th2 = h11*phi/2; th3 = h*gamma; @@ -505,7 +505,7 @@ end [alpha_ii_u, alpha_ij_u] = computeAlpha(phi_u,h_u,h11_u,gamma_u,lambda_u,mu_u); - [alpha_ii_v, alpha_ij_v] = computeAlpha(phi_v,h_v,h11_v,gamma_v,lambda_v,mu_v); + [alpha_ii_v, alpha_ij_v] = computeAlpha(phi_v,h_v,h11_v,gamma_v,lambda_v,mu_v); sigma_ii = tuning*(alpha_ii_u + alpha_ii_v)/4; sigma_ij = tuning*(alpha_ij_u + alpha_ij_v)/4; @@ -527,9 +527,9 @@ % Loop over components that we have interface conditions on for k = 1:dim - closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}'; - penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}'; - end + closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}'; + penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}'; + end end end @@ -555,7 +555,7 @@ % Returns the boundary operator op for the boundary specified by the string boundary. % op: may be a cell array of strings - function [varargout] = get_boundary_operator(obj, op, boundary) + function [varargout] = getBoundaryOperator(obj, op, boundary) switch boundary case {'w','W','west','West', 'e', 'E', 'east', 'East'} @@ -587,7 +587,7 @@ varargout{i} = obj.d1_r{j}; end case 'H' - switch boundary + switch boundary case {'w','W','west','West','s','S','south','South'} varargout{i} = obj.H_boundary_l{j}; case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} @@ -606,7 +606,7 @@ varargout{i} = obj.tau_l{j}; case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} varargout{i} = obj.tau_r{j}; - end + end otherwise error(['No such operator: operator = ' op{i}]); end @@ -614,6 +614,27 @@ end + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'w'} + H = H_boundary_l{1}; + case 'e' + H = H_boundary_r{1}; + case 's' + H = H_boundary_l{2}; + case 'n' + H = H_boundary_r{2}; + end + I_dim = speye(obj.dim, obj.dim); + H = kron(H, I_dim); + end + function N = size(obj) N = obj.dim*prod(obj.m); end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Elastic2dVariable.m --- a/+scheme/Elastic2dVariable.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Elastic2dVariable.m Wed Aug 07 15:23:42 2019 +0200 @@ -30,18 +30,10 @@ T_l, T_r tau_l, tau_r - H, Hi % Inner products - - phi % Borrowing constant for (d1 - e^T*D1) from R - gamma % Borrowing constant for d1 from M - H11 % First element of H + H, Hi, H_1D % Inner products + e_l, e_r - % Borrowing from H, M, and R - thH - thM - thR - e_l, e_r d1_l, d1_r % Normal derivatives at the boundary E % E{i}^T picks out component i @@ -50,22 +42,38 @@ % Kroneckered norms and coefficients RHOi_kron Hi_kron + + % Borrowing constants of the form gamma*h, where gamma is a dimensionless constant. + theta_R % Borrowing (d1- D1)^2 from R + theta_H % First entry in norm matrix + theta_M % Borrowing d1^2 from M. + + % Structures used for adjoint optimization + B end methods - function obj = Elastic2dVariable(g ,order, lambda_fun, mu_fun, rho_fun, opSet) + % The coefficients can either be function handles or grid functions + function obj = Elastic2dVariable(g ,order, lambda, mu, rho, opSet) default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable}); - default_arg('lambda_fun', @(x,y) 0*x+1); - default_arg('mu_fun', @(x,y) 0*x+1); - default_arg('rho_fun', @(x,y) 0*x+1); + default_arg('lambda', @(x,y) 0*x+1); + default_arg('mu', @(x,y) 0*x+1); + default_arg('rho', @(x,y) 0*x+1); dim = 2; assert(isa(g, 'grid.Cartesian')) - lambda = grid.evalOn(g, lambda_fun); - mu = grid.evalOn(g, mu_fun); - rho = grid.evalOn(g, rho_fun); + if isa(lambda, 'function_handle') + lambda = grid.evalOn(g, lambda); + end + if isa(mu, 'function_handle') + mu = grid.evalOn(g, mu); + end + if isa(rho, 'function_handle') + rho = grid.evalOn(g, rho); + end + m = g.size(); m_tot = g.N(); @@ -87,15 +95,9 @@ % Borrowing constants for i = 1:dim - beta = ops{i}.borrowing.R.delta_D; - obj.H11{i} = ops{i}.borrowing.H11; - obj.phi{i} = beta/obj.H11{i}; - obj.gamma{i} = ops{i}.borrowing.M.d1; - - % Better names - obj.thR{i} = ops{i}.borrowing.R.delta_D; - obj.thM{i} = ops{i}.borrowing.M.d1; - obj.thH{i} = ops{i}.borrowing.H11; + obj.theta_R{i} = h(i)*ops{i}.borrowing.R.delta_D; + obj.theta_H{i} = h(i)*ops{i}.borrowing.H11; + obj.theta_M{i} = h(i)*ops{i}.borrowing.M.d1; end I = cell(dim,1); @@ -183,6 +185,7 @@ obj.H_boundary = cell(dim,1); obj.H_boundary{1} = H{2}; obj.H_boundary{2} = H{1}; + obj.H_1D = {H{1}, H{2}}; % E{i}^T picks out component i. E = cell(dim,1); @@ -213,7 +216,7 @@ end end obj.D = D; - %=========================================% + %=========================================%' % Numerical traction operators for BC. % Because d1 =/= e0^T*D1, the numerical tractions are different @@ -237,20 +240,28 @@ tau_l{j} = cell(dim,1); tau_r{j} = cell(dim,1); + LAMBDA_l = e_l{j}'*LAMBDA*e_l{j}; + LAMBDA_r = e_r{j}'*LAMBDA*e_r{j}; + MU_l = e_l{j}'*MU*e_l{j}; + MU_r = e_r{j}'*MU*e_r{j}; + + [~, n_l] = size(e_l{j}); + [~, n_r] = size(e_r{j}); + % Loop over components for i = 1:dim - tau_l{j}{i} = sparse(m_tot,dim*m_tot); - tau_r{j}{i} = sparse(m_tot,dim*m_tot); + tau_l{j}{i} = sparse(n_l, dim*m_tot); + tau_r{j}{i} = sparse(n_r, dim*m_tot); for k = 1:dim T_l{j}{i,k} = ... - -d(i,j)*LAMBDA*(d(i,k)*e_l{k}*d1_l{k}' + db(i,k)*D1{k})... - -d(j,k)*MU*(d(i,j)*e_l{i}*d1_l{i}' + db(i,j)*D1{i})... - -d(i,k)*MU*e_l{j}*d1_l{j}'; + -d(i,j)*LAMBDA_l*(d(i,k)*d1_l{j}' + db(i,k)*e_l{j}'*D1{k})... + -d(j,k)*MU_l*(d(i,j)*d1_l{j}' + db(i,j)*e_l{j}'*D1{i})... + -d(i,k)*MU_l*d1_l{j}'; T_r{j}{i,k} = ... - d(i,j)*LAMBDA*(d(i,k)*e_r{k}*d1_r{k}' + db(i,k)*D1{k})... - +d(j,k)*MU*(d(i,j)*e_r{i}*d1_r{i}' + db(i,j)*D1{i})... - +d(i,k)*MU*e_r{j}*d1_r{j}'; + d(i,j)*LAMBDA_r*(d(i,k)*d1_r{j}' + db(i,k)*e_r{j}'*D1{k})... + +d(j,k)*MU_r*(d(i,j)*d1_r{j}' + db(i,j)*e_r{j}'*D1{i})... + +d(i,k)*MU_r*d1_r{j}'; tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}'; tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}'; @@ -258,6 +269,19 @@ end end + + % Transpose T and tau to match boundary operator convention + for i = 1:dim + for j = 1:dim + tau_l{i}{j} = transpose(tau_l{i}{j}); + tau_r{i}{j} = transpose(tau_r{i}{j}); + for k = 1:dim + T_l{i}{j,k} = transpose(T_l{i}{j,k}); + T_r{i}{j,k} = transpose(T_r{i}{j,k}); + end + end + end + obj.T_l = T_l; obj.T_r = T_r; obj.tau_l = tau_l; @@ -275,6 +299,44 @@ obj.grid = g; obj.dim = dim; + % B, used for adjoint optimization + B = cell(dim, 1); + for i = 1:dim + B{i} = cell(m_tot, 1); + end + + for i = 1:dim + for j = 1:m_tot + B{i}{j} = sparse(m_tot, m_tot); + end + end + + ind = grid.funcToMatrix(g, 1:m_tot); + + % Direction 1 + for k = 1:m(1) + c = sparse(m(1),1); + c(k) = 1; + [~, B_1D] = ops{1}.D2(c); + for l = 1:m(2) + p = ind(:,l); + B{1}{(k-1)*m(2) + l}(p, p) = B_1D; + end + end + + % Direction 2 + for k = 1:m(2) + c = sparse(m(2),1); + c(k) = 1; + [~, B_1D] = ops{2}.D2(c); + for l = 1:m(1) + p = ind(l,:); + B{2}{(l-1)*m(2) + k}(p, p) = B_1D; + end + end + + obj.B = B; + end @@ -295,7 +357,8 @@ % j is the coordinate direction of the boundary j = obj.get_boundary_number(boundary); - [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); + [e, T, tau, H_gamma] = obj.getBoundaryOperator({'e','T','tau','H'}, boundary); + E = obj.E; Hi = obj.Hi; @@ -316,33 +379,20 @@ % Dirichlet boundary condition case {'D','d','dirichlet','Dirichlet'} - phi = obj.phi{j}; - h = obj.h(j); - h11 = obj.H11{j}*h; - gamma = obj.gamma{j}; - - a_lambda = dim/h11 + 1/(h11*phi); - a_mu_i = 2/(gamma*h); - a_mu_ij = 2/h11 + 1/(h11*phi); - - d = @kroneckerDelta; % Kronecker delta - db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta - alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ... - + d(i,j)* a_mu_i*MU ... - + db(i,j)*a_mu_ij*MU ); + alpha = obj.getBoundaryOperator('alpha', boundary); % Loop over components that Dirichlet penalties end up on for i = 1:dim - C = T{k,i}; - A = -d(i,k)*alpha(i,j); - B = A + C; + C = transpose(T{k,i}); + A = -tuning*e*transpose(alpha{i,k}); + B = A + e*C; closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' ); penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma; end % Free boundary condition case {'F','f','Free','free','traction','Traction','t','T'} - closure = closure - E{k}*RHOi*Hi*e*H_gamma* (e'*tau{k} ); + closure = closure - E{k}*RHOi*Hi*e*H_gamma*tau{k}'; penalty = penalty + E{k}*RHOi*Hi*e*H_gamma; % Unknown boundary condition @@ -351,160 +401,216 @@ end end - function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary) + % type Struct that specifies the interface coupling. + % Fields: + % -- tuning: penalty strength, defaults to 1.2 + % -- interpolation: type of interpolation, default 'none' + function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type) + + defaultType.tuning = 1.2; + defaultType.interpolation = 'none'; + default_struct('type', defaultType); + + switch type.interpolation + case {'none', ''} + [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type); + case {'op','OP'} + [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type); + otherwise + error('Unknown type of interpolation: %s ', type.interpolation); + end + end + + function [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type) + tuning = type.tuning; + % u denotes the solution in the own domain % v denotes the solution in the neighbour domain % Operators without subscripts are from the own domain. - tuning = 1.2; - - % j is the coordinate direction of the boundary - j = obj.get_boundary_number(boundary); - j_v = neighbour_scheme.get_boundary_number(neighbour_boundary); % Get boundary operators - [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary); - [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary); + e = obj.getBoundaryOperator('e_tot', boundary); + tau = obj.getBoundaryOperator('tau_tot', boundary); + + e_v = neighbour_scheme.getBoundaryOperator('e_tot', neighbour_boundary); + tau_v = neighbour_scheme.getBoundaryOperator('tau_tot', neighbour_boundary); + + H_gamma = obj.getBoundaryQuadrature(boundary); % Operators and quantities that correspond to the own domain only - Hi = obj.Hi; - RHOi = obj.RHOi; - dim = obj.dim; - - %--- Other operators ---- - m_tot_u = obj.grid.N(); - E = obj.E; - LAMBDA_u = obj.LAMBDA; - MU_u = obj.MU; - lambda_u = e'*LAMBDA_u*e; - mu_u = e'*MU_u*e; + Hi = obj.Hi_kron; + RHOi = obj.RHOi_kron; - m_tot_v = neighbour_scheme.grid.N(); - E_v = neighbour_scheme.E; - LAMBDA_v = neighbour_scheme.LAMBDA; - MU_v = neighbour_scheme.MU; - lambda_v = e_v'*LAMBDA_v*e_v; - mu_v = e_v'*MU_v*e_v; - %------------------------- + % Penalty strength operators + alpha_u = 1/4*tuning*obj.getBoundaryOperator('alpha_tot', boundary); + alpha_v = 1/4*tuning*neighbour_scheme.getBoundaryOperator('alpha_tot', neighbour_boundary); - % Borrowing constants - h_u = obj.h(j); - thR_u = obj.thR{j}*h_u; - thM_u = obj.thM{j}*h_u; - thH_u = obj.thH{j}*h_u; - - h_v = neighbour_scheme.h(j_v); - thR_v = neighbour_scheme.thR{j_v}*h_v; - thH_v = neighbour_scheme.thH{j_v}*h_v; - thM_v = neighbour_scheme.thM{j_v}*h_v; + closure = -RHOi*Hi*e*H_gamma*(alpha_u' + alpha_v'*e_v*e'); + penalty = RHOi*Hi*e*H_gamma*(alpha_u'*e*e_v' + alpha_v'); - % alpha = penalty strength for normal component, beta for tangential - alpha_u = dim*lambda_u/(4*thH_u) + lambda_u/(4*thR_u) + mu_u/(2*thM_u); - alpha_v = dim*lambda_v/(4*thH_v) + lambda_v/(4*thR_v) + mu_v/(2*thM_v); - beta_u = mu_u/(2*thH_u) + mu_u/(4*thR_u); - beta_v = mu_v/(2*thH_v) + mu_v/(4*thR_v); - alpha = alpha_u + alpha_v; - beta = beta_u + beta_v; - - d = @kroneckerDelta; % Kronecker delta - db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta - strength = @(i,j) tuning*(d(i,j)*alpha + db(i,j)*beta); + closure = closure - 1/2*RHOi*Hi*e*H_gamma*tau'; + penalty = penalty - 1/2*RHOi*Hi*e*H_gamma*tau_v'; - % Preallocate - closure = sparse(dim*m_tot_u, dim*m_tot_u); - penalty = sparse(dim*m_tot_u, dim*m_tot_v); - - % Loop over components that penalties end up on - for i = 1:dim - closure = closure - E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e'*E{i}'; - penalty = penalty + E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e_v'*E_v{i}'; + closure = closure + 1/2*RHOi*Hi*tau*H_gamma*e'; + penalty = penalty - 1/2*RHOi*Hi*tau*H_gamma*e_v'; - closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*e'*tau{i}; - penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*e_v'*tau_v{i}; + end - % Loop over components that we have interface conditions on - for k = 1:dim - closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}'; - penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}'; - end - end + function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type) + error('Non-conforming interfaces not implemented yet.'); end % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. function [j, nj] = get_boundary_number(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) switch boundary - case {'w','W','west','West', 'e', 'E', 'east', 'East'} + case {'w', 'e'} j = 1; - case {'s','S','south','South', 'n', 'N', 'north', 'North'} + case {'s', 'n'} j = 2; - otherwise - error('No such boundary: boundary = %s',boundary); end switch boundary - case {'w','W','west','West','s','S','south','South'} + case {'w', 's'} nj = -1; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} + case {'e', 'n'} nj = 1; end end % Returns the boundary operator op for the boundary specified by the string boundary. - % op: may be a cell array of strings - function [varargout] = get_boundary_operator(obj, op, boundary) + % op -- string + % Only operators with name *_tot can be used with multiblock.DiffOp.getBoundaryOperator() + function [varargout] = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + assertIsMember(op, {'e', 'e_tot', 'd', 'T', 'tau', 'tau_tot', 'H', 'alpha', 'alpha_tot'}) switch boundary - case {'w','W','west','West', 'e', 'E', 'east', 'East'} + case {'w', 'e'} j = 1; - case {'s','S','south','South', 'n', 'N', 'north', 'North'} + case {'s', 'n'} j = 2; - otherwise - error('No such boundary: boundary = %s',boundary); - end - - if ~iscell(op) - op = {op}; end - for i = 1:length(op) - switch op{i} - case 'e' - switch boundary - case {'w','W','west','West','s','S','south','South'} - varargout{i} = obj.e_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - varargout{i} = obj.e_r{j}; - end - case 'd' - switch boundary - case {'w','W','west','West','s','S','south','South'} - varargout{i} = obj.d1_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - varargout{i} = obj.d1_r{j}; + switch op + case 'e' + switch boundary + case {'w', 's'} + o = obj.e_l{j}; + case {'e', 'n'} + o = obj.e_r{j}; + end + + case 'e_tot' + e = obj.getBoundaryOperator('e', boundary); + I_dim = speye(obj.dim, obj.dim); + o = kron(e, I_dim); + + case 'd' + switch boundary + case {'w', 's'} + o = obj.d1_l{j}; + case {'e', 'n'} + o = obj.d1_r{j}; + end + + case 'T' + switch boundary + case {'w', 's'} + o = obj.T_l{j}; + case {'e', 'n'} + o = obj.T_r{j}; + end + + case 'tau' + switch boundary + case {'w', 's'} + o = obj.tau_l{j}; + case {'e', 'n'} + o = obj.tau_r{j}; + end + + case 'tau_tot' + [e, tau] = obj.getBoundaryOperator({'e', 'tau'}, boundary); + + I_dim = speye(obj.dim, obj.dim); + e_tot = kron(e, I_dim); + E = obj.E; + tau_tot = (e_tot'*E{1}*e*tau{1}')'; + for i = 2:obj.dim + tau_tot = tau_tot + (e_tot'*E{i}*e*tau{i}')'; + end + o = tau_tot; + + case 'H' + o = obj.H_boundary{j}; + + case 'alpha' + % alpha = alpha(i,j) is the penalty strength for displacement BC. + e = obj.getBoundaryOperator('e', boundary); + + LAMBDA = obj.LAMBDA; + MU = obj.MU; + + dim = obj.dim; + theta_R = obj.theta_R{j}; + theta_H = obj.theta_H{j}; + theta_M = obj.theta_M{j}; + + a_lambda = dim/theta_H + 1/theta_R; + a_mu_i = 2/theta_M; + a_mu_ij = 2/theta_H + 1/theta_R; + + d = @kroneckerDelta; % Kronecker delta + db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta + alpha = cell(obj.dim, obj.dim); + + alpha_func = @(i,j) d(i,j)* a_lambda*LAMBDA ... + + d(i,j)* a_mu_i*MU ... + + db(i,j)*a_mu_ij*MU; + for i = 1:obj.dim + for l = 1:obj.dim + alpha{i,l} = d(i,l)*alpha_func(i,j)*e; end - case 'H' - varargout{i} = obj.H_boundary{j}; - case 'T' - switch boundary - case {'w','W','west','West','s','S','south','South'} - varargout{i} = obj.T_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - varargout{i} = obj.T_r{j}; + end + + o = alpha; + + case 'alpha_tot' + % alpha = alpha(i,j) is the penalty strength for displacement BC. + [e, e_tot, alpha] = obj.getBoundaryOperator({'e', 'e_tot', 'alpha'}, boundary); + E = obj.E; + [m, n] = size(alpha{1,1}); + alpha_tot = sparse(m*obj.dim, n*obj.dim); + for i = 1:obj.dim + for l = 1:obj.dim + alpha_tot = alpha_tot + (e_tot'*E{i}*e*alpha{i,l}'*E{l}')'; end - case 'tau' - switch boundary - case {'w','W','west','West','s','S','south','South'} - varargout{i} = obj.tau_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - varargout{i} = obj.tau_r{j}; - end - otherwise - error(['No such operator: operator = ' op{i}]); - end + end + o = alpha_tot; end end + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'w','e'} + j = 1; + case {'s','n'} + j = 2; + end + H = obj.H_boundary{j}; + I_dim = speye(obj.dim, obj.dim); + H = kron(H, I_dim); + end + function N = size(obj) N = obj.dim*prod(obj.m); end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Euler1d.m --- a/+scheme/Euler1d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Euler1d.m Wed Aug 07 15:23:42 2019 +0200 @@ -201,7 +201,8 @@ % Enforces the boundary conditions % w+ = R*w- + g(t) function closure = boundary_condition(obj,boundary, type, varargin) - [e_s,e_S,s] = obj.get_boundary_ops(boundary); + [e_s, e_S] = obj.getBoundaryOperator({'e', 'E'}, boundary); + s = obj.getBoundarySign(boundary); % Boundary condition on form % w_in = R*w_out + g, where g is data @@ -232,7 +233,8 @@ % % Returns closure(q,g) function closure = boundary_condition_L(obj, boundary, L_fun, p_in) - [e_s,e_S,s] = obj.get_boundary_ops(boundary); + [e_s, e_S] = obj.getBoundaryOperator({'e', 'E'}, boundary); + s = obj.getBoundarySign(boundary); p_ot = 1:3; p_ot(p_in) = []; @@ -273,7 +275,8 @@ % Return closure(q,g) function closure = boundary_condition_char(obj,boundary) - [e_s,e_S,s] = obj.get_boundary_ops(boundary); + [e_s, e_S] = obj.getBoundaryOperator({'e', 'E'}, boundary); + s = obj.getBoundarySign(boundary); function o = closure_fun(q, w_data) q_s = e_S'*q; @@ -314,7 +317,7 @@ % Return closure(q,[v; p]) function closure = boundary_condition_inflow(obj, boundary) - [~,~,s] = obj.get_boundary_ops(boundary); + s = obj.getBoundarySign(boundary); switch s case -1 @@ -335,7 +338,7 @@ % Return closure(q, p) function closure = boundary_condition_outflow(obj, boundary) - [~,~,s] = obj.get_boundary_ops(boundary); + s = obj.getBoundarySign(boundary); switch s case -1 @@ -352,7 +355,7 @@ % Return closure(q,[v; rho]) function closure = boundary_condition_inflow_rho(obj, boundary) - [~,~,s] = obj.get_boundary_ops(boundary); + s = obj.getBoundarySign(boundary); switch s case -1 @@ -372,7 +375,7 @@ % Return closure(q,rho) function closure = boundary_condition_outflow_rho(obj, boundary) - [~,~,s] = obj.get_boundary_ops(boundary); + s = obj.getBoundarySign(boundary); switch s case -1 @@ -388,7 +391,8 @@ % Set wall boundary condition v = 0. function closure = boundary_condition_wall(obj,boundary) - [e_s,e_S,s] = obj.get_boundary_ops(boundary); + [e_s, e_S] = obj.getBoundaryOperator({'e', 'E'}, boundary); + s = obj.getBoundarySign(boundary); % Vill vi sätta penalty på karateristikan som är nära noll också eller vill % vi låta den vara fri? @@ -478,18 +482,61 @@ penalty = -halfnorm_inv*(tau*e_v' + sig*d1_v' + phi*alpha_v*d2_v' + psi*alpha_v*d3_v'); end - % Ruturns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e,E,s] = get_boundary_ops(obj,boundary) + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + + if ~iscell(op) + op = {op}; + end + + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'l' + e = obj.e_l; + case 'r' + e = obj.e_r; + otherwise + error('No such boundary: boundary = %s',boundary); + end + varargout{i} = e; + + case 'E' + switch boundary + case 'l' + E = obj.e_L; + case 'r' + E = obj.e_R; + otherwise + error('No such boundary: boundary = %s',boundary); + end + varargout{i} = E; + end + end + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + % Note: for 1d diffOps, the boundary quadrature is the scalar 1. + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + + H_b = 1; + end + + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) switch boundary - case 'l' - e = obj.e_l; - E = obj.e_L; + case {'r'} + s = 1; + case {'l'} s = -1; - case 'r' - e = obj.e_r; - E = obj.e_R; - s = 1; otherwise error('No such boundary: boundary = %s',boundary); end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Heat2dCurvilinear.m --- a/+scheme/Heat2dCurvilinear.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Heat2dCurvilinear.m Wed Aug 07 15:23:42 2019 +0200 @@ -1,9 +1,9 @@ classdef Heat2dCurvilinear < scheme.Scheme % Discretizes the Laplacian with variable coefficent, curvilinear, -% in the Heat equation way (i.e., the discretization matrix is not necessarily +% in the Heat equation way (i.e., the discretization matrix is not necessarily % symmetric) -% u_t = div * (kappa * grad u ) +% u_t = div * (kappa * grad u ) % opSet should be cell array of opSets, one per dimension. This % is useful if we have periodic BC in one direction. @@ -29,9 +29,9 @@ e_l, e_r d1_l, d1_r % Normal derivatives at the boundary alpha % Vector of borrowing constants - + % Boundary inner products - H_boundary_l, H_boundary_r + H_boundary_l, H_boundary_r % Metric coefficients b % Cell matrix of size dim x dim @@ -109,7 +109,7 @@ opSetMetric{1} = sbp.D2Variable(m(1), {0, xmax}, order); opSetMetric{2} = sbp.D2Variable(m(2), {0, ymax}, order); D1Metric{1} = kron(opSetMetric{1}.D1, I{2}); - D1Metric{2} = kron(I{1}, opSetMetric{2}.D1); + D1Metric{2} = kron(I{1}, opSetMetric{2}.D1); x_xi = D1Metric{1}*x; x_eta = D1Metric{2}*x; @@ -157,7 +157,7 @@ % D2 coefficients kappa_coeff = cell(dim,dim); for j = 1:dim - obj.D2_kappa{j} = sparse(m_tot,m_tot); + obj.D2_kappa{j} = sparse(m_tot,m_tot); kappa_coeff{j} = sparse(m_tot,1); for i = 1:dim kappa_coeff{j} = kappa_coeff{j} + b{i,j}*J*b{i,j}*kappa; @@ -270,28 +270,20 @@ default_arg('symmetric', false); default_arg('tuning',1.2); - % j is the coordinate direction of the boundary - % nj: outward unit normal component. + % nj: outward unit normal component. % nj = -1 for west, south, bottom boundaries % nj = 1 for east, north, top boundaries - [j, nj] = obj.get_boundary_number(boundary); - switch nj - case 1 - e = obj.e_r{j}; - flux = obj.flux_r{j}; - H_gamma = obj.H_boundary_r{j}; - case -1 - e = obj.e_l{j}; - flux = obj.flux_l{j}; - H_gamma = obj.H_boundary_l{j}; - end + nj = obj.getBoundarySign(boundary); + + Hi = obj.Hi; + [e, flux] = obj.getBoundaryOperator({'e', 'flux'}, boundary); + H_gamma = obj.getBoundaryQuadrature(boundary); + alpha = obj.getBoundaryBorrowing(boundary); Hi = obj.Hi; Ji = obj.Ji; KAPPA = obj.KAPPA; - kappa_gamma = e'*KAPPA*e; - h = obj.h(j); - alpha = h*obj.alpha(j); + kappa_gamma = e'*KAPPA*e; switch type @@ -299,19 +291,19 @@ case {'D','d','dirichlet','Dirichlet'} if ~symmetric - closure = -Ji*Hi*flux'*e*H_gamma*(e' ); + closure = -Ji*Hi*flux'*e*H_gamma*(e' ); penalty = Ji*Hi*flux'*e*H_gamma; else closure = Ji*Hi*flux'*e*H_gamma*(e' )... - -tuning*2/alpha*Ji*Hi*e*kappa_gamma*H_gamma*(e' ) ; + -tuning*2/alpha*Ji*Hi*e*kappa_gamma*H_gamma*(e' ) ; penalty = -Ji*Hi*flux'*e*H_gamma ... +tuning*2/alpha*Ji*Hi*e*kappa_gamma*H_gamma; end % Normal flux boundary condition case {'N','n','neumann','Neumann'} - closure = -Ji*Hi*e*H_gamma*(e'*flux ); - penalty = Ji*Hi*e*H_gamma; + closure = -Ji*Hi*e*H_gamma*(e'*flux ); + penalty = Ji*Hi*e*H_gamma; % Unknown boundary condition otherwise @@ -325,57 +317,103 @@ error('Interface not implemented'); end - % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. - function [j, nj] = get_boundary_number(obj, boundary) + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) - switch boundary - case {'w','W','west','West', 'e', 'E', 'east', 'East'} - j = 1; - case {'s','S','south','South', 'n', 'N', 'north', 'North'} - j = 2; - otherwise - error('No such boundary: boundary = %s',boundary); + if ~iscell(op) + op = {op}; end - switch boundary - case {'w','W','west','West','s','S','south','South'} - nj = -1; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - nj = 1; + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'w' + e = obj.e_l{1}; + case 'e' + e = obj.e_r{1}; + case 's' + e = obj.e_l{2}; + case 'n' + e = obj.e_r{2}; + end + varargout{i} = e; + + case 'd' + switch boundary + case 'w' + d = obj.d1_l{1}; + case 'e' + d = obj.d1_r{1}; + case 's' + d = obj.d1_l{2}; + case 'n' + d = obj.d1_r{2}; + end + varargout{i} = d; + + case 'flux' + switch boundary + case 'w' + flux = obj.flux_l{1}; + case 'e' + flux = obj.flux_r{1}; + case 's' + flux = obj.flux_l{2}; + case 'n' + flux = obj.flux_r{2}; + end + varargout{i} = flux; + end end end - % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. - function [return_op] = get_boundary_operator(obj, op, boundary) + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) switch boundary - case {'w','W','west','West', 'e', 'E', 'east', 'East'} - j = 1; - case {'s','S','south','South', 'n', 'N', 'north', 'North'} - j = 2; - otherwise - error('No such boundary: boundary = %s',boundary); - end - - switch op + case 'w' + H_b = obj.H_boundary_l{1}; case 'e' - switch boundary - case {'w','W','west','West','s','S','south','South'} - return_op = obj.e_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - return_op = obj.e_r{j}; - end - case 'd' - switch boundary - case {'w','W','west','West','s','S','south','South'} - return_op = obj.d1_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - return_op = obj.d1_r{j}; - end - otherwise - error(['No such operator: operatr = ' op]); + H_b = obj.H_boundary_r{1}; + case 's' + H_b = obj.H_boundary_l{2}; + case 'n' + H_b = obj.H_boundary_r{2}; end + end + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'e','n'} + s = 1; + case {'w','s'} + s = -1; + end + end + + % Returns borrowing constant gamma*h + % boundary -- string + function gamm = getBoundaryBorrowing(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'w','e'} + gamm = obj.h(1)*obj.alpha(1); + case {'s','n'} + gamm = obj.h(2)*obj.alpha(2); + end end function N = size(obj)
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Heat2dVariable.m --- a/+scheme/Heat2dVariable.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Heat2dVariable.m Wed Aug 07 15:23:42 2019 +0200 @@ -1,9 +1,9 @@ classdef Heat2dVariable < scheme.Scheme % Discretizes the Laplacian with variable coefficent, -% In the Heat equation way (i.e., the discretization matrix is not necessarily +% In the Heat equation way (i.e., the discretization matrix is not necessarily % symmetric) -% u_t = div * (kappa * grad u ) +% u_t = div * (kappa * grad u ) % opSet should be cell array of opSets, one per dimension. This % is useful if we have periodic BC in one direction. @@ -29,7 +29,7 @@ e_l, e_r d1_l, d1_r % Normal derivatives at the boundary alpha % Vector of borrowing constants - + H_boundary % Boundary inner products end @@ -162,26 +162,18 @@ default_arg('symmetric', false); default_arg('tuning',1.2); - % j is the coordinate direction of the boundary - % nj: outward unit normal component. + % nj: outward unit normal component. % nj = -1 for west, south, bottom boundaries % nj = 1 for east, north, top boundaries - [j, nj] = obj.get_boundary_number(boundary); - switch nj - case 1 - e = obj.e_r; - d = obj.d1_r; - case -1 - e = obj.e_l; - d = obj.d1_l; - end + nj = obj.getBoundarySign(boundary); Hi = obj.Hi; - H_gamma = obj.H_boundary{j}; + [e, d] = obj.getBoundaryOperator({'e', 'd'}, boundary); + H_gamma = obj.getBoundaryQuadrature(boundary); + alpha = obj.getBoundaryBorrowing(boundary); + KAPPA = obj.KAPPA; - kappa_gamma = e{j}'*KAPPA*e{j}; - h = obj.h(j); - alpha = h*obj.alpha(j); + kappa_gamma = e'*KAPPA*e; switch type @@ -189,19 +181,19 @@ case {'D','d','dirichlet','Dirichlet'} if ~symmetric - closure = -nj*Hi*d{j}*kappa_gamma*H_gamma*(e{j}' ); - penalty = nj*Hi*d{j}*kappa_gamma*H_gamma; + closure = -nj*Hi*d*kappa_gamma*H_gamma*(e' ); + penalty = nj*Hi*d*kappa_gamma*H_gamma; else - closure = nj*Hi*d{j}*kappa_gamma*H_gamma*(e{j}' )... - -tuning*2/alpha*Hi*e{j}*kappa_gamma*H_gamma*(e{j}' ) ; - penalty = -nj*Hi*d{j}*kappa_gamma*H_gamma ... - +tuning*2/alpha*Hi*e{j}*kappa_gamma*H_gamma; + closure = nj*Hi*d*kappa_gamma*H_gamma*(e' )... + -tuning*2/alpha*Hi*e*kappa_gamma*H_gamma*(e' ) ; + penalty = -nj*Hi*d*kappa_gamma*H_gamma ... + +tuning*2/alpha*Hi*e*kappa_gamma*H_gamma; end % Free boundary condition case {'N','n','neumann','Neumann'} - closure = -nj*Hi*e{j}*kappa_gamma*H_gamma*(d{j}' ); - penalty = Hi*e{j}*kappa_gamma*H_gamma; + closure = -nj*Hi*e*kappa_gamma*H_gamma*(d' ); + penalty = Hi*e*kappa_gamma*H_gamma; % penalty is for normal derivative and not for derivative, hence the sign. % Unknown boundary condition @@ -216,57 +208,90 @@ error('Interface not implemented'); end - % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. - function [j, nj] = get_boundary_number(obj, boundary) + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) - switch boundary - case {'w','W','west','West', 'e', 'E', 'east', 'East'} - j = 1; - case {'s','S','south','South', 'n', 'N', 'north', 'North'} - j = 2; - otherwise - error('No such boundary: boundary = %s',boundary); + if ~iscell(op) + op = {op}; end - switch boundary - case {'w','W','west','West','s','S','south','South'} - nj = -1; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - nj = 1; + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'w' + e = obj.e_l{1}; + case 'e' + e = obj.e_r{1}; + case 's' + e = obj.e_l{2}; + case 'n' + e = obj.e_r{2}; + end + varargout{i} = e; + + case 'd' + switch boundary + case 'w' + d = obj.d1_l{1}; + case 'e' + d = obj.d1_r{1}; + case 's' + d = obj.d1_l{2}; + case 'n' + d = obj.d1_r{2}; + end + varargout{i} = d; + end end end - % Returns the coordinate number and outward normal component for the boundary specified by the string boundary. - function [return_op] = get_boundary_operator(obj, op, boundary) + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) switch boundary - case {'w','W','west','West', 'e', 'E', 'east', 'East'} - j = 1; - case {'s','S','south','South', 'n', 'N', 'north', 'North'} - j = 2; - otherwise - error('No such boundary: boundary = %s',boundary); - end - - switch op + case 'w' + H_b = obj.H_boundary{1}; case 'e' - switch boundary - case {'w','W','west','West','s','S','south','South'} - return_op = obj.e_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - return_op = obj.e_r{j}; - end - case 'd' - switch boundary - case {'w','W','west','West','s','S','south','South'} - return_op = obj.d1_l{j}; - case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'} - return_op = obj.d1_r{j}; - end - otherwise - error(['No such operator: operatr = ' op]); + H_b = obj.H_boundary{1}; + case 's' + H_b = obj.H_boundary{2}; + case 'n' + H_b = obj.H_boundary{2}; end + end + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'e','n'} + s = 1; + case {'w','s'} + s = -1; + end + end + + % Returns borrowing constant gamma*h + % boundary -- string + function gamm = getBoundaryBorrowing(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'w','e'} + gamm = obj.h(1)*obj.alpha(1); + case {'s','n'} + gamm = obj.h(2)*obj.alpha(2); + end end function N = size(obj)
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Hypsyst2d.m --- a/+scheme/Hypsyst2d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Hypsyst2d.m Wed Aug 07 15:23:42 2019 +0200 @@ -186,10 +186,10 @@ params = obj.params; x = obj.x; y = obj.y; + e_ = obj.getBoundaryOperator('e', boundary); switch boundary case {'w','W','west'} - e_ = obj.e_w; mat = obj.A; boundPos = 'l'; Hi = obj.Hxi; @@ -197,7 +197,6 @@ L = obj.evaluateCoefficientMatrix(L,x(1),y); side = max(length(y)); case {'e','E','east'} - e_ = obj.e_e; mat = obj.A; boundPos = 'r'; Hi = obj.Hxi; @@ -205,7 +204,6 @@ L = obj.evaluateCoefficientMatrix(L,x(end),y); side = max(length(y)); case {'s','S','south'} - e_ = obj.e_s; mat = obj.B; boundPos = 'l'; Hi = obj.Hyi; @@ -213,7 +211,6 @@ L = obj.evaluateCoefficientMatrix(L,x,y(1)); side = max(length(x)); case {'n','N','north'} - e_ = obj.e_n; mat = obj.B; boundPos = 'r'; Hi = obj.Hyi; @@ -297,5 +294,54 @@ signVec = [sum(poseig),sum(zeroeig),sum(negeig)]; end + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + if ~iscell(op) + op = {op}; + end + + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'w' + e = obj.e_w; + case 'e' + e = obj.e_e; + case 's' + e = obj.e_s; + case 'n' + e = obj.e_n; + end + varargout{i} = e; + end + end + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + e = obj.getBoundaryOperator('e', boundary); + + switch boundary + case 'w' + H_b = inv(e'*obj.Hyi*e); + case 'e' + H_b = inv(e'*obj.Hyi*e); + case 's' + H_b = inv(e'*obj.Hxi*e); + case 'n' + H_b = inv(e'*obj.Hxi*e); + end + end + end end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Hypsyst2dCurve.m --- a/+scheme/Hypsyst2dCurve.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Hypsyst2dCurve.m Wed Aug 07 15:23:42 2019 +0200 @@ -169,31 +169,28 @@ Y = obj.Y; xi = obj.xi; eta = obj.eta; + e_ = obj.getBoundaryOperator('e', boundary); switch boundary case {'w','W','west'} - e_ = obj.e_w; mat = obj.Ahat; boundPos = 'l'; Hi = obj.Hxii; [V,Vi,D,signVec] = obj.matrixDiag(mat,X(obj.index_w),Y(obj.index_w),obj.X_eta(obj.index_w),obj.Y_eta(obj.index_w)); side = max(length(eta)); case {'e','E','east'} - e_ = obj.e_e; mat = obj.Ahat; boundPos = 'r'; Hi = obj.Hxii; [V,Vi,D,signVec] = obj.matrixDiag(mat,X(obj.index_e),Y(obj.index_e),obj.X_eta(obj.index_e),obj.Y_eta(obj.index_e)); side = max(length(eta)); case {'s','S','south'} - e_ = obj.e_s; mat = obj.Bhat; boundPos = 'l'; Hi = obj.Hetai; [V,Vi,D,signVec] = obj.matrixDiag(mat,X(obj.index_s),Y(obj.index_s),obj.X_xi(obj.index_s),obj.Y_xi(obj.index_s)); side = max(length(xi)); case {'n','N','north'} - e_ = obj.e_n; mat = obj.Bhat; boundPos = 'r'; Hi = obj.Hetai; @@ -374,5 +371,56 @@ Vi = [Vi(poseig,:); Vi(zeroeig,:); Vi(negeig,:)]; signVec = [sum(poseig),sum(zeroeig),sum(negeig)]; end + + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + if ~iscell(op) + op = {op}; + end + + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'w' + e = obj.e_w; + case 'e' + e = obj.e_e; + case 's' + e = obj.e_s; + case 'n' + e = obj.e_n; + end + varargout{i} = e; + end + end + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + e = obj.getBoundaryOperator('e', boundary); + + switch boundary + case 'w' + H_b = inv(e'*obj.Hetai*e); + case 'e' + H_b = inv(e'*obj.Hetai*e); + case 's' + H_b = inv(e'*obj.Hxii*e); + case 'n' + H_b = inv(e'*obj.Hxii*e); + end + end + + end end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Laplace1d.m --- a/+scheme/Laplace1d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Laplace1d.m Wed Aug 07 15:23:42 2019 +0200 @@ -56,11 +56,13 @@ default_arg('type','neumann'); default_arg('data',0); - [e,d,s] = obj.get_boundary_ops(boundary); + e = obj.getBoundaryOperator('e', boundary); + d = obj.getBoundaryOperator('d', boundary); + s = obj.getBoundarySign(boundary); switch type % Dirichlet boundary condition - case {'D','dirichlet'} + case {'D','d','dirichlet'} tuning = 1.1; tau1 = -tuning/obj.gamm; tau2 = 1; @@ -68,10 +70,10 @@ tau = tau1*e + tau2*d; closure = obj.a*obj.Hi*tau*e'; - penalty = obj.a*obj.Hi*tau; + penalty = -obj.a*obj.Hi*tau; % Neumann boundary condition - case {'N','neumann'} + case {'N','n','neumann'} tau = -e; closure = obj.a*obj.Hi*tau*d'; @@ -86,10 +88,13 @@ function [closure, penalty] = interface(obj, boundary, neighbour_scheme, neighbour_boundary, type) % u denotes the solution in the own domain % v denotes the solution in the neighbour domain + e_u = obj.getBoundaryOperator('e', boundary); + d_u = obj.getBoundaryOperator('d', boundary); + s_u = obj.getBoundarySign(boundary); - [e_u,d_u,s_u] = obj.get_boundary_ops(boundary); - [e_v,d_v,s_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); - + e_v = neighbour_scheme.getBoundaryOperator('e', neighbour_boundary); + d_v = neighbour_scheme.getBoundaryOperator('d', neighbour_boundary); + s_v = neighbour_scheme.getBoundarySign(neighbour_boundary); a_u = obj.a; a_v = neighbour_scheme.a; @@ -99,7 +104,7 @@ tuning = 1.1; - tau1 = -(a_u/gamm_u + a_v/gamm_v) * tuning; + tau1 = -1/4*(a_u/gamm_u + a_v/gamm_v) * tuning; tau2 = 1/2*a_u; sig1 = -1/2; sig2 = 0; @@ -111,20 +116,37 @@ penalty = obj.Hi*(-tau*e_v' + sig*a_v*d_v'); end - % Ruturns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e,d,s] = get_boundary_ops(obj,boundary) + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string + % boundary -- string + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e', 'd'}) + assertIsMember(boundary, {'l', 'r'}) + + o = obj.([op, '_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + % Note: for 1d diffOps, the boundary quadrature is the scalar 1. + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + + H_b = 1; + end + + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + switch boundary - case 'l' - e = obj.e_l; - d = obj.d_l; + case {'r'} + s = 1; + case {'l'} s = -1; - case 'r' - e = obj.e_r; - d = obj.d_r; - s = 1; - otherwise - error('No such boundary: boundary = %s',boundary); end end @@ -133,14 +155,4 @@ end end - - methods(Static) - % Calculates the matrcis need for the inteface coupling between boundary bound_u of scheme schm_u - % and bound_v of scheme schm_v. - % [uu, uv, vv, vu] = inteface_couplong(A,'r',B,'l') - function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v) - [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v); - [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u); - end - end -end \ No newline at end of file +end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/LaplaceCurvilinear.m --- a/+scheme/LaplaceCurvilinear.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/LaplaceCurvilinear.m Wed Aug 07 15:23:42 2019 +0200 @@ -238,7 +238,10 @@ default_arg('type','neumann'); default_arg('parameter', []); - [e, d, gamm, H_b, ~] = obj.get_boundary_ops(boundary); + e = obj.getBoundaryOperator('e', boundary); + d = obj.getBoundaryOperator('d', boundary); + H_b = obj.getBoundaryQuadrature(boundary); + gamm = obj.getBoundaryBorrowing(boundary); switch type % Dirichlet boundary condition case {'D','d','dirichlet'} @@ -298,8 +301,17 @@ % u denotes the solution in the own domain % v denotes the solution in the neighbour domain - [e_u, d_u, gamm_u, H_b_u, I_u] = obj.get_boundary_ops(boundary); - [e_v, d_v, gamm_v, H_b_v, I_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); + e_u = obj.getBoundaryOperator('e', boundary); + d_u = obj.getBoundaryOperator('d', boundary); + H_b_u = obj.getBoundaryQuadrature(boundary); + I_u = obj.getBoundaryIndices(boundary); + gamm_u = obj.getBoundaryBorrowing(boundary); + + e_v = neighbour_scheme.getBoundaryOperator('e', neighbour_boundary); + d_v = neighbour_scheme.getBoundaryOperator('d', neighbour_boundary); + H_b_v = neighbour_scheme.getBoundaryQuadrature(neighbour_boundary); + I_v = neighbour_scheme.getBoundaryIndices(neighbour_boundary); + gamm_v = neighbour_scheme.getBoundaryBorrowing(neighbour_boundary); u = obj; v = neighbour_scheme; @@ -336,8 +348,18 @@ % u denotes the solution in the own domain % v denotes the solution in the neighbour domain - [e_u, d_u, gamm_u, H_b_u, I_u] = obj.get_boundary_ops(boundary); - [e_v, d_v, gamm_v, H_b_v, I_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); + e_u = obj.getBoundaryOperator('e', boundary); + d_u = obj.getBoundaryOperator('d', boundary); + H_b_u = obj.getBoundaryQuadrature(boundary); + I_u = obj.getBoundaryIndices(boundary); + gamm_u = obj.getBoundaryBorrowing(boundary); + + e_v = neighbour_scheme.getBoundaryOperator('e', neighbour_boundary); + d_v = neighbour_scheme.getBoundaryOperator('d', neighbour_boundary); + H_b_v = neighbour_scheme.getBoundaryQuadrature(neighbour_boundary); + I_v = neighbour_scheme.getBoundaryIndices(neighbour_boundary); + gamm_v = neighbour_scheme.getBoundaryBorrowing(neighbour_boundary); + % Find the number of grid points along the interface m_u = size(e_u, 2); @@ -378,37 +400,48 @@ end - % Returns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string + % boundary -- string + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e', 'd'}) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + o = obj.([op, '_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points % - % I -- the indices of the boundary points in the grid matrix - function [e, d, gamm, H_b, I] = get_boundary_ops(obj, boundary) + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + H_b = obj.(['H_', boundary]); + end + + % Returns the indices of the boundary points in the grid matrix + % boundary -- string + function I = getBoundaryIndices(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + ind = grid.funcToMatrix(obj.grid, 1:prod(obj.m)); - switch boundary case 'w' - e = obj.e_w; - d = obj.d_w; - H_b = obj.H_w; I = ind(1,:); case 'e' - e = obj.e_e; - d = obj.d_e; - H_b = obj.H_e; I = ind(end,:); case 's' - e = obj.e_s; - d = obj.d_s; - H_b = obj.H_s; I = ind(:,1)'; case 'n' - e = obj.e_n; - d = obj.d_n; - H_b = obj.H_n; I = ind(:,end)'; - otherwise - error('No such boundary: boundary = %s',boundary); end + end + + % Returns borrowing constant gamma + % boundary -- string + function gamm = getBoundaryBorrowing(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) switch boundary case {'w','e'}
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Scheme.m --- a/+scheme/Scheme.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Scheme.m Wed Aug 07 15:23:42 2019 +0200 @@ -31,20 +31,10 @@ % depending on the particular scheme implementation [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type) - % TODO: op = getBoundaryOperator()?? - % makes sense to have it available through a method instead of random properties + op = getBoundaryOperator(obj, opName, boundary) + H_b= getBoundaryQuadrature(obj, boundary) % Returns the number of degrees of freedom. N = size(obj) end - - methods(Static) - % Calculates the matrcis need for the inteface coupling between - % boundary bound_u of scheme schm_u and bound_v of scheme schm_v. - % [uu, uv, vv, vu] = inteface_coupling(A,'r',B,'l') - function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v) - [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v); - [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u); - end - end end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Schrodinger.m --- a/+scheme/Schrodinger.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Schrodinger.m Wed Aug 07 15:23:42 2019 +0200 @@ -67,7 +67,8 @@ default_arg('type','dirichlet'); default_arg('data',0); - [e,d,s] = obj.get_boundary_ops(boundary); + [e, d] = obj.getBoundaryOperator({'e', 'd'}, boundary); + s = obj.getBoundarySign(boundary); switch type % Dirichlet boundary condition @@ -93,8 +94,11 @@ function [closure, penalty] = interface(obj, boundary, neighbour_scheme, neighbour_boundary, type) % u denotes the solution in the own domain % v denotes the solution in the neighbour domain - [e_u,d_u,s_u] = obj.get_boundary_ops(boundary); - [e_v,d_v,s_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); + [e_u, d_u] = obj.getBoundaryOperator({'e', 'd'}, boundary); + s_u = obj.getBoundarySign(boundary); + + [e_v, d_v] = neighbour_scheme.getBoundaryOperator({'e', 'd'}, neighbour_boundary); + s_v = neighbour_scheme.getBoundarySign(neighbour_boundary); a = -s_u* 1/2 * 1i ; b = a'; @@ -106,20 +110,60 @@ penalty = obj.Hi * (-tau*e_v' - sig*d_v'); end - % Ruturns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e,d,s] = get_boundary_ops(obj,boundary) + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'l', 'r'}) + + if ~iscell(op) + op = {op}; + end + + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'l' + e = obj.e_l; + case 'r' + e = obj.e_r; + end + varargout{i} = e; + + case 'd' + switch boundary + case 'l' + d = obj.d1_l; + case 'r' + d = obj.d1_r; + end + varargout{i} = d; + end + end + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + % Note: for 1d diffOps, the boundary quadrature is the scalar 1. + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + + H_b = 1; + end + + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + switch boundary - case 'l' - e = obj.e_l; - d = obj.d1_l; + case {'r'} + s = 1; + case {'l'} s = -1; - case 'r' - e = obj.e_r; - d = obj.d1_r; - s = 1; - otherwise - error('No such boundary: boundary = %s',boundary); end end @@ -128,14 +172,4 @@ end end - - methods(Static) - % Calculates the matrcis need for the inteface coupling between boundary bound_u of scheme schm_u - % and bound_v of scheme schm_v. - % [uu, uv, vv, vu] = inteface_couplong(A,'r',B,'l') - function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v) - [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v); - [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u); - end - end -end \ No newline at end of file +end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Schrodinger2d.m --- a/+scheme/Schrodinger2d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Schrodinger2d.m Wed Aug 07 15:23:42 2019 +0200 @@ -162,35 +162,26 @@ default_arg('type','Neumann'); default_arg('parameter', []); - % j is the coordinate direction of the boundary % nj: outward unit normal component. % nj = -1 for west, south, bottom boundaries % nj = 1 for east, north, top boundaries - [j, nj] = obj.get_boundary_number(boundary); - switch nj - case 1 - e = obj.e_r; - d = obj.d1_r; - case -1 - e = obj.e_l; - d = obj.d1_l; - end - + nj = obj.getBoundarySign(boundary); + [e, d] = obj.getBoundaryOperator({'e', 'd'}, boundary); + H_gamma = obj.getBoundaryQuadrature(boundary); Hi = obj.Hi; - H_gamma = obj.H_boundary{j}; - a = e{j}'*obj.a*e{j}; + a = e'*obj.a*e; switch type % Dirichlet boundary condition case {'D','d','dirichlet','Dirichlet'} - closure = nj*Hi*d{j}*a*1i*H_gamma*(e{j}' ); - penalty = -nj*Hi*d{j}*a*1i*H_gamma; + closure = nj*Hi*d*a*1i*H_gamma*(e' ); + penalty = -nj*Hi*d*a*1i*H_gamma; % Free boundary condition case {'N','n','neumann','Neumann'} - closure = -nj*Hi*e{j}*a*1i*H_gamma*(d{j}' ); - penalty = nj*Hi*e{j}*a*1i*H_gamma; + closure = -nj*Hi*e*a*1i*H_gamma*(d' ); + penalty = nj*Hi*e*a*1i*H_gamma; % Unknown boundary condition otherwise @@ -221,13 +212,14 @@ % v denotes the solution in the neighbour domain % Get boundary operators - [e_neighbour, d_neighbour] = neighbour_scheme.get_boundary_ops(neighbour_boundary); - [e, d, H_gamma] = obj.get_boundary_ops(boundary); + [e_v, d_v] = neighbour_scheme.getBoundaryOperator({'e', 'd'}, neighbour_boundary); + [e_u, d_u] = obj.getBoundaryOperator({'e', 'd'}, boundary); + H_gamma = obj.getBoundaryQuadrature(boundary); Hi = obj.Hi; a = obj.a; % Get outward unit normal component - [~, n] = obj.get_boundary_number(boundary); + n = obj.getBoundarySign(boundary); Hi = obj.Hi; sigma = -n*1i*a/2; @@ -247,13 +239,14 @@ % u denotes the solution in the own domain % v denotes the solution in the neighbour domain - [e_v, d_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); - [e_u, d_u, H_gamma] = obj.get_boundary_ops(boundary); + [e_v, d_v] = neighbour_scheme.getBoundaryOperator({'e', 'd'}, neighbour_boundary); + [e_u, d_u] = obj.getBoundaryOperator({'e', 'd'}, boundary); + H_gamma = obj.getBoundaryQuadrature(boundary); Hi = obj.Hi; a = obj.a; % Get outward unit normal component - [~, n] = obj.get_boundary_number(boundary); + n = obj.getBoundarySign(boundary); % Find the number of grid points along the interface m_u = size(e_u, 2); @@ -293,29 +286,76 @@ end end - % Returns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e, d, H_b] = get_boundary_ops(obj, boundary) + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + if ~iscell(op) + op = {op}; + end + + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'w' + e = obj.e_w; + case 'e' + e = obj.e_e; + case 's' + e = obj.e_s; + case 'n' + e = obj.e_n; + end + varargout{i} = e; + + case 'd' + switch boundary + case 'w' + d = obj.d_w; + case 'e' + d = obj.d_e; + case 's' + d = obj.d_s; + case 'n' + d = obj.d_n; + end + varargout{i} = d; + end + end + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) switch boundary case 'w' - e = obj.e_w; - d = obj.d_w; H_b = obj.H_boundary{1}; case 'e' - e = obj.e_e; - d = obj.d_e; H_b = obj.H_boundary{1}; case 's' - e = obj.e_s; - d = obj.d_s; H_b = obj.H_boundary{2}; case 'n' - e = obj.e_n; - d = obj.d_n; H_b = obj.H_boundary{2}; - otherwise - error('No such boundary: boundary = %s',boundary); + end + end + + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'e','n'} + s = 1; + case {'w','s'} + s = -1; end end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/TODO.txt --- a/+scheme/TODO.txt Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -% TODO: Rename package and abstract class to diffOp
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Utux.m --- a/+scheme/Utux.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Utux.m Wed Aug 07 15:23:42 2019 +0200 @@ -68,26 +68,23 @@ % neighbour_boundary is a string specifying which boundary to interface to. function [closure, penalty] = boundary_condition(obj,boundary,type) default_arg('type','dirichlet'); - sigma_left = -1; % Scalar penalty parameter for left boundary - sigma_right = 1; % Scalar penalty parameter for right boundary + s = obj.getBoundarySign(boundary); + e = obj.getBoundaryOperator('e', boundary); switch boundary % Can only specify boundary condition where there is inflow % Extract the postivie resp. negative part of a, for the left % resp. right boundary, and set other values of a to zero. % Then the closure will effectively only contribute to inflow boundaries - case {'l','L','left','Left'} + case {'l'} a_inflow = obj.a; a_inflow(a_inflow < 0) = 0; - tau = sigma_left*a_inflow*obj.e_l; - closure = obj.Hi*tau*obj.e_l'; - case {'r','R','right','Right'} + case {'r'} a_inflow = obj.a; a_inflow(a_inflow > 0) = 0; - tau = sigma_right*a_inflow*obj.e_r; - closure = obj.Hi*tau*obj.e_r'; end + tau = s*a_inflow*e; + closure = obj.Hi*tau*e'; penalty = -obj.Hi*tau; - end function [closure, penalty] = interface(obj, boundary, neighbour_scheme, neighbour_boundary, type) @@ -105,19 +102,43 @@ end + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + + switch boundary + case {'r'} + s = 1; + case {'l'} + s = -1; + end + end + + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string + % boundary -- string + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e'}) + assertIsMember(boundary, {'l', 'r'}) + + o = obj.([op, '_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + % Note: for 1d diffOps, the boundary quadrature is the scalar 1. + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'l', 'r'}) + + H_b = 1; + end + function N = size(obj) N = obj.m; end end - - methods(Static) - % Calculates the matrices needed for the inteface coupling between boundary bound_u of scheme schm_u - % and bound_v of scheme schm_v. - % [uu, uv, vv, vu] = inteface_coupling(A,'r',B,'l') - function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v) - [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v); - [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u); - end - end -end \ No newline at end of file +end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Utux2d.m --- a/+scheme/Utux2d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Utux2d.m Wed Aug 07 15:23:42 2019 +0200 @@ -11,6 +11,7 @@ H % Discrete norm H_x, H_y % Norms in the x and y directions Hi, Hx, Hy, Hxi, Hyi % Kroneckered norms + H_w, H_e, H_s, H_n % Boundary quadratures % Derivatives Dx, Dy @@ -59,6 +60,10 @@ Hxi = ops_x.HI; Hyi = ops_y.HI; + obj.H_w = Hy; + obj.H_e = Hy; + obj.H_s = Hx; + obj.H_n = Hx; obj.H_x = Hx; obj.H_y = Hy; obj.H = kron(Hx,Hy); @@ -109,8 +114,9 @@ % neighbour_boundary is a string specifying which boundary to interface to. function [closure, penalty] = boundary_condition(obj,boundary,type) default_arg('type','dirichlet'); - sigma_left = -1; % Scalar penalty parameter for left boundaries (West/South) - sigma_right = 1; % Scalar penalty parameter for right boundaries (East/North) + s = obj.getBoundarySign(boundary); + e = obj.getBoundaryOperator('e', boundary); + H_1d = obj.getOneDirectionalNorm(boundary); switch boundary % Can only specify boundary condition where there is inflow % Extract the postivie resp. negative part of a, for the left @@ -119,24 +125,18 @@ case {'w','W','west','West'} a_inflow = obj.a{1}; a_inflow(a_inflow < 0) = 0; - tau = sigma_left*a_inflow*obj.e_w*obj.H_y; - closure = obj.Hi*tau*obj.e_w'; case {'e','E','east','East'} a_inflow = obj.a{1}; a_inflow(a_inflow > 0) = 0; - tau = sigma_right*a_inflow*obj.e_e*obj.H_y; - closure = obj.Hi*tau*obj.e_e'; case {'s','S','south','South'} a_inflow = obj.a{2}; a_inflow(a_inflow < 0) = 0; - tau = sigma_left*a_inflow*obj.e_s*obj.H_x; - closure = obj.Hi*tau*obj.e_s'; case {'n','N','north','North'} a_inflow = obj.a{2}; a_inflow(a_inflow > 0) = 0; - tau = sigma_right*a_inflow*obj.e_n*obj.H_x; - closure = obj.Hi*tau*obj.e_n'; end + tau = s*a_inflow*e*H_1d; + closure = obj.Hi*tau*e'; penalty = -obj.Hi*tau; end @@ -168,16 +168,7 @@ couplingType = type.couplingType; % Get neighbour boundary operator - switch neighbour_boundary - case {'e','E','east','East'} - e_neighbour = neighbour_scheme.e_e; - case {'w','W','west','West'} - e_neighbour = neighbour_scheme.e_w; - case {'n','N','north','North'} - e_neighbour = neighbour_scheme.e_n; - case {'s','S','south','South'} - e_neighbour = neighbour_scheme.e_s; - end + e_neighbour = neighbour_scheme.getBoundaryOperator('e', neighbour_boundary); switch couplingType @@ -226,16 +217,7 @@ interpolationDamping = type.interpolationDamping; % Get neighbour boundary operator - switch neighbour_boundary - case {'e','E','east','East'} - e_neighbour = neighbour_scheme.e_e; - case {'w','W','west','West'} - e_neighbour = neighbour_scheme.e_w; - case {'n','N','north','North'} - e_neighbour = neighbour_scheme.e_n; - case {'s','S','south','South'} - e_neighbour = neighbour_scheme.e_s; - end + e_neighbour = neighbour_scheme.getBoundaryOperator('e', neighbour_boundary); switch couplingType @@ -319,19 +301,55 @@ end + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + switch boundary + case {'e','n'} + s = 1; + case {'w','s'} + s = -1; + end + end + + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string + % boundary -- string + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e'}) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + o = obj.([op, '_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + H_b = obj.(['H_', boundary]); + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_1d = getOneDirectionalNorm(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + switch boundary + case {'w','e'} + H_1d = obj.H_y; + case {'s','n'} + H_1d = obj.H_x; + end + end + function N = size(obj) N = obj.m; end end - - methods(Static) - % Calculates the matrices needed for the inteface coupling between boundary bound_u of scheme schm_u - % and bound_v of scheme schm_v. - % [uu, uv, vv, vu] = inteface_coupling(A,'r',B,'l') - function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v) - [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v); - [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u); - end - end -end \ No newline at end of file +end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Wave2d.m --- a/+scheme/Wave2d.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+scheme/Wave2d.m Wed Aug 07 15:23:42 2019 +0200 @@ -106,7 +106,10 @@ default_arg('type','neumann'); default_arg('data',0); - [e,d,s,gamm,halfnorm_inv] = obj.get_boundary_ops(boundary); + [e, d] = obj.getBoundaryOperator({'e', 'd'}, boundary); + gamm = obj.getBoundaryBorrowing(boundary); + s = obj.getBoundarySign(boundary); + halfnorm_inv = obj.getHalfnormInv(boundary); switch type % Dirichlet boundary condition @@ -164,6 +167,15 @@ [e_u,d_u,s_u,gamm_u, halfnorm_inv] = obj.get_boundary_ops(boundary); [e_v,d_v,s_v,gamm_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); + [e_u, d_u] = obj.getBoundaryOperator({'e', 'd'}, boundary); + gamm_u = obj.getBoundaryBorrowing(boundary); + s_u = obj.getBoundarySign(boundary); + halfnorm_inv = obj.getHalfnormInv(boundary); + + [e_v, d_v] = neighbour_scheme.getBoundaryOperator({'e', 'd'}, neighbour_boundary); + gamm_v = neighbour_scheme.getBoundaryBorrowing(neighbour_boundary); + s_v = neighbour_scheme.getBoundarySign(neighbour_boundary); + tuning = 1.1; alpha_u = obj.alpha; @@ -183,36 +195,107 @@ penalty = halfnorm_inv*(-tau*e_v' - sig*alpha_v*d_v'); end - % Ruturns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - function [e,d,s,gamm, halfnorm_inv] = get_boundary_ops(obj,boundary) + + % Returns the boundary operator op for the boundary specified by the string boundary. + % op -- string or a cell array of strings + % boundary -- string + function varargout = getBoundaryOperator(obj, op, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + if ~iscell(op) + op = {op}; + end + + for i = 1:numel(op) + switch op{i} + case 'e' + switch boundary + case 'w' + e = obj.e_w; + case 'e' + e = obj.e_e; + case 's' + e = obj.e_s; + case 'n' + e = obj.e_n; + end + varargout{i} = e; + + case 'd' + switch boundary + case 'w' + d = obj.d1_w; + case 'e' + d = obj.d1_e; + case 's' + d = obj.d1_s; + case 'n' + d = obj.d1_n; + end + varargout{i} = d; + end + end + + end + + % Returns square boundary quadrature matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + switch boundary case 'w' - e = obj.e_w; - d = obj.d1_w; - s = -1; - gamm = obj.gamm_x; - halfnorm_inv = obj.Hix; + H_b = obj.H_y; case 'e' - e = obj.e_e; - d = obj.d1_e; - s = 1; - gamm = obj.gamm_x; - halfnorm_inv = obj.Hix; + H_b = obj.H_y; case 's' - e = obj.e_s; - d = obj.d1_s; - s = -1; - gamm = obj.gamm_y; - halfnorm_inv = obj.Hiy; + H_b = obj.H_x; case 'n' - e = obj.e_n; - d = obj.d1_n; - s = 1; + H_b = obj.H_x; + end + end + + % Returns borrowing constant gamma + % boundary -- string + function gamm = getBoundaryBorrowing(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'w','e'} + gamm = obj.gamm_x; + case {'s','n'} gamm = obj.gamm_y; - halfnorm_inv = obj.Hiy; - otherwise - error('No such boundary: boundary = %s',boundary); + end + end + + % Returns the boundary sign. The right boundary is considered the positive boundary + % boundary -- string + function s = getBoundarySign(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case {'e','n'} + s = 1; + case {'w','s'} + s = -1; + end + end + + % Returns the halfnorm_inv used in SATs. TODO: better notation + function Hinv = getHalfnormInv(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + switch boundary + case 'w' + Hinv = obj.Hix; + case 'e' + Hinv = obj.Hix; + case 's' + Hinv = obj.Hiy; + case 'n' + Hinv = obj.Hiy; end end @@ -221,14 +304,4 @@ end end - - methods(Static) - % Calculates the matrcis need for the inteface coupling between boundary bound_u of scheme schm_u - % and bound_v of scheme schm_v. - % [uu, uv, vv, vu] = inteface_couplong(A,'r',B,'l') - function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v) - [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v); - [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u); - end - end -end \ No newline at end of file +end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/Wave2dCurve.m --- a/+scheme/Wave2dCurve.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,359 +0,0 @@ -classdef Wave2dCurve < scheme.Scheme - properties - m % Number of points in each direction, possibly a vector - h % Grid spacing - - grid - - order % Order accuracy for the approximation - - D % non-stabalized scheme operator - M % Derivative norm - c - J, Ji - a11, a12, a22 - - H % Discrete norm - Hi - H_u, H_v % Norms in the x and y directions - Hu,Hv % Kroneckerd norms. 1'*Hx*v corresponds to integration in the x dir. - Hi_u, Hi_v - Hiu, Hiv - e_w, e_e, e_s, e_n - du_w, dv_w - du_e, dv_e - du_s, dv_s - du_n, dv_n - gamm_u, gamm_v - lambda - - Dx, Dy % Physical derivatives - - x_u - x_v - y_u - y_v - end - - methods - function obj = Wave2dCurve(g ,order, c, opSet) - default_arg('opSet',@sbp.D2Variable); - default_arg('c', 1); - - warning('Use LaplaceCruveilinear instead') - - assert(isa(g, 'grid.Curvilinear')) - - m = g.size(); - m_u = m(1); - m_v = m(2); - m_tot = g.N(); - - h = g.scaling(); - h_u = h(1); - h_v = h(2); - - % Operators - ops_u = opSet(m_u, {0, 1}, order); - ops_v = opSet(m_v, {0, 1}, order); - - I_u = speye(m_u); - I_v = speye(m_v); - - D1_u = ops_u.D1; - D2_u = ops_u.D2; - H_u = ops_u.H; - Hi_u = ops_u.HI; - e_l_u = ops_u.e_l; - e_r_u = ops_u.e_r; - d1_l_u = ops_u.d1_l; - d1_r_u = ops_u.d1_r; - - D1_v = ops_v.D1; - D2_v = ops_v.D2; - H_v = ops_v.H; - Hi_v = ops_v.HI; - e_l_v = ops_v.e_l; - e_r_v = ops_v.e_r; - d1_l_v = ops_v.d1_l; - d1_r_v = ops_v.d1_r; - - Du = kr(D1_u,I_v); - Dv = kr(I_u,D1_v); - - % Metric derivatives - coords = g.points(); - x = coords(:,1); - y = coords(:,2); - - x_u = Du*x; - x_v = Dv*x; - y_u = Du*y; - y_v = Dv*y; - - J = x_u.*y_v - x_v.*y_u; - a11 = 1./J .* (x_v.^2 + y_v.^2); - a12 = -1./J .* (x_u.*x_v + y_u.*y_v); - a22 = 1./J .* (x_u.^2 + y_u.^2); - lambda = 1/2 * (a11 + a22 - sqrt((a11-a22).^2 + 4*a12.^2)); - - % Assemble full operators - L_12 = spdiags(a12, 0, m_tot, m_tot); - Duv = Du*L_12*Dv; - Dvu = Dv*L_12*Du; - - Duu = sparse(m_tot); - Dvv = sparse(m_tot); - ind = grid.funcToMatrix(g, 1:m_tot); - - for i = 1:m_v - D = D2_u(a11(ind(:,i))); - p = ind(:,i); - Duu(p,p) = D; - end - - for i = 1:m_u - D = D2_v(a22(ind(i,:))); - p = ind(i,:); - Dvv(p,p) = D; - end - - obj.H = kr(H_u,H_v); - obj.Hi = kr(Hi_u,Hi_v); - obj.Hu = kr(H_u,I_v); - obj.Hv = kr(I_u,H_v); - obj.Hiu = kr(Hi_u,I_v); - obj.Hiv = kr(I_u,Hi_v); - - obj.e_w = kr(e_l_u,I_v); - obj.e_e = kr(e_r_u,I_v); - obj.e_s = kr(I_u,e_l_v); - obj.e_n = kr(I_u,e_r_v); - obj.du_w = kr(d1_l_u,I_v); - obj.dv_w = (obj.e_w'*Dv)'; - obj.du_e = kr(d1_r_u,I_v); - obj.dv_e = (obj.e_e'*Dv)'; - obj.du_s = (obj.e_s'*Du)'; - obj.dv_s = kr(I_u,d1_l_v); - obj.du_n = (obj.e_n'*Du)'; - obj.dv_n = kr(I_u,d1_r_v); - - obj.x_u = x_u; - obj.x_v = x_v; - obj.y_u = y_u; - obj.y_v = y_v; - - obj.m = m; - obj.h = [h_u h_v]; - obj.order = order; - obj.grid = g; - - obj.c = c; - obj.J = spdiags(J, 0, m_tot, m_tot); - obj.Ji = spdiags(1./J, 0, m_tot, m_tot); - obj.a11 = a11; - obj.a12 = a12; - obj.a22 = a22; - obj.D = obj.Ji*c^2*(Duu + Duv + Dvu + Dvv); - obj.lambda = lambda; - - obj.Dx = spdiag( y_v./J)*Du + spdiag(-y_u./J)*Dv; - obj.Dy = spdiag(-x_v./J)*Du + spdiag( x_u./J)*Dv; - - obj.gamm_u = h_u*ops_u.borrowing.M.d1; - obj.gamm_v = h_v*ops_v.borrowing.M.d1; - end - - - % Closure functions return the opertors applied to the own doamin to close the boundary - % Penalty functions return the opertors to force the solution. In the case of an interface it returns the operator applied to the other doamin. - % boundary is a string specifying the boundary e.g. 'l','r' or 'e','w','n','s'. - % type is a string specifying the type of boundary condition if there are several. - % data is a function returning the data that should be applied at the boundary. - % neighbour_scheme is an instance of Scheme that should be interfaced to. - % neighbour_boundary is a string specifying which boundary to interface to. - function [closure, penalty] = boundary_condition(obj, boundary, type, parameter) - default_arg('type','neumann'); - default_arg('parameter', []); - - [e, d_n, d_t, coeff_n, coeff_t, s, gamm, halfnorm_inv , ~, ~, ~, scale_factor] = obj.get_boundary_ops(boundary); - switch type - % Dirichlet boundary condition - case {'D','d','dirichlet'} - % v denotes the solution in the neighbour domain - tuning = 1.2; - % tuning = 20.2; - [e, d_n, d_t, coeff_n, coeff_t, s, gamm, halfnorm_inv_n, halfnorm_inv_t, halfnorm_t] = obj.get_boundary_ops(boundary); - - a_n = spdiag(coeff_n); - a_t = spdiag(coeff_t); - - F = (s * a_n * d_n' + s * a_t*d_t')'; - - u = obj; - - b1 = gamm*u.lambda./u.a11.^2; - b2 = gamm*u.lambda./u.a22.^2; - - tau = -1./b1 - 1./b2; - tau = tuning * spdiag(tau); - sig1 = 1; - - penalty_parameter_1 = halfnorm_inv_n*(tau + sig1*halfnorm_inv_t*F*e'*halfnorm_t)*e; - - closure = obj.Ji*obj.c^2 * penalty_parameter_1*e'; - penalty = -obj.Ji*obj.c^2 * penalty_parameter_1; - - - % Neumann boundary condition - case {'N','n','neumann'} - c = obj.c; - - a_n = spdiags(coeff_n,0,length(coeff_n),length(coeff_n)); - a_t = spdiags(coeff_t,0,length(coeff_t),length(coeff_t)); - d = (a_n * d_n' + a_t*d_t')'; - - tau1 = -s; - tau2 = 0; - tau = c.^2 * obj.Ji*(tau1*e + tau2*d); - - closure = halfnorm_inv*tau*d'; - penalty = -halfnorm_inv*tau; - - % Characteristic boundary condition - case {'characteristic', 'char', 'c'} - default_arg('parameter', 1); - beta = parameter; - c = obj.c; - - a_n = spdiags(coeff_n,0,length(coeff_n),length(coeff_n)); - a_t = spdiags(coeff_t,0,length(coeff_t),length(coeff_t)); - d = s*(a_n * d_n' + a_t*d_t')'; % outward facing normal derivative - - tau = -c.^2 * 1/beta*obj.Ji*e; - - warning('is this right?! /c?') - closure{1} = halfnorm_inv*tau/c*spdiag(scale_factor)*e'; - closure{2} = halfnorm_inv*tau*beta*d'; - penalty = -halfnorm_inv*tau; - - % Unknown, boundary condition - otherwise - error('No such boundary condition: type = %s',type); - end - end - - function [closure, penalty] = interface(obj, boundary, neighbour_scheme, neighbour_boundary, type) - % u denotes the solution in the own domain - % v denotes the solution in the neighbour domain - tuning = 1.2; - % tuning = 20.2; - [e_u, d_n_u, d_t_u, coeff_n_u, coeff_t_u, s_u, gamm_u, halfnorm_inv_u_n, halfnorm_inv_u_t, halfnorm_u_t, I_u] = obj.get_boundary_ops(boundary); - [e_v, d_n_v, d_t_v, coeff_n_v, coeff_t_v, s_v, gamm_v, halfnorm_inv_v_n, halfnorm_inv_v_t, halfnorm_v_t, I_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary); - - a_n_u = spdiag(coeff_n_u); - a_t_u = spdiag(coeff_t_u); - a_n_v = spdiag(coeff_n_v); - a_t_v = spdiag(coeff_t_v); - - F_u = (s_u * a_n_u * d_n_u' + s_u * a_t_u*d_t_u')'; - F_v = (s_v * a_n_v * d_n_v' + s_v * a_t_v*d_t_v')'; - - u = obj; - v = neighbour_scheme; - - b1_u = gamm_u*u.lambda(I_u)./u.a11(I_u).^2; - b2_u = gamm_u*u.lambda(I_u)./u.a22(I_u).^2; - b1_v = gamm_v*v.lambda(I_v)./v.a11(I_v).^2; - b2_v = gamm_v*v.lambda(I_v)./v.a22(I_v).^2; - - tau = -1./(4*b1_u) -1./(4*b1_v) -1./(4*b2_u) -1./(4*b2_v); - tau = tuning * spdiag(tau); - sig1 = 1/2; - sig2 = -1/2; - - penalty_parameter_1 = halfnorm_inv_u_n*(e_u*tau + sig1*halfnorm_inv_u_t*F_u*e_u'*halfnorm_u_t*e_u); - penalty_parameter_2 = halfnorm_inv_u_n * sig2 * e_u; - - - closure = obj.Ji*obj.c^2 * ( penalty_parameter_1*e_u' + penalty_parameter_2*F_u'); - penalty = obj.Ji*obj.c^2 * (-penalty_parameter_1*e_v' + penalty_parameter_2*F_v'); - end - - % Ruturns the boundary ops and sign for the boundary specified by the string boundary. - % The right boundary is considered the positive boundary - % - % I -- the indecies of the boundary points in the grid matrix - function [e, d_n, d_t, coeff_n, coeff_t, s, gamm, halfnorm_inv_n, halfnorm_inv_t, halfnorm_t, I, scale_factor] = get_boundary_ops(obj, boundary) - - % gridMatrix = zeros(obj.m(2),obj.m(1)); - % gridMatrix(:) = 1:numel(gridMatrix); - - ind = grid.funcToMatrix(obj.grid, 1:prod(obj.m)); - - switch boundary - case 'w' - e = obj.e_w; - d_n = obj.du_w; - d_t = obj.dv_w; - s = -1; - - I = ind(1,:); - coeff_n = obj.a11(I); - coeff_t = obj.a12(I); - scale_factor = sqrt(obj.x_v(I).^2 + obj.y_v(I).^2); - case 'e' - e = obj.e_e; - d_n = obj.du_e; - d_t = obj.dv_e; - s = 1; - - I = ind(end,:); - coeff_n = obj.a11(I); - coeff_t = obj.a12(I); - scale_factor = sqrt(obj.x_v(I).^2 + obj.y_v(I).^2); - case 's' - e = obj.e_s; - d_n = obj.dv_s; - d_t = obj.du_s; - s = -1; - - I = ind(:,1)'; - coeff_n = obj.a22(I); - coeff_t = obj.a12(I); - scale_factor = sqrt(obj.x_u(I).^2 + obj.y_u(I).^2); - case 'n' - e = obj.e_n; - d_n = obj.dv_n; - d_t = obj.du_n; - s = 1; - - I = ind(:,end)'; - coeff_n = obj.a22(I); - coeff_t = obj.a12(I); - scale_factor = sqrt(obj.x_u(I).^2 + obj.y_u(I).^2); - otherwise - error('No such boundary: boundary = %s',boundary); - end - - switch boundary - case {'w','e'} - halfnorm_inv_n = obj.Hiu; - halfnorm_inv_t = obj.Hiv; - halfnorm_t = obj.Hv; - gamm = obj.gamm_u; - case {'s','n'} - halfnorm_inv_n = obj.Hiv; - halfnorm_inv_t = obj.Hiu; - halfnorm_t = obj.Hu; - gamm = obj.gamm_v; - end - end - - function N = size(obj) - N = prod(obj.m); - end - - - end -end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/error1d.m --- a/+scheme/error1d.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -function e = error1d(discr, v1, v2) - h = discr.h; - e = sqrt(h*sum((v1-v2).^2)); -end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/error2d.m --- a/+scheme/error2d.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -function e = error2d(discr, v1, v2) - % If v1 and v2 are more complex types, something like grid functions... Then we may use .getVectorFrom here! - h = discr.h; - e = sqrt(h.^2*sum((v1-v2).^2)); -end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/errorMax.m --- a/+scheme/errorMax.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -function e = errorMax(~, v1, v2) - e = max(abs(v1-v2)); -end
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/errorRelative.m --- a/+scheme/errorRelative.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -function e = errorRelative(~,v1,v2) - e = sqrt(sum((v1-v2).^2)/sum(v2.^2)); -end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/errorSbp.m --- a/+scheme/errorSbp.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ -function e = errorSbp(discr, v1, v2) - % If v1 and v2 are more complex types, something like grid functions... Then we may use .getVectorFrom here! - H = discr.H; - err = v2 - v1; - e = sqrt(err'*H*err); -end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +scheme/errorVector.m --- a/+scheme/errorVector.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3 +0,0 @@ -function e = errorVector(~, v1, v2) - e = v2-v1; -end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +time/+cdiff/cdiff.m --- a/+time/+cdiff/cdiff.m Wed Aug 07 13:28:21 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,16 +0,0 @@ -% Takes a step of -% v_tt = Dv+Ev_t+S -% -% 1/k^2 * (v_next - 2v + v_prev) = Dv + E 1/(2k)(v_next - v_prev) + S -% -function [v_next, v] = cdiff(v, v_prev, k, D, E, S) - % 1/k^2 * (v_next - 2v + v_prev) = Dv + E 1/(2k)(v_next - v_prev) + S - % ekv to - % A v_next = B v + C v_prev + S - I = speye(size(D)); - A = 1/k^2 * I - 1/(2*k)*E; - B = 2/k^2 * I + D; - C = -1/k^2 * I - 1/(2*k)*E; - - v_next = A\(B*v + C*v_prev + S); -end \ No newline at end of file
diff -r f6c571d8f22f -r 433c89bf19e0 +time/Cdiff.m --- a/+time/Cdiff.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+time/Cdiff.m Wed Aug 07 15:23:42 2019 +0200 @@ -1,36 +1,45 @@ classdef Cdiff < time.Timestepper properties - D - E - S + A, B, C + AA, BB, CC + G k t - v - v_prev + v, v_prev n end methods - % Solves u_tt = Du + Eu_t + S - % D, E, S can either all be constants or all be function handles, - % They can also be omitted by setting them equal to the empty matrix. - % Cdiff(D, E, S, k, t0, n0, v, v_prev) - function obj = Cdiff(D, E, S, k, t0, n0, v, v_prev) - m = length(v); - default_arg('E',sparse(m,m)); - default_arg('S',sparse(m,1)); + % Solves + % A*v_tt + B*v_t + C*v = G(t) + % v(t0) = v0 + % v_t(t0) = v0t + % starting at time t0 with timestep k + % Using + % A*Dp*Dm*v_n + B*D0*v_n + C*v_n = G(t_n) + function obj = Cdiff(A, B, C, G, v0, v0t, k, t0) + m = length(v0); + default_arg('A', speye(m)); + default_arg('B', sparse(m,m)); + default_arg('G', @(t) sparse(m,1)); + default_arg('t0', 0); - obj.D = D; - obj.E = E; - obj.S = S; + obj.A = A; + obj.B = B; + obj.C = C; + obj.G = G; + % Rewrite as AA*v_(n+1) + BB*v_n + CC*v_(n-1) = G(t_n) + obj.AA = A/k^2 + B/(2*k); + obj.BB = -2*A/k^2 + C; + obj.CC = A/k^2 - B/(2*k); obj.k = k; - obj.t = t0; - obj.n = n0; - obj.v = v; - obj.v_prev = v_prev; + obj.v_prev = v0; + obj.v = v0 + k*v0t; + obj.t = t0+k; + obj.n = 1; end function [v,t] = getV(obj) @@ -43,10 +52,21 @@ t = obj.t; end + function E = getEnergy(obj) + v = obj.v; + vp = obj.v_prev; + vt = (obj.v - obj.v_prev)/obj.k; + + E = vt'*obj.A*vt + v'*obj.C*vp; + end + function obj = step(obj) - [obj.v, obj.v_prev] = time.cdiff.cdiff(obj.v, obj.v_prev, obj.k, obj.D, obj.E, obj.S); + v_next = obj.AA\(-obj.BB*obj.v - obj.CC*obj.v_prev + obj.G(obj.t)); + + obj.v_prev = obj.v; + obj.v = v_next; obj.t = obj.t + obj.k; obj.n = obj.n + 1; end end -end \ No newline at end of file +end
diff -r f6c571d8f22f -r 433c89bf19e0 +time/CdiffImplicit.m --- a/+time/CdiffImplicit.m Wed Aug 07 13:28:21 2019 +0200 +++ b/+time/CdiffImplicit.m Wed Aug 07 15:23:42 2019 +0200 @@ -1,7 +1,8 @@ classdef CdiffImplicit < time.Timestepper properties - A, B, C, G + A, B, C AA, BB, CC + G k t v, v_prev @@ -13,59 +14,36 @@ methods % Solves - % A*u_tt + B*u + C*v_t = G(t) - % u(t0) = f1 - % u_t(t0) = f2 - % starting at time t0 with timestep k - function obj = CdiffImplicit(A, B, C, G, f1, f2, k, t0) - default_arg('A', []); - default_arg('C', []); - default_arg('G', []); - default_arg('f1', 0); - default_arg('f2', 0); + % A*v_tt + B*v_t + C*v = G(t) + % v(t0) = v0 + % v_t(t0) = v0t + % starting at time t0 with timestep + % Using + % A*Dp*Dm*v_n + B*D0*v_n + C*I0*v_n = G(t_n) + function obj = CdiffImplicit(A, B, C, G, v0, v0t, k, t0) + m = length(v0); + default_arg('A', speye(m)); + default_arg('B', sparse(m,m)); + default_arg('G', @(t) sparse(m,1)); default_arg('t0', 0); - m = size(B,1); - - if isempty(A) - A = speye(m); - end - - if isempty(C) - C = sparse(m,m); - end - - if isempty(G) - G = @(t) sparse(m,1); - end - - if isempty(f1) - f1 = sparse(m,1); - end - - if isempty(f2) - f2 = sparse(m,1); - end - obj.A = A; obj.B = B; obj.C = C; obj.G = G; - AA = 1/k^2*A + 1/2*B + 1/(2*k)*C; - BB = -2/k^2*A; - CC = 1/k^2*A + 1/2*B - 1/(2*k)*C; - % AA*v_next + BB*v + CC*v_prev == G(t_n) + % Rewrite as AA*v_(n+1) + BB*v_n + CC*v_(n-1) = G(t_n) + AA = A/k^2 + B/(2*k) + C/2; + BB = -2*A/k^2; + CC = A/k^2 - B/(2*k) + C/2; obj.AA = AA; obj.BB = BB; obj.CC = CC; - v_prev = f1; + v_prev = v0; I = speye(m); - % v = (1/k^2*A)\((1/k^2*A - 1/2*B)*f1 + (1/k*I - 1/2*C)*f2 + 1/2*G(0)); - v = f1 + k*f2; - + v = v0 + k*v0t; if ~issparse(A) || ~issparse(B) || ~issparse(C) error('LU factorization with full pivoting only works for sparse matrices.') @@ -78,7 +56,6 @@ obj.p = p; obj.q = q; - obj.k = k; obj.t = t0+k; obj.n = 1; @@ -92,17 +69,17 @@ end function [vt,t] = getVt(obj) - % Calculate next time step to be able to do centered diff. - v_next = zeros(size(obj.v)); - b = obj.G(obj.t) - obj.BB*obj.v - obj.CC*obj.v_prev; + vt = (obj.v-obj.v_prev)/obj.k; % Could be improved using u_tt = f(u)) + t = obj.t; + end - y = obj.L\b(obj.p); - z = obj.U\y; - v_next(obj.q) = z; + % Calculate the conserved energy (Dm*v_n)^2_A + Im*v_n^2_B + function E = getEnergy(obj) + v = obj.v; + vp = obj.v_prev; + vt = (obj.v - obj.v_prev)/obj.k; - - vt = (v_next-obj.v_prev)/(2*obj.k); - t = obj.t; + E = vt'*obj.A*vt + 1/2*(v'*obj.C*v + vp'*obj.C*vp); end function obj = step(obj) @@ -123,30 +100,3 @@ end end end - - - - - -%%% Derivation -% syms A B C G -% syms n k -% syms f1 f2 - -% v = symfun(sym('v(n)'),n); - - -% d = A/k^2 * (v(n+1) - 2*v(n) +v(n-1)) + B/2*(v(n+1)+v(n-1)) + C/(2*k)*(v(n+1) - v(n-1)) == G -% ic1 = v(0) == f1 -% ic2 = A/k*(v(1)-f1) + k/2*(B*f1 + C*f2 - G) - f2 == 0 - -% c = collect(d, [v(n) v(n-1) v(n+1)]) % (-(2*A)/k^2)*v(n) + (B/2 + A/k^2 - C/(2*k))*v(n - 1) + (B/2 + A/k^2 + C/(2*k))*v(n + 1) == G -% syms AA BB CC -% % AA = B/2 + A/k^2 + C/(2*k) -% % BB = -(2*A)/k^2 -% % CC = B/2 + A/k^2 - C/(2*k) -% s = subs(c, [B/2 + A/k^2 + C/(2*k), -(2*A)/k^2, B/2 + A/k^2 - C/(2*k)], [AA, BB, CC]) - - -% ic2_a = collect(ic2, [v(1) f1 f2]) % (A/k)*v(1) + ((B*k)/2 - A/k)*f1 + ((C*k)/2 - 1)*f2 - (G*k)/2 == 0 -
diff -r f6c571d8f22f -r 433c89bf19e0 arrowAnnotation.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/arrowAnnotation.m Wed Aug 07 15:23:42 2019 +0200 @@ -0,0 +1,23 @@ +% Draw an arrow from p1 to p2, with text attached +function [h] = arrowAnnotation(p1,p2) + ah = gca; + xl = ah.XLim(1); + xr = ah.XLim(2); + + yl = ah.YLim(1); + yr = ah.YLim(2); + + dx = xr - xl; + dy = yr - yl; + + s = [ + ah.Position(1) + (p1(1) - xl)/dx*ah.Position(3), + ah.Position(1) + (p2(1) - xl)/dx*ah.Position(3), + ]; + t = [ + ah.Position(2) + (p1(2) - yl)/dy*ah.Position(4), + ah.Position(2) + (p2(2) - yl)/dy*ah.Position(4), + ]; + + h = annotation('arrow', s, t); +end
diff -r f6c571d8f22f -r 433c89bf19e0 assertLength.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/assertLength.m Wed Aug 07 15:23:42 2019 +0200 @@ -0,0 +1,4 @@ +function assertLength(A,l) + assert(isvector(A), sprintf('Expected ''%s'' to be a vector, got matrix of size %s',inputname(1), toString(size(A)))); + assert(length(A) == l, sprintf('Expected ''%s'' to have length %d, got %d', inputname(1), l, length(A))); +end
diff -r f6c571d8f22f -r 433c89bf19e0 assertSize.m --- a/assertSize.m Wed Aug 07 13:28:21 2019 +0200 +++ b/assertSize.m Wed Aug 07 15:23:42 2019 +0200 @@ -2,13 +2,13 @@ function assertSize(A,varargin) if length(varargin) == 1 s = varargin{1}; - errmsg = sprintf('Expected %s to have size %s, got: %s',inputname(1), toString(s), toString(size(A))); - assert(all(size(A) == s), errmsg); + assert(length(size(A)) == length(s), sprintf('Expected ''%s'' to have dimension %d, got %d', inputname(1), length(s), length(size(A)))); + assert(all(size(A) == s), sprintf('Expected ''%s'' to have size %s, got: %s',inputname(1), toString(s), toString(size(A)))); elseif length(varargin) == 2 dim = varargin{1}; s = varargin{2}; - errmsg = sprintf('Expected %s to have size %d along dimension %d, got: %d',inputname(1), s, dim, size(A,dim)); + errmsg = sprintf('Expected ''%s'' to have size %d along dimension %d, got: %d',inputname(1), s, dim, size(A,dim)); assert(size(A,dim) == s, errmsg); else error('Expected 2 or 3 arguments to assertSize()');
diff -r f6c571d8f22f -r 433c89bf19e0 runtestsAll.m --- a/runtestsAll.m Wed Aug 07 13:28:21 2019 +0200 +++ b/runtestsAll.m Wed Aug 07 15:23:42 2019 +0200 @@ -15,7 +15,7 @@ rootSuite = matlab.unittest.TestSuite.fromFolder(pwd); packageSuites = {}; for i = 1:length(packages) - packageSuites{i} = matlab.unittest.TestSuite.fromPackage(packages{i}); + packageSuites{i} = matlab.unittest.TestSuite.fromPackage(packages{i}, 'IncludingSubpackages', true); end ts = [rootSuite, packageSuites{:}];
diff -r f6c571d8f22f -r 433c89bf19e0 runtestsPackage.m --- a/runtestsPackage.m Wed Aug 07 13:28:21 2019 +0200 +++ b/runtestsPackage.m Wed Aug 07 15:23:42 2019 +0200 @@ -1,4 +1,4 @@ function res = runtestsPackage(pkgName) - ts = matlab.unittest.TestSuite.fromPackage(pkgName); + ts = matlab.unittest.TestSuite.fromPackage(pkgName, 'IncludingSubpackages', true); res = ts.run(); -end \ No newline at end of file +end
diff -r f6c571d8f22f -r 433c89bf19e0 show.m --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/show.m Wed Aug 07 15:23:42 2019 +0200 @@ -0,0 +1,5 @@ +function show(str) + assertType(str, {'string', 'char'}) + val = evalin('caller',str); + fprintf('%s => %s\n\n', str, toString(val)); +end \ No newline at end of file