changeset 997:78db023a7fe3 feature/getBoundaryOp

Add getBoundaryOperator method to all 2d schemes, except obsolete Wave2dCurve and ElastiCurve, which needs a big makeover.
author Martin Almquist <malmquist@stanford.edu>
date Sat, 12 Jan 2019 11:57:50 -0800
parents a0b3161e44f3
children 2b1b944deae1
files +scheme/Beam2d.m +scheme/Heat2dCurvilinear.m +scheme/Heat2dVariable.m +scheme/Hypsyst2d.m +scheme/Hypsyst2dCurve.m +scheme/LaplaceCurvilinear.m +scheme/Schrodinger2d.m +scheme/Utux2d.m +scheme/Wave2d.m
diffstat 9 files changed, 683 insertions(+), 246 deletions(-) [+]
line wrap: on
line diff
--- a/+scheme/Beam2d.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Beam2d.m	Sat Jan 12 11:57:50 2019 -0800
@@ -121,7 +121,10 @@
             default_arg('type','dn');
             default_arg('data',0);
 
-            [e,d1,d2,d3,s,gamm,delt,halfnorm_inv] = obj.get_boundary_ops(boundary);
+            [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
@@ -164,8 +167,14 @@
         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);
+            [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;
 
@@ -192,46 +201,141 @@
             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)
+        % 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'
-                    e  = obj.e_w;
-                    d1 = obj.d1_w;
-                    d2 = obj.d2_w;
-                    d3 = obj.d3_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;
-                    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;
+                case {'s','n'}
                     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
--- a/+scheme/Heat2dCurvilinear.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Heat2dCurvilinear.m	Sat Jan 12 11:57:50 2019 -0800
@@ -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,109 @@
             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)
 
-            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};
+                    otherwise
+                        error('No such boundary: boundary = %s',boundary);
+                    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};
+                    otherwise
+                        error('No such boundary: boundary = %s',boundary);
+                    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};
+                    otherwise
+                        error('No such boundary: boundary = %s',boundary);
+                    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)
 
             switch boundary
-                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
-                    j = 1;
-                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
-                    j = 2;
+                case 'w'
+                    H_b = obj.H_boundary_l{1};
+                case 'e'
+                    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};
                 otherwise
                     error('No such boundary: boundary = %s',boundary);
             end
+        end
 
-            switch op
-                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
+        % 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 operator: operatr = ' op]);
+                    error('No such boundary: boundary = %s',boundary);
             end
+        end
 
+        % Returns borrowing constant gamma*h
+        % boundary -- string
+        function gamm = getBoundaryBorrowing(obj, boundary)
+            switch boundary
+                case {'w','e'}
+                    gamm = obj.h(1)*obj.alpha(1);
+                case {'s','n'}
+                    gamm = obj.h(2)*obj.alpha(2);
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
         end
 
         function N = size(obj)
--- a/+scheme/Heat2dVariable.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Heat2dVariable.m	Sat Jan 12 11:57:50 2019 -0800
@@ -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,94 @@
             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)
 
-            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};
+                    otherwise
+                        error('No such boundary: boundary = %s',boundary);
+                    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};
+                    otherwise
+                        error('No such boundary: boundary = %s',boundary);
+                    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)
 
             switch boundary
-                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
-                    j = 1;
-                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
-                    j = 2;
+                case 'w'
+                    H_b = obj.H_boundary{1};
+                case 'e'
+                    H_b = obj.H_boundary{1};
+                case 's'
+                    H_b = obj.H_boundary{2};
+                case 'n'
+                    H_b = obj.H_boundary{2};
                 otherwise
                     error('No such boundary: boundary = %s',boundary);
             end
+        end
 
-            switch op
-                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
+        % 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 operator: operatr = ' op]);
+                    error('No such boundary: boundary = %s',boundary);
             end
+        end
 
+        % Returns borrowing constant gamma*h
+        % boundary -- string
+        function gamm = getBoundaryBorrowing(obj, boundary)
+            switch boundary
+                case {'w','e'}
+                    gamm = obj.h(1)*obj.alpha(1);
+                case {'s','n'}
+                    gamm = obj.h(2)*obj.alpha(2);
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
         end
 
         function N = size(obj)
--- a/+scheme/Hypsyst2d.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Hypsyst2d.m	Sat Jan 12 11:57:50 2019 -0800
@@ -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,56 @@
             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)
+
+            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;
+                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)
+
+            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);
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+        end
+
     end
 end
\ No newline at end of file
--- a/+scheme/Hypsyst2dCurve.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Hypsyst2dCurve.m	Sat Jan 12 11:57:50 2019 -0800
@@ -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,58 @@
             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)
+
+            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;
+                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)
+
+            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);
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+        end
+
+
     end
 end
\ No newline at end of file
--- a/+scheme/LaplaceCurvilinear.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/LaplaceCurvilinear.m	Sat Jan 12 11:57:50 2019 -0800
@@ -437,7 +437,6 @@
                     varargout{i} = d;
                 end
             end
-
         end
 
         % Returns square boundary quadrature matrix, of dimension
--- a/+scheme/Schrodinger2d.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Schrodinger2d.m	Sat Jan 12 11:57:50 2019 -0800
@@ -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,32 +286,83 @@
             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)
+
+            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 '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
+        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'
-                    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)
+            switch boundary
+                case {'e','n'}
+                    s = 1;
+                case {'w','s'}
+                    s = -1;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+        end
+
         function N = size(obj)
             N = prod(obj.m);
         end
--- a/+scheme/Utux2d.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Utux2d.m	Sat Jan 12 11:57:50 2019 -0800
@@ -139,16 +139,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
 
@@ -197,16 +188,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
 
@@ -290,6 +272,56 @@
 
          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;
+                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
+
         function N = size(obj)
             N = obj.m;
         end
--- a/+scheme/Wave2d.m	Tue Jan 08 11:51:24 2019 +0100
+++ b/+scheme/Wave2d.m	Sat Jan 12 11:57:50 2019 -0800
@@ -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,34 +195,109 @@
             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)
+
+            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 '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;
+                    otherwise
+                        error('No such boundary: boundary = %s',boundary);
+                    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)
+
             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;
+                    H_b = obj.H_x;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+        end
+
+        % Returns borrowing constant gamma
+        % boundary -- string
+        function gamm = getBoundaryBorrowing(obj, boundary)
+            switch boundary
+                case {'w','e'}
+                    gamm = obj.gamm_x;
+                case {'s','n'}
+                    gamm = obj.gamm_y;
+                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;
-                    gamm = obj.gamm_y;
-                    halfnorm_inv = obj.Hiy;
+                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