Mercurial > repos > public > sbplib
view +scheme/Beam2d.m @ 998:2b1b944deae1 feature/getBoundaryOp
Add getBoundaryOperator to all 1d schemes. Did not add getBoundaryQuadrature because it doesnt make sense in 1d (?)
author | Martin Almquist <malmquist@stanford.edu> |
---|---|
date | Sat, 12 Jan 2019 13:35:19 -0800 |
parents | 78db023a7fe3 |
children |
line wrap: on
line source
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] = obj.getBoundaryOperator({'e', 'd1', 'd2', 'd3'}, boundary); s = obj.getBoundarySign(boundary); [gamm, delt] = obj.getBoundaryBorrowing(boundary); halfnorm_inv = obj.getHalfnormInv(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] = obj.getBoundaryOperator({'e', 'd1', 'd2', 'd3'}, boundary); s_u = obj.getBoundarySign(boundary); [gamm_u, delt_u] = obj.getBoundaryBorrowing(boundary); halfnorm_inv = obj.getHalfnormInv(boundary); [e_v, d1_v, d2_v, d3_v] = neighbour_scheme.getBoundaryOperator({'e', 'd1', 'd2', 'd3'}, neighbour_boundary); s_v = neighbour_scheme.getBoundarySign(neighbour_boundary); [gamm_v, delt_v] = neighbour_scheme.getBoundaryBorrowing(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 % 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 'w' e = obj.e_w; case 'e' e = obj.e_e; case 's' e = obj.e_s; case 'n' e = obj.e_n; otherwise error('No such boundary: boundary = %s',boundary); end varargout{i} = e; case 'd1' switch boundary case 'w' d1 = obj.d1_w; case 'e' d1 = obj.d1_e; case 's' d1 = obj.d1_s; case 'n' d1 = obj.d1_n; otherwise error('No such boundary: boundary = %s',boundary); end varargout{i} = d1; end case 'd2' switch boundary case 'w' d2 = obj.d2_w; case 'e' d2 = obj.d2_e; case 's' d2 = obj.d2_s; case 'n' d2 = obj.d2_n; otherwise error('No such boundary: boundary = %s',boundary); end varargout{i} = d2; end case 'd3' switch boundary case 'w' d3 = obj.d3_w; case 'e' d3 = obj.d3_e; case 's' d3 = obj.d3_s; case 'n' d3 = obj.d3_n; otherwise error('No such boundary: boundary = %s',boundary); end varargout{i} = d3; 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) switch boundary case 'w' H_b = obj.H_y; case 'e' H_b = obj.H_y; case 's' H_b = obj.H_x; case 'n' H_b = obj.H_x; 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) switch boundary case {'e','n'} s = 1; case {'w','s'} s = -1; otherwise error('No such boundary: boundary = %s',boundary); end end % Returns the halfnorm_inv used in SATs. TODO: better notation function Hinv = getHalfnormInv(obj, boundary) switch boundary case 'w' Hinv = obj.Hix; case 'e' Hinv = obj.Hix; case 's' Hinv = obj.Hiy; case 'n' Hinv = obj.Hiy; otherwise error('No such boundary: boundary = %s',boundary); end end % Returns borrowing constant gamma % boundary -- string function [gamm, delt] = getBoundaryBorrowing(obj, boundary) switch boundary case {'w','e'} gamm = obj.gamm_x; delt = obj.delt_x; case {'s','n'} gamm = obj.gamm_y; delt = obj.delt_y; otherwise error('No such boundary: boundary = %s',boundary); end end function N = size(obj) N = prod(obj.m); end end end