Mercurial > repos > public > sbplib
changeset 1086:90c23fd08f59 feature/laplace_curvilinear_test
Make LaplaceCurvilinearNew the default version and remove the others
author | Martin Almquist <malmquist@stanford.edu> |
---|---|
date | Fri, 29 Mar 2019 14:41:36 -0700 |
parents | 49c0b8c7330a |
children | 867307f4d80f |
files | +scheme/LaplaceCurvilinear.m +scheme/LaplaceCurvilinearNew.m +scheme/LaplaceCurvilinearNewCorner.m |
diffstat | 3 files changed, 178 insertions(+), 1256 deletions(-) [+] |
line wrap: on
line diff
diff -r 49c0b8c7330a -r 90c23fd08f59 +scheme/LaplaceCurvilinear.m --- a/+scheme/LaplaceCurvilinear.m Fri Mar 29 14:24:39 2019 -0700 +++ b/+scheme/LaplaceCurvilinear.m Fri Mar 29 14:41:36 2019 -0700 @@ -2,10 +2,11 @@ properties m % Number of points in each direction, possibly a vector h % Grid spacing + dim % Number of spatial dimensions grid - order % Order accuracy for the approximation + order % Order of accuracy for the approximation a,b % Parameters of the operator @@ -22,10 +23,12 @@ % Metric coefficients J, Ji a11, a12, a22 + K x_u x_v y_u y_v + s_w, s_e, s_s, s_n % Boundary integral scale factors % Inner product and operators for logical coordinates H_u, H_v % Norms in the x and y directions @@ -36,8 +39,15 @@ du_e, dv_e du_s, dv_s du_n, dv_n + + % Borrowing constants + theta_M_u, theta_M_v + theta_R_u, theta_R_v + theta_H_u, theta_H_v + + % Temporary + lambda gamm_u, gamm_v - lambda end @@ -45,14 +55,10 @@ % Implements a*div(b*grad(u)) as a SBP scheme % TODO: Implement proper H, it should be the real physical quadrature, the logic quadrature may be but in a separate variable (H_logic?) - function obj = LaplaceCurvilinear(g ,order, a, b, opSet) + function obj = LaplaceCurvilinear(g, order, a, b, opSet) default_arg('opSet',@sbp.D2Variable); default_arg('a', 1); - default_arg('b', 1); - - if b ~=1 - error('Not implemented yet') - end + default_arg('b', @(x,y) 0*x + 1); % assert(isa(g, 'grid.Curvilinear')) if isa(a, 'function_handle') @@ -60,6 +66,17 @@ a = spdiag(a); end + if isa(b, 'function_handle') + b = grid.evalOn(g, b); + b = spdiag(b); + end + + % If b is scalar + if length(b) == 1 + b = b*speye(g.N(), g.N()); + end + + dim = 2; m = g.size(); m_u = m(1); m_v = m(2); @@ -134,29 +151,37 @@ a22 = 1./J .* (x_u.^2 + y_u.^2); lambda = 1/2 * (a11 + a22 - sqrt((a11-a22).^2 + 4*a12.^2)); + K = cell(dim, dim); + K{1,1} = spdiag(y_v./J); + K{1,2} = spdiag(-y_u./J); + K{2,1} = spdiag(-x_v./J); + K{2,2} = spdiag(x_u./J); + obj.K = K; + obj.x_u = x_u; obj.x_v = x_v; obj.y_u = y_u; obj.y_v = y_v; - % Assemble full operators L_12 = spdiag(a12); - Duv = Du*L_12*Dv; - Dvu = Dv*L_12*Du; + Duv = Du*b*L_12*Dv; + Dvu = Dv*b*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))); + b_a11 = b*a11; + D = D2_u(b_a11(ind(:,i))); p = ind(:,i); Duu(p,p) = D; end for i = 1:m_u - D = D2_v(a22(ind(i,:))); + b_a22 = b*a22; + D = D2_v(b_a22(ind(i,:))); p = ind(i,:); Dvv(p,p) = D; end @@ -214,14 +239,29 @@ obj.h = [h_u h_v]; obj.order = order; obj.grid = g; + obj.dim = dim; obj.a = a; obj.b = b; obj.a11 = a11; obj.a12 = a12; obj.a22 = a22; + obj.s_w = spdiag(s_w); + obj.s_e = spdiag(s_e); + obj.s_s = spdiag(s_s); + obj.s_n = spdiag(s_n); + + obj.theta_M_u = h_u*ops_u.borrowing.M.d1; + obj.theta_M_v = h_v*ops_v.borrowing.M.d1; + + obj.theta_R_u = h_u*ops_u.borrowing.R.delta_D; + obj.theta_R_v = h_v*ops_v.borrowing.R.delta_D; + + obj.theta_H_u = h_u*ops_u.borrowing.H11; + obj.theta_H_v = h_v*ops_v.borrowing.H11; + + % Temporary obj.lambda = lambda; - obj.gamm_u = h_u*ops_u.borrowing.M.d1; obj.gamm_v = h_v*ops_v.borrowing.M.d1; end @@ -238,34 +278,46 @@ default_arg('type','neumann'); default_arg('parameter', []); - [e, d] = obj.getBoundaryOperator({'e', 'd'}, boundary); + e = obj.getBoundaryOperator('e', boundary); + d = obj.getBoundaryOperator('d', boundary); H_b = obj.getBoundaryQuadrature(boundary); - gamm = obj.getBoundaryBorrowing(boundary); + s_b = obj.getBoundaryScaling(boundary); + [th_H, ~, th_R] = obj.getBoundaryBorrowing(boundary); + m = obj.getBoundaryNumber(boundary); + + K = obj.K; + J = obj.J; + Hi = obj.Hi; + a = obj.a; + b_b = e'*obj.b*e; + switch type % Dirichlet boundary condition case {'D','d','dirichlet'} tuning = 1.0; - b1 = gamm*obj.lambda./obj.a11.^2; - b2 = gamm*obj.lambda./obj.a22.^2; + sigma = 0*b_b; + for i = 1:obj.dim + sigma = sigma + e'*J*K{i,m}*K{i,m}*e; + end + sigma = sigma/s_b; + tau = tuning*(1/th_R + obj.dim/th_H)*sigma; - tau1 = tuning * spdiag(-1./b1 - 1./b2); - tau2 = 1; + closure = a*Hi*d*b_b*H_b*e' ... + -a*Hi*e*tau*b_b*H_b*e'; - tau = (tau1*e + tau2*d)*H_b; - - closure = obj.a*obj.Hi*tau*e'; - penalty = -obj.a*obj.Hi*tau; + penalty = -a*Hi*d*b_b*H_b ... + +a*Hi*e*tau*b_b*H_b; - % Neumann boundary condition + % Neumann boundary condition. Note that the penalty is for du/dn and not b*du/dn. case {'N','n','neumann'} tau1 = -1; tau2 = 0; tau = (tau1*e + tau2*d)*H_b; - closure = obj.a*obj.Hi*tau*d'; - penalty = -obj.a*obj.Hi*tau; + closure = a*Hi*tau*b_b*d'; + penalty = -a*Hi*tau*b_b; % Unknown, boundary condition @@ -280,7 +332,9 @@ % -- interpolation: type of interpolation, default 'none' function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary,type) - defaultType.tuning = 1.2; + % error('Not implemented') + + defaultType.tuning = 1.0; defaultType.interpolation = 'none'; default_struct('type', defaultType); @@ -297,44 +351,77 @@ function [closure, penalty] = interfaceStandard(obj,boundary,neighbour_scheme,neighbour_boundary,type) tuning = type.tuning; + dim = obj.dim; % u denotes the solution in the own domain % v denotes the solution in the neighbour domain - [e_u, d_u] = obj.getBoundaryOperator({'e', 'd'}, boundary); - H_b_u = obj.getBoundaryQuadrature(boundary); - I_u = obj.getBoundaryIndices(boundary); - gamm_u = obj.getBoundaryBorrowing(boundary); - - [e_v, d_v] = neighbour_scheme.getBoundaryOperator({'e', '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; - 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; + % Boundary operators, u + e_u = u.getBoundaryOperator('e', boundary); + d_u = u.getBoundaryOperator('d', boundary); + gamm_u = u.getBoundaryBorrowing(boundary); + s_b_u = u.getBoundaryScaling(boundary); + [th_H_u, ~, th_R_u] = u.getBoundaryBorrowing(boundary); + m_u = u.getBoundaryNumber(boundary); + + % Coefficients, u + K_u = u.K; + J_u = u.J; + b_b_u = e_u'*u.b*e_u; - tau1 = -1./(4*b1_u) -1./(4*b1_v) -1./(4*b2_u) -1./(4*b2_v); - tau1 = tuning * spdiag(tau1); - tau2 = 1/2; + % Boundary operators, v + e_v = v.getBoundaryOperator('e', neighbour_boundary); + d_v = v.getBoundaryOperator('d', neighbour_boundary); + gamm_v = v.getBoundaryBorrowing(neighbour_boundary); + s_b_v = v.getBoundaryScaling(neighbour_boundary); + [th_H_v, ~, th_R_v] = v.getBoundaryBorrowing(neighbour_boundary); + m_v = v.getBoundaryNumber(neighbour_boundary); + + % Coefficients, v + K_v = v.K; + J_v = v.J; + b_b_v = e_v'*v.b*e_v; - sig1 = -1/2; - sig2 = 0; + %--- Penalty strength tau ------------- + sigma_u = 0*b_b_u; + sigma_v = 0*b_b_v; + for i = 1:obj.dim + sigma_u = sigma_u + e_u'*J_u*K_u{i,m_u}*K_u{i,m_u}*e_u; + sigma_v = sigma_v + e_v'*J_v*K_v{i,m_v}*K_v{i,m_v}*e_v; + end + sigma_u = sigma_u/s_b_u; + sigma_v = sigma_v/s_b_v; + + tau_R_u = 1/th_R_u*sigma_u; + tau_R_v = 1/th_R_v*sigma_v; + + tau_H_u = dim*1/th_H_u*sigma_u; + tau_H_v = dim*1/th_H_v*sigma_v; - tau = (e_u*tau1 + tau2*d_u)*H_b_u; - sig = (sig1*e_u + sig2*d_u)*H_b_u; + tau = 1/4*tuning*(b_b_u*(tau_R_u + tau_H_u) + b_b_v*(tau_R_v + tau_H_v)); + %-------------------------------------- + + % Operators/coefficients that are only required from this side + Hi = u.Hi; + H_b = u.getBoundaryQuadrature(boundary); + a = u.a; - closure = obj.a*obj.Hi*( tau*e_u' + sig*d_u'); - penalty = obj.a*obj.Hi*(-tau*e_v' + sig*d_v'); + closure = 1/2*a*Hi*d_u*b_b_u*H_b*e_u' ... + -1/2*a*Hi*e_u*H_b*b_b_u*d_u' ... + -a*Hi*e_u*tau*H_b*e_u'; + + penalty = -1/2*a*Hi*d_u*b_b_u*H_b*e_v' ... + -1/2*a*Hi*e_u*H_b*b_b_v*d_v' ... + +a*Hi*e_u*tau*H_b*e_v'; end function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type) % TODO: Make this work for curvilinear grids warning('LaplaceCurvilinear: Non-conforming grid interpolation only works for Cartesian grids.'); + warning('LaplaceCurvilinear: Non-conforming interface uses Virtas penalty strength'); + warning('LaplaceCurvilinear: Non-conforming interface assumes that b is constant'); % User can request special interpolation operators by specifying type.interpOpSet default_field(type, 'interpOpSet', @sbp.InterpOpsOP); @@ -344,12 +431,14 @@ % u denotes the solution in the own domain % v denotes the solution in the neighbour domain - [e_u, d_u] = obj.getBoundaryOperator({'e', 'd'}, 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, d_v] = neighbour_scheme.getBoundaryOperator({'e', 'd'}, neighbour_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); @@ -395,47 +484,13 @@ end % Returns the boundary operator op for the boundary specified by the string boundary. - % op -- string or a cell array of strings + % op -- string % boundary -- string - function varargout = getBoundaryOperator(obj, op, boundary) - - if ~iscell(op) - op = {op}; - end + function o = getBoundaryOperator(obj, op, boundary) + assertIsMember(op, {'e', 'd'}) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) - 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 '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; - otherwise - error('No such boundary: boundary = %s',boundary); - end - varargout{i} = d; - end - end + o = obj.([op, '_', boundary]); end % Returns square boundary quadrature matrix, of dimension @@ -443,18 +498,32 @@ % % boundary -- string function H_b = getBoundaryQuadrature(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + H_b = obj.(['H_', boundary]); + end + + % Returns square boundary quadrature scaling matrix, of dimension + % corresponding to the number of boundary points + % + % boundary -- string + function s_b = getBoundaryScaling(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) + + s_b = obj.(['s_', boundary]); + end + + % Returns the coordinate number corresponding to the boundary + % + % boundary -- string + function m = getBoundaryNumber(obj, boundary) + assertIsMember(boundary, {'w', 'e', 's', 'n'}) switch boundary - case 'w' - H_b = obj.H_w; - case 'e' - H_b = obj.H_e; - case 's' - H_b = obj.H_s; - case 'n' - H_b = obj.H_n; - otherwise - error('No such boundary: boundary = %s',boundary); + case {'w', 'e'} + m = 1; + case {'s', 'n'} + m = 2; end end @@ -478,12 +547,16 @@ % Returns borrowing constant gamma % boundary -- string - function gamm = getBoundaryBorrowing(obj, boundary) + function [theta_H, theta_M, theta_R] = getBoundaryBorrowing(obj, boundary) switch boundary case {'w','e'} - gamm = obj.gamm_u; + theta_H = obj.theta_H_u; + theta_M = obj.theta_M_u; + theta_R = obj.theta_R_u; case {'s','n'} - gamm = obj.gamm_v; + theta_H = obj.theta_H_v; + theta_M = obj.theta_M_v; + theta_R = obj.theta_R_v; otherwise error('No such boundary: boundary = %s',boundary); end
diff -r 49c0b8c7330a -r 90c23fd08f59 +scheme/LaplaceCurvilinearNew.m --- a/+scheme/LaplaceCurvilinearNew.m Fri Mar 29 14:24:39 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,569 +0,0 @@ -classdef LaplaceCurvilinearNew < scheme.Scheme - properties - m % Number of points in each direction, possibly a vector - h % Grid spacing - dim % Number of spatial dimensions - - grid - - order % Order of accuracy for the approximation - - a,b % Parameters of the operator - - - % Inner products and operators for physical coordinates - D % Laplace operator - H, Hi % Inner product - e_w, e_e, e_s, e_n - d_w, d_e, d_s, d_n % Normal derivatives at the boundary - H_w, H_e, H_s, H_n % Boundary inner products - Dx, Dy % Physical derivatives - M % Gradient inner product - - % Metric coefficients - J, Ji - a11, a12, a22 - K - x_u - x_v - y_u - y_v - s_w, s_e, s_s, s_n % Boundary integral scale factors - - % Inner product and operators for logical coordinates - H_u, H_v % Norms in the x and y directions - Hi_u, Hi_v - Hu,Hv % Kroneckerd norms. 1'*Hx*v corresponds to integration in the x dir. - Hiu, Hiv - du_w, dv_w - du_e, dv_e - du_s, dv_s - du_n, dv_n - - % Borrowing constants - theta_M_u, theta_M_v - theta_R_u, theta_R_v - theta_H_u, theta_H_v - - % Temporary - lambda - gamm_u, gamm_v - - end - - methods - % Implements a*div(b*grad(u)) as a SBP scheme - % TODO: Implement proper H, it should be the real physical quadrature, the logic quadrature may be but in a separate variable (H_logic?) - - function obj = LaplaceCurvilinearNew(g, order, a, b, opSet) - default_arg('opSet',@sbp.D2Variable); - default_arg('a', 1); - default_arg('b', @(x,y) 0*x + 1); - - % assert(isa(g, 'grid.Curvilinear')) - if isa(a, 'function_handle') - a = grid.evalOn(g, a); - a = spdiag(a); - end - - if isa(b, 'function_handle') - b = grid.evalOn(g, b); - b = spdiag(b); - end - - % If b is scalar - if length(b) == 1 - b = b*speye(g.N(), g.N()); - end - - dim = 2; - 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); - - - % 1D 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; - - - % Logical operators - Du = kr(D1_u,I_v); - Dv = kr(I_u,D1_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); - - e_w = kr(e_l_u,I_v); - e_e = kr(e_r_u,I_v); - e_s = kr(I_u,e_l_v); - e_n = kr(I_u,e_r_v); - obj.du_w = kr(d1_l_u,I_v); - obj.dv_w = (e_w'*Dv)'; - obj.du_e = kr(d1_r_u,I_v); - obj.dv_e = (e_e'*Dv)'; - obj.du_s = (e_s'*Du)'; - obj.dv_s = kr(I_u,d1_l_v); - obj.du_n = (e_n'*Du)'; - obj.dv_n = kr(I_u,d1_r_v); - - - % Metric coefficients - 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)); - - K = cell(dim, dim); - K{1,1} = spdiag(y_v./J); - K{1,2} = spdiag(-y_u./J); - K{2,1} = spdiag(-x_v./J); - K{2,2} = spdiag(x_u./J); - obj.K = K; - - obj.x_u = x_u; - obj.x_v = x_v; - obj.y_u = y_u; - obj.y_v = y_v; - - % Assemble full operators - L_12 = spdiag(a12); - Duv = Du*b*L_12*Dv; - Dvu = Dv*b*L_12*Du; - - Duu = sparse(m_tot); - Dvv = sparse(m_tot); - ind = grid.funcToMatrix(g, 1:m_tot); - - for i = 1:m_v - b_a11 = b*a11; - D = D2_u(b_a11(ind(:,i))); - p = ind(:,i); - Duu(p,p) = D; - end - - for i = 1:m_u - b_a22 = b*a22; - D = D2_v(b_a22(ind(i,:))); - p = ind(i,:); - Dvv(p,p) = D; - end - - - % Physical operators - obj.J = spdiag(J); - obj.Ji = spdiag(1./J); - - obj.D = obj.Ji*a*(Duu + Duv + Dvu + Dvv); - obj.H = obj.J*kr(H_u,H_v); - obj.Hi = obj.Ji*kr(Hi_u,Hi_v); - - obj.e_w = e_w; - obj.e_e = e_e; - obj.e_s = e_s; - obj.e_n = e_n; - - %% normal derivatives - I_w = ind(1,:); - I_e = ind(end,:); - I_s = ind(:,1); - I_n = ind(:,end); - - a11_w = spdiag(a11(I_w)); - a12_w = spdiag(a12(I_w)); - a11_e = spdiag(a11(I_e)); - a12_e = spdiag(a12(I_e)); - a22_s = spdiag(a22(I_s)); - a12_s = spdiag(a12(I_s)); - a22_n = spdiag(a22(I_n)); - a12_n = spdiag(a12(I_n)); - - s_w = sqrt((e_w'*x_v).^2 + (e_w'*y_v).^2); - s_e = sqrt((e_e'*x_v).^2 + (e_e'*y_v).^2); - s_s = sqrt((e_s'*x_u).^2 + (e_s'*y_u).^2); - s_n = sqrt((e_n'*x_u).^2 + (e_n'*y_u).^2); - - obj.d_w = -1*(spdiag(1./s_w)*(a11_w*obj.du_w' + a12_w*obj.dv_w'))'; - obj.d_e = (spdiag(1./s_e)*(a11_e*obj.du_e' + a12_e*obj.dv_e'))'; - obj.d_s = -1*(spdiag(1./s_s)*(a22_s*obj.dv_s' + a12_s*obj.du_s'))'; - obj.d_n = (spdiag(1./s_n)*(a22_n*obj.dv_n' + a12_n*obj.du_n'))'; - - obj.Dx = spdiag( y_v./J)*Du + spdiag(-y_u./J)*Dv; - obj.Dy = spdiag(-x_v./J)*Du + spdiag( x_u./J)*Dv; - - %% Boundary inner products - obj.H_w = H_v*spdiag(s_w); - obj.H_e = H_v*spdiag(s_e); - obj.H_s = H_u*spdiag(s_s); - obj.H_n = H_u*spdiag(s_n); - - % Misc. - obj.m = m; - obj.h = [h_u h_v]; - obj.order = order; - obj.grid = g; - obj.dim = dim; - - obj.a = a; - obj.b = b; - obj.a11 = a11; - obj.a12 = a12; - obj.a22 = a22; - obj.s_w = spdiag(s_w); - obj.s_e = spdiag(s_e); - obj.s_s = spdiag(s_s); - obj.s_n = spdiag(s_n); - - obj.theta_M_u = h_u*ops_u.borrowing.M.d1; - obj.theta_M_v = h_v*ops_v.borrowing.M.d1; - - obj.theta_R_u = h_u*ops_u.borrowing.R.delta_D; - obj.theta_R_v = h_v*ops_v.borrowing.R.delta_D; - - obj.theta_H_u = h_u*ops_u.borrowing.H11; - obj.theta_H_v = h_v*ops_v.borrowing.H11; - - % Temporary - obj.lambda = lambda; - 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 = obj.getBoundaryOperator('e', boundary); - d = obj.getBoundaryOperator('d', boundary); - H_b = obj.getBoundaryQuadrature(boundary); - s_b = obj.getBoundaryScaling(boundary); - [th_H, ~, th_R] = obj.getBoundaryBorrowing(boundary); - m = obj.getBoundaryNumber(boundary); - - K = obj.K; - J = obj.J; - Hi = obj.Hi; - a = obj.a; - b_b = e'*obj.b*e; - - switch type - % Dirichlet boundary condition - case {'D','d','dirichlet'} - tuning = 1.0; - - sigma = 0*b_b; - for i = 1:obj.dim - sigma = sigma + e'*J*K{i,m}*K{i,m}*e; - end - sigma = sigma/s_b; - tau = tuning*(1/th_R + obj.dim/th_H)*sigma; - - closure = a*Hi*d*b_b*H_b*e' ... - -a*Hi*e*tau*b_b*H_b*e'; - - penalty = -a*Hi*d*b_b*H_b ... - +a*Hi*e*tau*b_b*H_b; - - - % Neumann boundary condition. Note that the penalty is for du/dn and not b*du/dn. - case {'N','n','neumann'} - tau1 = -1; - tau2 = 0; - tau = (tau1*e + tau2*d)*H_b; - - closure = a*Hi*tau*b_b*d'; - penalty = -a*Hi*tau*b_b; - - - % Unknown, boundary condition - otherwise - error('No such boundary condition: type = %s',type); - end - end - - % 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) - - % error('Not implemented') - - defaultType.tuning = 1.0; - 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; - - dim = obj.dim; - % u denotes the solution in the own domain - % v denotes the solution in the neighbour domain - u = obj; - v = neighbour_scheme; - - % Boundary operators, u - e_u = u.getBoundaryOperator('e', boundary); - d_u = u.getBoundaryOperator('d', boundary); - gamm_u = u.getBoundaryBorrowing(boundary); - s_b_u = u.getBoundaryScaling(boundary); - [th_H_u, ~, th_R_u] = u.getBoundaryBorrowing(boundary); - m_u = u.getBoundaryNumber(boundary); - - % Coefficients, u - K_u = u.K; - J_u = u.J; - b_b_u = e_u'*u.b*e_u; - - % Boundary operators, v - e_v = v.getBoundaryOperator('e', neighbour_boundary); - d_v = v.getBoundaryOperator('d', neighbour_boundary); - gamm_v = v.getBoundaryBorrowing(neighbour_boundary); - s_b_v = v.getBoundaryScaling(neighbour_boundary); - [th_H_v, ~, th_R_v] = v.getBoundaryBorrowing(neighbour_boundary); - m_v = v.getBoundaryNumber(neighbour_boundary); - - % Coefficients, v - K_v = v.K; - J_v = v.J; - b_b_v = e_v'*v.b*e_v; - - %--- Penalty strength tau ------------- - sigma_u = 0*b_b_u; - sigma_v = 0*b_b_v; - for i = 1:obj.dim - sigma_u = sigma_u + e_u'*J_u*K_u{i,m_u}*K_u{i,m_u}*e_u; - sigma_v = sigma_v + e_v'*J_v*K_v{i,m_v}*K_v{i,m_v}*e_v; - end - sigma_u = sigma_u/s_b_u; - sigma_v = sigma_v/s_b_v; - - tau_R_u = 1/th_R_u*sigma_u; - tau_R_v = 1/th_R_v*sigma_v; - - tau_H_u = dim*1/th_H_u*sigma_u; - tau_H_v = dim*1/th_H_v*sigma_v; - - tau = 1/4*tuning*(b_b_u*(tau_R_u + tau_H_u) + b_b_v*(tau_R_v + tau_H_v)); - %-------------------------------------- - - % Operators/coefficients that are only required from this side - Hi = u.Hi; - H_b = u.getBoundaryQuadrature(boundary); - a = u.a; - - closure = 1/2*a*Hi*d_u*b_b_u*H_b*e_u' ... - -1/2*a*Hi*e_u*H_b*b_b_u*d_u' ... - -a*Hi*e_u*tau*H_b*e_u'; - - penalty = -1/2*a*Hi*d_u*b_b_u*H_b*e_v' ... - -1/2*a*Hi*e_u*H_b*b_b_v*d_v' ... - +a*Hi*e_u*tau*H_b*e_v'; - end - - function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type) - - % TODO: Make this work for curvilinear grids - warning('LaplaceCurvilinear: Non-conforming grid interpolation only works for Cartesian grids.'); - warning('LaplaceCurvilinear: Non-conforming interface uses Virtas penalty strength'); - warning('LaplaceCurvilinear: Non-conforming interface assumes that b is constant'); - - % User can request special interpolation operators by specifying type.interpOpSet - default_field(type, 'interpOpSet', @sbp.InterpOpsOP); - interpOpSet = type.interpOpSet; - tuning = type.tuning; - - - % 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); - 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); - m_v = size(e_v, 2); - - Hi = obj.Hi; - a = obj.a; - - 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_u = -1./(4*b1_u) -1./(4*b2_u); - tau_v = -1./(4*b1_v) -1./(4*b2_v); - - tau_u = tuning * spdiag(tau_u); - tau_v = tuning * spdiag(tau_v); - beta_u = tau_v; - - % Build interpolation operators - intOps = interpOpSet(m_u, m_v, obj.order, neighbour_scheme.order); - Iu2v = intOps.Iu2v; - Iv2u = intOps.Iv2u; - - closure = a*Hi*e_u*tau_u*H_b_u*e_u' + ... - a*Hi*e_u*H_b_u*Iv2u.bad*beta_u*Iu2v.good*e_u' + ... - a*1/2*Hi*d_u*H_b_u*e_u' + ... - -a*1/2*Hi*e_u*H_b_u*d_u'; - - penalty = -a*Hi*e_u*tau_u*H_b_u*Iv2u.good*e_v' + ... - -a*Hi*e_u*H_b_u*Iv2u.bad*beta_u*e_v' + ... - -a*1/2*Hi*d_u*H_b_u*Iv2u.good*e_v' + ... - -a*1/2*Hi*e_u*H_b_u*Iv2u.bad*d_v'; - - 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', '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 - % - % boundary -- string - function H_b = getBoundaryQuadrature(obj, boundary) - assertIsMember(boundary, {'w', 'e', 's', 'n'}) - - H_b = obj.(['H_', boundary]); - end - - % Returns square boundary quadrature scaling matrix, of dimension - % corresponding to the number of boundary points - % - % boundary -- string - function s_b = getBoundaryScaling(obj, boundary) - assertIsMember(boundary, {'w', 'e', 's', 'n'}) - - s_b = obj.(['s_', boundary]); - end - - % Returns the coordinate number corresponding to the boundary - % - % boundary -- string - function m = getBoundaryNumber(obj, boundary) - assertIsMember(boundary, {'w', 'e', 's', 'n'}) - - switch boundary - case {'w', 'e'} - m = 1; - case {'s', 'n'} - m = 2; - end - end - - % Returns the indices of the boundary points in the grid matrix - % boundary -- string - function I = getBoundaryIndices(obj, boundary) - ind = grid.funcToMatrix(obj.grid, 1:prod(obj.m)); - switch boundary - case 'w' - I = ind(1,:); - case 'e' - I = ind(end,:); - case 's' - I = ind(:,1)'; - case 'n' - I = ind(:,end)'; - otherwise - error('No such boundary: boundary = %s',boundary); - end - end - - % Returns borrowing constant gamma - % boundary -- string - function [theta_H, theta_M, theta_R] = getBoundaryBorrowing(obj, boundary) - switch boundary - case {'w','e'} - theta_H = obj.theta_H_u; - theta_M = obj.theta_M_u; - theta_R = obj.theta_R_u; - case {'s','n'} - theta_H = obj.theta_H_v; - theta_M = obj.theta_M_v; - theta_R = obj.theta_R_v; - otherwise - error('No such boundary: boundary = %s',boundary); - end - end - - function N = size(obj) - N = prod(obj.m); - end - end -end
diff -r 49c0b8c7330a -r 90c23fd08f59 +scheme/LaplaceCurvilinearNewCorner.m --- a/+scheme/LaplaceCurvilinearNewCorner.m Fri Mar 29 14:24:39 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,582 +0,0 @@ -classdef LaplaceCurvilinearNewCorner < scheme.Scheme - properties - m % Number of points in each direction, possibly a vector - h % Grid spacing - dim % Number of spatial dimensions - - grid - - order % Order of accuracy for the approximation - - a,b % Parameters of the operator - - - % Inner products and operators for physical coordinates - D % Laplace operator - H, Hi % Inner product - e_w, e_e, e_s, e_n - d_w, d_e, d_s, d_n % Normal derivatives at the boundary - H_w, H_e, H_s, H_n % Boundary inner products - Dx, Dy % Physical derivatives - M % Gradient inner product - - % Metric coefficients - J, Ji - a11, a12, a22 - K - x_u - x_v - y_u - y_v - s_w, s_e, s_s, s_n % Boundary integral scale factors - - % Inner product and operators for logical coordinates - H_u, H_v % Norms in the x and y directions - Hi_u, Hi_v - Hu,Hv % Kroneckerd norms. 1'*Hx*v corresponds to integration in the x dir. - Hiu, Hiv - du_w, dv_w - du_e, dv_e - du_s, dv_s - du_n, dv_n - - % Borrowing constants - theta_M_u, theta_M_v - theta_R_u, theta_R_v - theta_H_u, theta_H_v - - % Temporary - lambda - gamm_u, gamm_v - - end - - methods - % Implements a*div(b*grad(u)) as a SBP scheme - % TODO: Implement proper H, it should be the real physical quadrature, the logic quadrature may be but in a separate variable (H_logic?) - - function obj = LaplaceCurvilinearNewCorner(g, order, a, b, opSet) - default_arg('opSet',@sbp.D2Variable); - default_arg('a', 1); - default_arg('b', @(x,y) 0*x + 1); - - % assert(isa(g, 'grid.Curvilinear')) - if isa(a, 'function_handle') - a = grid.evalOn(g, a); - a = spdiag(a); - end - - if isa(b, 'function_handle') - b = grid.evalOn(g, b); - b = spdiag(b); - end - - % If b is scalar - if length(b) == 1 - b = b*speye(g.N(), g.N()); - end - - dim = 2; - 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); - - - % 1D 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; - - - % Logical operators - Du = kr(D1_u,I_v); - Dv = kr(I_u,D1_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); - - e_w = kr(e_l_u,I_v); - e_e = kr(e_r_u,I_v); - e_s = kr(I_u,e_l_v); - e_n = kr(I_u,e_r_v); - obj.du_w = kr(d1_l_u,I_v); - obj.dv_w = (e_w'*Dv)'; - obj.du_e = kr(d1_r_u,I_v); - obj.dv_e = (e_e'*Dv)'; - obj.du_s = (e_s'*Du)'; - obj.dv_s = kr(I_u,d1_l_v); - obj.du_n = (e_n'*Du)'; - obj.dv_n = kr(I_u,d1_r_v); - - - % Metric coefficients - 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)); - - K = cell(dim, dim); - K{1,1} = spdiag(y_v./J); - K{1,2} = spdiag(-y_u./J); - K{2,1} = spdiag(-x_v./J); - K{2,2} = spdiag(x_u./J); - obj.K = K; - - obj.x_u = x_u; - obj.x_v = x_v; - obj.y_u = y_u; - obj.y_v = y_v; - - % Assemble full operators - L_12 = spdiag(a12); - Duv = Du*b*L_12*Dv; - Dvu = Dv*b*L_12*Du; - - Duu = sparse(m_tot); - Dvv = sparse(m_tot); - ind = grid.funcToMatrix(g, 1:m_tot); - - for i = 1:m_v - b_a11 = b*a11; - D = D2_u(b_a11(ind(:,i))); - p = ind(:,i); - Duu(p,p) = D; - end - - for i = 1:m_u - b_a22 = b*a22; - D = D2_v(b_a22(ind(i,:))); - p = ind(i,:); - Dvv(p,p) = D; - end - - - % Physical operators - obj.J = spdiag(J); - obj.Ji = spdiag(1./J); - - obj.D = obj.Ji*a*(Duu + Duv + Dvu + Dvv); - obj.H = obj.J*kr(H_u,H_v); - obj.Hi = obj.Ji*kr(Hi_u,Hi_v); - - obj.e_w = e_w; - obj.e_e = e_e; - obj.e_s = e_s; - obj.e_n = e_n; - - %% normal derivatives - I_w = ind(1,:); - I_e = ind(end,:); - I_s = ind(:,1); - I_n = ind(:,end); - - a11_w = spdiag(a11(I_w)); - a12_w = spdiag(a12(I_w)); - a11_e = spdiag(a11(I_e)); - a12_e = spdiag(a12(I_e)); - a22_s = spdiag(a22(I_s)); - a12_s = spdiag(a12(I_s)); - a22_n = spdiag(a22(I_n)); - a12_n = spdiag(a12(I_n)); - - s_w = sqrt((e_w'*x_v).^2 + (e_w'*y_v).^2); - s_e = sqrt((e_e'*x_v).^2 + (e_e'*y_v).^2); - s_s = sqrt((e_s'*x_u).^2 + (e_s'*y_u).^2); - s_n = sqrt((e_n'*x_u).^2 + (e_n'*y_u).^2); - - obj.d_w = -1*(spdiag(1./s_w)*(a11_w*obj.du_w' + a12_w*obj.dv_w'))'; - obj.d_e = (spdiag(1./s_e)*(a11_e*obj.du_e' + a12_e*obj.dv_e'))'; - obj.d_s = -1*(spdiag(1./s_s)*(a22_s*obj.dv_s' + a12_s*obj.du_s'))'; - obj.d_n = (spdiag(1./s_n)*(a22_n*obj.dv_n' + a12_n*obj.du_n'))'; - - obj.Dx = spdiag( y_v./J)*Du + spdiag(-y_u./J)*Dv; - obj.Dy = spdiag(-x_v./J)*Du + spdiag( x_u./J)*Dv; - - %% Boundary inner products - obj.H_w = H_v*spdiag(s_w); - obj.H_e = H_v*spdiag(s_e); - obj.H_s = H_u*spdiag(s_s); - obj.H_n = H_u*spdiag(s_n); - - % Misc. - obj.m = m; - obj.h = [h_u h_v]; - obj.order = order; - obj.grid = g; - obj.dim = dim; - - obj.a = a; - obj.b = b; - obj.a11 = a11; - obj.a12 = a12; - obj.a22 = a22; - obj.s_w = spdiag(s_w); - obj.s_e = spdiag(s_e); - obj.s_s = spdiag(s_s); - obj.s_n = spdiag(s_n); - - obj.theta_M_u = h_u*ops_u.borrowing.M.d1; - obj.theta_M_v = h_v*ops_v.borrowing.M.d1; - - obj.theta_R_u = h_u*ops_u.borrowing.R.delta_D; - obj.theta_R_v = h_v*ops_v.borrowing.R.delta_D; - - obj.theta_H_u = h_u*ops_u.borrowing.H11; - obj.theta_H_v = h_v*ops_v.borrowing.H11; - - % Temporary - obj.lambda = lambda; - 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 = obj.getBoundaryOperator('e', boundary); - d = obj.getBoundaryOperator('d', boundary); - H_b = obj.getBoundaryQuadrature(boundary); - s_b = obj.getBoundaryScaling(boundary); - [th_H, ~, th_R] = obj.getBoundaryBorrowing(boundary); - m = obj.getBoundaryNumber(boundary); - - K = obj.K; - J = obj.J; - Hi = obj.Hi; - a = obj.a; - b_b = e'*obj.b*e; - - switch type - % Dirichlet boundary condition - case {'D','d','dirichlet'} - tuning = 1.0; - - sigma = 0*b_b; - for i = 1:obj.dim - sigma = sigma + e'*J*K{i,m}*K{i,m}*e; - end - sigma = sigma/s_b; - % tau = tuning*(1/th_R + obj.dim/th_H)*sigma; - - tau_R = 1/th_R*sigma; - - tau_H = 1/th_H*sigma; - tau_H(1,1) = obj.dim*tau_H(1,1); - tau_H(end,end) = obj.dim*tau_H(end,end); - - tau = tuning*(tau_R + tau_H); - - closure = a*Hi*d*b_b*H_b*e' ... - -a*Hi*e*tau*b_b*H_b*e'; - - penalty = -a*Hi*d*b_b*H_b ... - +a*Hi*e*tau*b_b*H_b; - - - % Neumann boundary condition. Note that the penalty is for du/dn and not b*du/dn. - case {'N','n','neumann'} - tau1 = -1; - tau2 = 0; - tau = (tau1*e + tau2*d)*H_b; - - closure = a*Hi*tau*b_b*d'; - penalty = -a*Hi*tau*b_b; - - - % Unknown, boundary condition - otherwise - error('No such boundary condition: type = %s',type); - end - end - - % 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) - - % error('Not implemented') - - defaultType.tuning = 1.0; - 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; - - dim = obj.dim; - % u denotes the solution in the own domain - % v denotes the solution in the neighbour domain - u = obj; - v = neighbour_scheme; - - % Boundary operators, u - e_u = u.getBoundaryOperator('e', boundary); - d_u = u.getBoundaryOperator('d', boundary); - gamm_u = u.getBoundaryBorrowing(boundary); - s_b_u = u.getBoundaryScaling(boundary); - [th_H_u, ~, th_R_u] = u.getBoundaryBorrowing(boundary); - m_u = u.getBoundaryNumber(boundary); - - % Coefficients, u - K_u = u.K; - J_u = u.J; - b_b_u = e_u'*u.b*e_u; - - % Boundary operators, v - e_v = v.getBoundaryOperator('e', neighbour_boundary); - d_v = v.getBoundaryOperator('d', neighbour_boundary); - gamm_v = v.getBoundaryBorrowing(neighbour_boundary); - s_b_v = v.getBoundaryScaling(neighbour_boundary); - [th_H_v, ~, th_R_v] = v.getBoundaryBorrowing(neighbour_boundary); - m_v = v.getBoundaryNumber(neighbour_boundary); - - % Coefficients, v - K_v = v.K; - J_v = v.J; - b_b_v = e_v'*v.b*e_v; - - %--- Penalty strength tau ------------- - sigma_u = 0*b_b_u; - sigma_v = 0*b_b_v; - for i = 1:obj.dim - sigma_u = sigma_u + e_u'*J_u*K_u{i,m_u}*K_u{i,m_u}*e_u; - sigma_v = sigma_v + e_v'*J_v*K_v{i,m_v}*K_v{i,m_v}*e_v; - end - sigma_u = sigma_u/s_b_u; - sigma_v = sigma_v/s_b_v; - - tau_R_u = 1/th_R_u*sigma_u; - tau_R_v = 1/th_R_v*sigma_v; - - tau_H_u = 1/th_H_u*sigma_u; - tau_H_u(1,1) = dim*tau_H_u(1,1); - tau_H_u(end,end) = dim*tau_H_u(end,end); - - tau_H_v = 1/th_H_v*sigma_v; - tau_H_v(1,1) = dim*tau_H_v(1,1); - tau_H_v(end,end) = dim*tau_H_v(end,end); - - tau = 1/4*tuning*(b_b_u*(tau_R_u + tau_H_u) + b_b_v*(tau_R_v + tau_H_v)); - %-------------------------------------- - - % Operators/coefficients that are only required from this side - Hi = u.Hi; - H_b = u.getBoundaryQuadrature(boundary); - a = u.a; - - closure = 1/2*a*Hi*d_u*b_b_u*H_b*e_u' ... - -1/2*a*Hi*e_u*H_b*b_b_u*d_u' ... - -a*Hi*e_u*tau*H_b*e_u'; - - penalty = -1/2*a*Hi*d_u*b_b_u*H_b*e_v' ... - -1/2*a*Hi*e_u*H_b*b_b_v*d_v' ... - +a*Hi*e_u*tau*H_b*e_v'; - end - - function [closure, penalty] = interfaceNonConforming(obj,boundary,neighbour_scheme,neighbour_boundary,type) - - % TODO: Make this work for curvilinear grids - warning('LaplaceCurvilinear: Non-conforming grid interpolation only works for Cartesian grids.'); - warning('LaplaceCurvilinear: Non-conforming interface uses Virtas penalty strength'); - warning('LaplaceCurvilinear: Non-conforming interface assumes that b is constant'); - - % User can request special interpolation operators by specifying type.interpOpSet - default_field(type, 'interpOpSet', @sbp.InterpOpsOP); - interpOpSet = type.interpOpSet; - tuning = type.tuning; - - - % 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); - 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); - m_v = size(e_v, 2); - - Hi = obj.Hi; - a = obj.a; - - 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_u = -1./(4*b1_u) -1./(4*b2_u); - tau_v = -1./(4*b1_v) -1./(4*b2_v); - - tau_u = tuning * spdiag(tau_u); - tau_v = tuning * spdiag(tau_v); - beta_u = tau_v; - - % Build interpolation operators - intOps = interpOpSet(m_u, m_v, obj.order, neighbour_scheme.order); - Iu2v = intOps.Iu2v; - Iv2u = intOps.Iv2u; - - closure = a*Hi*e_u*tau_u*H_b_u*e_u' + ... - a*Hi*e_u*H_b_u*Iv2u.bad*beta_u*Iu2v.good*e_u' + ... - a*1/2*Hi*d_u*H_b_u*e_u' + ... - -a*1/2*Hi*e_u*H_b_u*d_u'; - - penalty = -a*Hi*e_u*tau_u*H_b_u*Iv2u.good*e_v' + ... - -a*Hi*e_u*H_b_u*Iv2u.bad*beta_u*e_v' + ... - -a*1/2*Hi*d_u*H_b_u*Iv2u.good*e_v' + ... - -a*1/2*Hi*e_u*H_b_u*Iv2u.bad*d_v'; - - 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', '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 - % - % boundary -- string - function H_b = getBoundaryQuadrature(obj, boundary) - assertIsMember(boundary, {'w', 'e', 's', 'n'}) - - H_b = obj.(['H_', boundary]); - end - - % Returns square boundary quadrature scaling matrix, of dimension - % corresponding to the number of boundary points - % - % boundary -- string - function s_b = getBoundaryScaling(obj, boundary) - assertIsMember(boundary, {'w', 'e', 's', 'n'}) - - s_b = obj.(['s_', boundary]); - end - - % Returns the coordinate number corresponding to the boundary - % - % boundary -- string - function m = getBoundaryNumber(obj, boundary) - assertIsMember(boundary, {'w', 'e', 's', 'n'}) - - switch boundary - case {'w', 'e'} - m = 1; - case {'s', 'n'} - m = 2; - end - end - - % Returns the indices of the boundary points in the grid matrix - % boundary -- string - function I = getBoundaryIndices(obj, boundary) - ind = grid.funcToMatrix(obj.grid, 1:prod(obj.m)); - switch boundary - case 'w' - I = ind(1,:); - case 'e' - I = ind(end,:); - case 's' - I = ind(:,1)'; - case 'n' - I = ind(:,end)'; - otherwise - error('No such boundary: boundary = %s',boundary); - end - end - - % Returns borrowing constant gamma - % boundary -- string - function [theta_H, theta_M, theta_R] = getBoundaryBorrowing(obj, boundary) - switch boundary - case {'w','e'} - theta_H = obj.theta_H_u; - theta_M = obj.theta_M_u; - theta_R = obj.theta_R_u; - case {'s','n'} - theta_H = obj.theta_H_v; - theta_M = obj.theta_M_v; - theta_R = obj.theta_R_v; - otherwise - error('No such boundary: boundary = %s',boundary); - end - end - - function N = size(obj) - N = prod(obj.m); - end - end -end