changeset 820:501750fbbfdb

Merge with feature/grids
author Jonatan Werpers <jonatan@werpers.com>
date Fri, 07 Sep 2018 14:40:58 +0200
parents fdf0ef9150f4 (current diff) 44f05d7b6f0a (diff)
children 95c26000c0ba 5573913a0949 a4669d961d26
files +grid/Curve.m +grid/Ti.m +grid/Ti3D.m +grid/equal_step_size.m +grid/old/concat_curve.m +grid/old/curve_discretise.m +grid/old/curve_interp.m +grid/old/max_h.m +grid/old/min_h.m +grid/old/plot_shape.m +grid/old/shape.m +grid/old/shape_discretise.m +grid/old/shape_linesegments.m +grid/old/triang_interp.m +grid/old/triang_interp_pts.m +grid/old/triang_map.m +grid/old/triang_plot_interp.m +grid/old/triang_show.m +grid/place_label.m +multiblock/gridVector1d.m +multiblock/gridVector2d.m +multiblock/multiblockgrid.m +multiblock/solutionVector2cell.m +multiblock/stitchSchemes.m +sbp/+implementations/d4_compatible_halfvariable_2.m +sbp/+implementations/d4_compatible_halfvariable_4.m +sbp/+implementations/d4_compatible_halfvariable_6.m +sbp/D4CompatibleVariable.m .hgtags cell2sparse.m cell2vector.m vector2cell.m
diffstat 232 files changed, 11396 insertions(+), 2686 deletions(-) [+]
line wrap: on
line diff
diff -r fdf0ef9150f4 -r 501750fbbfdb +anim/setup_time_quantity_plot.m
--- a/+anim/setup_time_quantity_plot.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+anim/setup_time_quantity_plot.m	Fri Sep 07 14:40:58 2018 +0200
@@ -16,7 +16,7 @@
         if ishandle(axis_handle)
             % t = [t t_now];
             for j = 1:length(yfun)
-                addpoints(plot_handles(j),t_now,yfun{j}(varargin{:}));
+                addpoints(plot_handles(j),t_now,full(yfun{j}(varargin{:})));
             end
 
             [t,~] = getpoints(plot_handles(1));
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/fromMatrix.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/fromMatrix.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,24 @@
+function bm = fromMatrix(A, div)
+    d1 = div{1};
+    d2 = div{2};
+    [n, m] = size(A);
+    if n ~= sum(d1) || m ~= sum(d2)
+        error('blockmatrix:fromMatrix:NonMatchingDim','The dimensions in div does not sum to the dimensions in A.');
+    end
+
+    bm = cell(length(d1), length(d2));
+    I = 1;
+    for i = 1:length(d1)
+        J = 1;
+        for j = 1:length(d2)
+            Asub = A(I:(I + d1(i)-1), J:(J + d2(j)-1));
+            if nnz(Asub) == 0
+                bm{i,j} = sparse(d1(i), d2(j));
+            else
+                bm{i,j} = Asub;
+            end
+            J = J + d2(j);
+        end
+        I = I + d1(i);
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/fromMatrixTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/fromMatrixTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,78 @@
+function tests = fromMatrixTest()
+    tests = functiontests(localfunctions);
+end
+
+function testErrorNonMatchingDim(testCase)
+    in  = {
+        {magic(5), {[1 2 3], [4]}},
+        {magic(5), {[1 1 1 1 1 1], [5]}},
+        {magic(5), {[5], [1 1 1 1 1 1]}},
+        {ones(4,2),{[2 3],[2]}},
+        {ones(4,2),{[2 2],[3]}},
+    };
+
+    for i = 1:length(in)
+        testCase.verifyError(@()blockmatrix.fromMatrix(in{i}{:}),'blockmatrix:fromMatrix:NonMatchingDim');
+    end
+end
+
+function testFromMatrix(testCase)
+    cases = {
+        {
+            {[],{[],[]}},
+            {}
+        },
+        {
+            {
+                magic(3),
+                {[3],[3]}
+            },
+            {magic(3)}
+        },
+        {
+            {
+                magic(3),
+                {[1 1 1],[1 1 1]}
+            },
+            mat2cell(magic(3),[1 1 1],[1 1 1])
+        },
+        {
+            {
+                [17 24 1 8 15; 23 5 7 14 16; 4 6 13 20 22; 10 12 19 21 3; 11 18 25 2 9],
+                {[1 4],[2 3]}
+            },
+            {
+                [17 24], [1 8 15];
+                [23 5; 4 6; 10 12; 11 18], [7 14 16; 13 20 22; 19 21 3; 25 2 9];
+            };
+        },
+        {
+            {
+                magic(3),
+                {[1 0 2],[1 2 0]}
+            },
+            mat2cell(magic(3),[1 0 2],[1 2 0])
+        },
+        {
+            {
+                zeros(0,1),
+                {0,1},
+            },
+            {zeros(0,1)}
+        },
+    };
+    for i = 1:length(cases)
+        out = convertToFull(blockmatrix.fromMatrix(cases{i}{1}{:}));
+        expected = cases{i}{2};
+        testCase.verifyEqual(out,expected);
+    end
+end
+
+function C = convertToFull(C)
+    [N,M] = size(C);
+    for i = 1:N
+        for j = 1:M
+            C{i,j} = full(C{i,j});
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/getDivision.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/getDivision.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,42 @@
+function div = getDivision(bm)
+    if ~blockmatrix.isBlockmatrix(bm)
+        error('blockmatrix:getDivision:NotABlockmatrix', 'Input is not a blockmatrix');
+    end
+
+    if isempty(bm)
+        div = {[],[]};
+        return
+    end
+
+    div = {row_height(bm),col_width(bm)};
+end
+
+
+function m = col_width(C)
+    m = zeros(1,size(C,2));
+    for j = 1:size(C,2)
+        for i = 1:size(C,1)
+            if isNullMatrix(C{i,j})
+                continue
+            end
+            m(j) = size(C{i,j},2);
+        end
+    end
+end
+
+function n = row_height(C)
+    n = zeros(1,size(C,1));
+    for i = 1:size(C,1)
+        for j = 1:size(C,2)
+            if isNullMatrix(C{i,j})
+                continue
+            end
+            n(i) = size(C{i,j},1);
+        end
+    end
+end
+
+function b = isNullMatrix(A)
+    [n, m] = size(A);
+    b = n == 0 && m == 0;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/getDivisionTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/getDivisionTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,81 @@
+function tests = getDivisionTest()
+    tests = functiontests(localfunctions);
+end
+
+function testError(testCase)
+    cases = {
+        magic(3),
+        {[2 2 2];{1,2}},
+        {[2 2 2];[1 2]},
+        {[2; 2; 2], [1; 2]},
+    };
+
+    for i =1:length(cases)
+        testCase.verifyError(@()blockmatrix.getDivision(cases{i}), 'blockmatrix:getDivision:NotABlockmatrix')
+    end
+end
+
+function testGetDivision(testCase)
+    cases = {
+        {
+            {},
+            {[],[]};
+        },
+        {
+            {
+            [2 2; 2 1], [1; 2];
+            [2 2], [1]
+            },
+            {[2 1], [2 1]}
+        },
+        {
+            {
+            [2 2; 2 1], [];
+            [2 2], [1]
+            },
+            {[2 1], [2 1]}
+        },
+        {
+            {
+            [2 2; 2 1], [];
+            [2 2], []
+            },
+            {[2 1], [2 0]}
+        },
+        {
+            {
+            [2 2; 2 1], [1; 2];
+            [], []
+            },
+            {[2 0], [2 1]}
+        },
+        {
+            {
+            [2 2; 2 1];
+            [2 2]
+            },
+            {[2 1], 2}
+        },
+        {
+            {zeros(3,0)},
+            {3, 0},
+        },
+        {
+            {zeros(3,0), zeros(3,0)},
+            {3, [0, 0]},
+        },
+        {
+            {zeros(3,0); zeros(2,0)},
+            {[3 2],0},
+        },
+    };
+
+    for i = 1:length(cases)
+        in = cases{i}{1};
+        out = blockmatrix.getDivision(in);
+        expected = cases{i}{2};
+        testCase.verifyEqual(out, expected);
+    end
+end
+
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/isBlockmatrix.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/isBlockmatrix.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,59 @@
+function b = isBlockmatrix(bm)
+    if ~iscell(bm)
+        b = false;
+        return
+    end
+
+    % Make sure all blocks are numerical matrices
+    for i = 1:length(bm)
+        if ~isnumeric(bm{i})
+            b = false;
+            return
+        end
+    end
+
+    [N,M] = size(bm);
+    % Make sure column dimensions agree
+    for i = 1:N
+        d = [];
+        for j = 1:M
+            d_ij = size(bm{i,j},1);
+            if d_ij == 0
+                continue
+            end
+
+            if isempty(d)
+                d = d_ij;
+                continue
+            end
+
+            if d ~= d_ij
+                b = false;
+                return
+            end
+        end
+    end
+
+    % Make sure row dimensions agree
+    for j = 1:M
+        d = [];
+        for i = 1:N
+            d_ij = size(bm{i,j},2);
+            if d_ij == 0
+                continue
+            end
+
+            if isempty(d)
+                d = d_ij;
+                continue
+            end
+
+            if d ~= d_ij
+                b = false;
+                return
+            end
+        end
+    end
+
+    b = true;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/isBlockmatrixTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/isBlockmatrixTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,67 @@
+function tests = isBlockmatrixTest()
+    tests = functiontests(localfunctions);
+end
+
+function testIsBlockmatrix(testCase)
+    cases = {
+        {
+            magic(3),
+            false % Must be a cell array
+        }
+        {
+            {[2 2 2];{1,2}},
+            false % All elements of the cell matrix must be regular matrices
+        },
+        {
+            {[2 2 2];[1 2]},
+            false % Row dimensions must match
+        },
+        {
+            {[2; 2; 2], [1; 2]},
+            false % Column dimensions must match
+        },
+        {
+            {},
+            true % An empty matrix is a matrix too
+        },
+        {
+            {
+            [2 2; 2 1], [1; 2];
+            [2 2], [1]
+            },
+            true % A simple valid one
+        },
+        {
+            {
+            [2 2; 2 1], [];
+            [2 2], [1]
+            },
+            true % Empty blocks assumed to be zero and match dimensions
+        },
+        {
+            {
+            [2 2; 2 1], [];
+            [2 2], []
+            },
+            true % Empty blocks allowed.
+        },
+        {
+            {
+            [2 2; 2 1], [1; 2];
+            [], []
+            },
+            true % Empty blocks allowed.
+        },
+        {
+            blockmatrix.zero({[1 2 3],[2 3]}),
+            true % A zero block matrix is a block matrix
+        },
+    };
+
+    for i = 1:length(cases)
+        in = cases{i}{1};
+        out = blockmatrix.isBlockmatrix(in);
+        expected = cases{i}{2};
+        testCase.verifyEqual(out, expected, sprintf('Should return %d for %s', expected, toString(in)));
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/isDivision.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/isDivision.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,34 @@
+function b = isDivision(div)
+    % Make sure it is a cellarray
+    if ~iscell(div)
+        b = false;
+        return
+    end
+
+    % Make sure it has the right shape
+    if numel(div) ~= 2
+        b = false;
+        return
+    end
+
+    if ~isDivisionVector(div{1}) || ~isDivisionVector(div{2})
+        b = false;
+        return
+    end
+
+    b = true;
+end
+
+function b = isDivisionVector(v)
+    if isempty(v)
+        b = true;
+        return
+    end
+
+    if any(v < 0)
+        b = false;
+        return
+    end
+
+    b = true;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/isDivisionTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/isDivisionTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,25 @@
+function tests = isDivisionTest()
+    tests = functiontests(localfunctions);
+end
+
+function testIsDivision(testCase)
+    cases = {
+        {[1 2] ,false},     % Must be a cell array
+        {{[1 2 3]} ,false}, % Must have two vectors
+        {{[],[]}, true}     % No blocks is a valid blockmatrix
+        {{[1 2],[]} ,true},
+        {{[],[1 2]} ,true},
+        {{[2 2 2],[1 2]} ,true},
+        {{[1 2],[1 0]} ,true},
+        {{[0 2],[1 1]} ,true},
+        {{[1 2],[1]} ,true},
+        {{[1 2],[1], [1 2 3]} ,false},
+    };
+
+    for i = 1:length(cases)
+        in = cases{i}{1};
+        out = blockmatrix.isDivision(in);
+        expected = cases{i}{2};
+        testCase.verifyEqual(out, expected, sprintf('Should return %d for %s', expected, toString(in)));
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/multiply.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/multiply.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,17 @@
+function C = multiply(A, B)
+    [n_a, m_a] = size(A);
+    [n_b, m_b] = size(B);
+
+    assert(m_a == n_b, 'Dimensions do not agree.')
+
+    C = cell(n_a, m_b);
+
+    for i = 1:n_a
+        for j = 1:m_b
+            C{i,j} = sparse(size(A{i,1},1), size(B{1,j},2));
+            for k = 1:n_b
+                C{i,j} = C{i,j} + A{i,k}*B{k,j};
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/multiplyTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/multiplyTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,57 @@
+function tests = multiplyTest()
+    tests = functiontests(localfunctions);
+end
+
+
+function testMultiply(testCase)
+    a11 = [
+        0.8147    0.1270;
+        0.9058    0.9134;
+    ];
+    a12 = [
+        0.6324    0.2785    0.9575;
+        0.0975    0.5469    0.9649;
+    ];
+    a21 = [
+        0.1576    0.9706;
+    ];
+    a22 = [
+        0.9572    0.4854    0.8003;
+    ];
+    A = {
+        a11 a12;
+        a21 a22;
+    };
+
+    b11 = [
+        0.1419    0.9157    0.9595;
+        0.4218    0.7922    0.6557;
+    ];
+    b12 = [
+        0.0357    0.9340;
+        0.8491    0.6787;
+    ];
+    b21 = [
+        0.7577    0.6555    0.0318;
+        0.7431    0.1712    0.2769;
+        0.3922    0.7060    0.0462;
+    ];
+    b22 = [
+        0.0971    0.3171;
+        0.8235    0.9502;
+        0.6948    0.0344;
+    ];
+
+    B = {
+        b11 b12;
+        b21 b22;
+    };
+
+
+    C = {
+        a11*b11 + a12*b21, a11*b12 + a12*b22;
+        a21*b11 + a22*b21, a21*b12 + a22*b22;
+    };
+
+    testCase.verifyEqual(blockmatrix.multiply(A,B), C);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/toMatrix.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/toMatrix.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,23 @@
+function A = toMatrix(bm)
+    if ~blockmatrix.isBlockmatrix(bm)
+        error('blockmatrix:toMatrix:NotABlockmatrix', 'Input is not a blockmatrix');
+    end
+
+    div = blockmatrix.getDivision(bm);
+    n = div{1};
+    m = div{2};
+
+    N = sum(n);
+    M = sum(m);
+
+    A = sparse(N,M);
+
+    for i = 1:size(bm,1)
+        for j = 1:size(bm,2)
+            if isempty(bm{i,j})
+                bm{i,j} = sparse(n(i),m(j));
+            end
+        end
+    end
+    A = cell2mat(bm);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/toMatrixTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/toMatrixTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,78 @@
+function tests = toMatrixTest()
+    tests = functiontests(localfunctions);
+end
+
+function testError(testCase)
+    testCase.verifyError(@()blockmatrix.toMatrix([]), 'blockmatrix:toMatrix:NotABlockmatrix')
+end
+
+function testToMatrix(testCase)
+    cases = {
+        {
+            {},
+            [],
+        },
+        {
+            {1, 2; 3, 4},
+            [1,2; 3,4],
+        }
+        {
+            {
+            [2 2; 2 1], [1; 2];
+            [2 2], [1]
+            },
+            [2 2 1;
+             2 1 2;
+             2 2 1],
+        },
+        {
+            {
+            [2 2; 2 1], [];
+            [2 2], [1]
+            },
+            [2 2 0;
+             2 1 0;
+             2 2 1],
+        },
+        {
+            {
+            [2 2; 2 1], [];
+            [2 2], []
+            },
+            [2 2;
+             2 1;
+             2 2],
+        },
+        {
+            {
+            [2 2; 2 1], [1; 2];
+            [], []
+            },
+            [2 2 1;
+             2 1 2],
+        },
+        {
+            {zeros(0,0)},
+            [],
+        },
+        {
+            {zeros(3,0), zeros(3,0)},
+            zeros(3,0),
+        },
+        {
+            {zeros(3,0); zeros(2,0)},
+            zeros(5,0),
+        },
+        {
+            {zeros(0,3), zeros(0,2)},
+            zeros(0,5),
+        },
+    };
+
+    for i = 1:length(cases)
+        in = cases{i}{1};
+        out = full(blockmatrix.toMatrix(in));
+        expected = cases{i}{2};
+        testCase.verifyEqual(out, expected);
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/zero.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/zero.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,20 @@
+% Creates a block matrix according to the division with zeros everywhere.
+function bm = zero(div)
+    if ~blockmatrix.isDivision(div)
+        error('div is not a valid division');
+    end
+
+    n = div{1};
+    m = div{2};
+
+    N = length(n);
+    M = length(m);
+
+    bm = cell(N,M);
+
+    for i = 1:N
+        for j = 1:M
+            bm{i,j} = sparse(n(i),m(j));
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +blockmatrix/zeroTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+blockmatrix/zeroTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,68 @@
+function tests = zeroTest()
+    tests = functiontests(localfunctions);
+end
+
+function testZero(testCase)
+    cases = {
+        {
+            {[],[]},
+            {},
+        },
+        {
+            {0,0},
+            {[]};
+        },
+        {
+            {1,1},
+            {0};
+        },
+        {
+            {2,1},
+            {[0; 0]};
+        },
+        {
+            {1,2},
+            {[0 0]};
+        },
+        {
+            {[1 2],2},
+            {[0 0];[0 0; 0 0]};
+        },
+        {
+            {[1 2],[2 1]},
+            {[0 0],[0];[0 0; 0 0],[0; 0]};
+        },
+        {
+            {[3],[0]},
+            {zeros(3,0)},
+        },
+
+        {
+            {[0],[3]},
+            {zeros(0,3)},
+        },
+        {
+            {[0 2],[0 3]},
+            {
+                zeros(0,0), zeros(0,3);
+                zeros(2,0), zeros(2,3);
+            },
+        },
+    };
+
+    for i = 1:length(cases)
+        out = convertToFull(blockmatrix.zero(cases{i}{1}));
+        expected = cases{i}{2};
+        testCase.verifyEqual(out,expected);
+    end
+end
+
+
+function C = convertToFull(C)
+    [N,M] = size(C);
+    for i = 1:N
+        for j = 1:M
+            C{i,j} = full(C{i,j});
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +draw/prompt_bezier.m
--- a/+draw/prompt_bezier.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+draw/prompt_bezier.m	Fri Sep 07 14:40:58 2018 +0200
@@ -22,8 +22,8 @@
     p.Color = Color.yellow;
     p.MarkerSize = 16;
 
-    C = grid.Curve.bezier(a,c1,c2,b);
-    fprintf('C = grid.Curve.bezier([%.3g; %.3g],[%.3g; %.3g],[%.3g; %.3g],[%.3g; %.3g]);\n',a,c1,c2,b)
+    C = parametrization.Curve.bezier(a,c1,c2,b);
+    fprintf('C = parametrization.Curve.bezier([%.3g; %.3g],[%.3g; %.3g],[%.3g; %.3g],[%.3g; %.3g]);\n',a,c1,c2,b)
     h = C.plot();
     uistack(h,'bottom');
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +draw/prompt_point.m
--- a/+draw/prompt_point.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+draw/prompt_point.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,22 +1,23 @@
-function [p, button] = prompt_point(s,varargin)
+function [p, button] = prompt_point(s, varargin)
     default_arg('s',[])
 
     set(gcf,'Pointer','crosshair')
 
     if ~isempty(s)
-        fprintf(s,varargin{:});
+        fprintf(s, varargin{:});
     end
 
-    a = gca;
+    fh = gcf();
+    ah = gca();
 
-    function get_point(src,event)
-        cp = a.CurrentPoint;
+    function get_point(src, event)
+        cp = ah.CurrentPoint;
         p = cp(1,1:2)';
-        a.ButtonDownFcn = [];
+        fh.WindowButtonUpFcn = [];
     end
 
-    a.ButtonDownFcn = @get_point;
-    waitfor(a,'ButtonDownFcn', [])
+    fh.WindowButtonUpFcn = @get_point;
+    waitfor(fh,'WindowButtonUpFcn', [])
 
     set(gcf,'Pointer','arrow')
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Cartesian.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/Cartesian.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,197 @@
+classdef Cartesian < grid.Structured
+    properties
+        n % Number of points in the grid
+        d % Number of dimensions
+        m % Number of points in each direction
+        x % Cell array of vectors with node placement for each dimension.
+        h % Spacing/Scaling
+        lim % Cell array of left and right boundaries for each dimension.
+    end
+
+    % General d dimensional grid with n points
+    methods
+        % Creates a cartesian grid given vectors conatining the coordinates
+        % in each direction
+        function obj = Cartesian(varargin)
+            obj.d = length(varargin);
+
+            for i = 1:obj.d
+                assert(isnumeric(varargin{i}), 'Coordinate inputs must be vectors.')
+
+                obj.x{i} = varargin{i};
+                obj.m(i) = length(varargin{i});
+            end
+
+            obj.n = prod(obj.m);
+            if obj.n == 0
+                error('grid:Cartesian:EmptyGrid','Input parameter gives an empty grid.')
+            end
+
+            obj.h = [];
+
+            obj.lim = cell(1,obj.d);
+            for i = 1:obj.d
+                obj.lim{i} = {obj.x{i}(1), obj.x{i}(end)};
+            end
+        end
+        % n returns the number of points in the grid
+        function o = N(obj)
+            o = obj.n;
+        end
+
+        % d returns the spatial dimension of the grid
+        function o = D(obj)
+            o = obj.d;
+        end
+
+        function m = size(obj)
+            m = obj.m;
+        end
+
+        % points returns a n x d matrix containing the coordianets for all points.
+        % points are ordered according to the kronecker product with X*Y*Z
+        function X = points(obj)
+            X = zeros(obj.n, obj.d);
+
+            for i = 1:obj.d
+                if iscolumn(obj.x{i})
+                    c = obj.x{i};
+                else
+                    c = obj.x{i}';
+                end
+
+                m_before = prod(obj.m(1:i-1));
+                m_after = prod(obj.m(i+1:end));
+
+                X(:,i) = kr(ones(m_before,1),c,ones(m_after,1));
+            end
+        end
+
+        % matrices returns a cell array with coordinates in matrix form.
+        % For 2d case these will have to be transposed to work with plotting routines.
+        function X = matrices(obj)
+
+            if obj.d == 1 % There is no 1d matrix data type in matlab, handle special case
+                X{1} = reshape(obj.x{1}, [obj.m 1]);
+                return
+            end
+
+            X = cell(1,obj.d);
+            for i = 1:obj.d
+                s = ones(1,obj.d);
+                s(i) = obj.m(i);
+
+                t = reshape(obj.x{i},s);
+
+                s = obj.m;
+                s(i) = 1;
+                X{i} = repmat(t,s);
+            end
+        end
+
+        function h = scaling(obj)
+            if isempty(obj.h)
+                error('grid:Cartesian:NoScalingSet', 'No scaling set')
+            end
+
+            h = obj.h;
+        end
+
+        % Restricts the grid function gf on obj to the subgrid g.
+        % Only works for even multiples
+        function gf = restrictFunc(obj, gf, g)
+            m1 = obj.m;
+            m2 = g.m;
+
+            % Check the input
+            if prod(m1) ~= numel(gf)
+                error('grid:Cartesian:restrictFunc:NonMatchingFunctionSize', 'The grid function has to few or too many points.');
+            end
+
+            if ~all(mod(m1-1,m2-1) == 0)
+                error('grid:Cartesian:restrictFunc:NonMatchingGrids', 'Only integer downsamplings are allowed');
+            end
+
+            % Calculate stride for each dimension
+            stride = (m1-1)./(m2-1);
+
+            % Create downsampling indecies
+            I = {};
+            for i = 1:length(m1)
+                I{i} = 1:stride(i):m1(i);
+            end
+
+            gf = reshapeRowMaj(gf, m1);
+            gf = gf(I{:});
+            gf = reshapeRowMaj(gf, prod(m2));
+        end
+
+        % Projects the grid function gf on obj to the grid g.
+        function gf = projectFunc(obj, gf, g)
+            error('grid:Cartesian:NotImplemented')
+        end
+
+        % Return the names of all boundaries in this grid.
+        function bs = getBoundaryNames(obj)
+            switch obj.D()
+                case 1
+                    bs = {'l', 'r'};
+                case 2
+                    bs = {'w', 'e', 's', 'n'};
+                case 3
+                    bs = {'w', 'e', 's', 'n', 'd', 'u'};
+                otherwise
+                    error('not implemented');
+            end
+        end
+
+        % Return coordinates for the given boundary
+        function X = getBoundary(obj, name)
+            % In what dimension is the boundary?
+            switch name
+                case {'l', 'r', 'w', 'e'}
+                    D = 1;
+                case {'s', 'n'}
+                    D = 2;
+                case {'d', 'u'}
+                    D = 3;
+                otherwise
+                    error('not implemented');
+            end
+
+            % At what index is the boundary?
+            switch name
+                case {'l', 'w', 's', 'd'}
+                    index = 1;
+                case {'r', 'e', 'n', 'u'}
+                    index = obj.m(D);
+                otherwise
+                    error('not implemented');
+            end
+
+
+
+            I = cell(1, obj.d);
+            for i = 1:obj.d
+                if i == D
+                    I{i} = index;
+                else
+                    I{i} = ':';
+                end
+            end
+
+            % Calculate size of result:
+            m = obj.m;
+            m(D) = [];
+            N = prod(m);
+
+            X = zeros(N, obj.d);
+
+            coordMat = obj.matrices();
+            for i = 1:length(coordMat)
+                Xtemp = coordMat{i}(I{:});
+                X(:,i) = reshapeRowMaj(Xtemp, [N,1]);
+            end
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/CartesianTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/CartesianTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,318 @@
+function tests = CartesianTest()
+    tests = functiontests(localfunctions);
+end
+
+
+function testWarningEmptyGrid(testCase)
+    in  = {
+        {[]},
+        {[],[1]},
+        {[1],[2], []},
+    };
+
+    for i = 1:length(in)
+        testCase.verifyError(@()grid.Cartesian(in{i}{:}),'grid:Cartesian:EmptyGrid');
+    end
+end
+
+function testN(testCase)
+    in  = {
+        {[1 2 3]},
+        {[1 2 3],[1 2]},
+        {[1 2 3],[1 2 3]},
+        {[1 2 3],[1 2 3], [1]},
+        {[1 2 3],[1 2 3], [1 3 4]},
+    };
+
+    out = [3,6,9,9,27];
+
+    for i = 1:length(in)
+        g = grid.Cartesian(in{i}{:});
+        testCase.verifyEqual(g.N(),out(i));
+    end
+end
+
+
+function testD(testCase)
+    in  = {
+        {[1 2 3]},
+        {[1 2 3],[1 2]},
+        {[1 2 3],[1 2 3]},
+        {[1 2 3],[1 2 3], [1]},
+        {[1 2 3],[1 2 3], [1 3 4]},
+    };
+
+    out = [1,2,2,3,3];
+
+    for i = 1:length(in)
+        g = grid.Cartesian(in{i}{:});
+        testCase.verifyEqual(g.D(),out(i));
+    end
+end
+
+function testSize(testCase)
+    in  = {
+        {[1 2 3]},
+        {[1 2 3],[1 2]},
+        {[1 2 3],[1 2 3]},
+        {[1 2 3],[1 2 3], [1]},
+        {[1 2 3],[1 2 3], [1 3 4]},
+    };
+
+    out = {
+        [3],
+        [3 2],
+        [3 3],
+        [3 3 1],
+        [3 3 3],
+    };
+
+    for i = 1:length(in)
+        g = grid.Cartesian(in{i}{:});
+        testCase.verifyEqual(g.size(),out{i});
+    end
+end
+
+function testPoints(testCase)
+    in  = {
+        {[1 2]},
+        {[1 2],[3 4]},
+        {[1 2],[3 4], [5 6]},
+    };
+
+    out = {
+        [[1; 2]],
+        [[1; 1; 2; 2],[3; 4; 3; 4]],
+        [[1; 1; 1; 1; 2; 2; 2; 2],[3; 3; 4; 4; 3; 3; 4; 4],[ 5; 6; 5; 6; 5; 6; 5; 6]],
+    };
+
+    for i = 1:length(in)
+        g = grid.Cartesian(in{i}{:});
+        testCase.verifyEqual(g.points(),out{i});
+    end
+end
+
+function testMatrices(testCase)
+    in  = {
+        {[1 2]},
+        {[1 2],[3 4]},
+        {[1 2],[3 4], [5 6]},
+    };
+
+    out{1}{1} = [1; 2];
+
+    out{2}{1} = [1, 1; 2, 2];
+    out{2}{2} = [3, 4; 3, 4];
+
+    out{3}{1}(:,:,1) = [1, 1; 2, 2];
+    out{3}{1}(:,:,2) = [1, 1; 2, 2];
+
+    out{3}{2}(:,:,1) = [3, 4; 3, 4];
+    out{3}{2}(:,:,2) = [3, 4; 3, 4];
+
+    out{3}{3}(:,:,1) = [5, 5; 5, 5];
+    out{3}{3}(:,:,2) = [6, 6; 6, 6];
+
+    for i = 1:length(in)
+        g = grid.Cartesian(in{i}{:});
+        testCase.verifyEqual(g.matrices(),out{i});
+    end
+end
+
+
+function testRestrictFuncInvalidInput(testCase)
+    inG1  = {
+        {[1 2 3 4 5]},
+        {[1 2 3],[4 5 6 7 8]},
+        {[1 2 3],[4 5 6 7 8]},
+        {[1 2 3],[4 5 6 7 8]},
+    };
+
+    inG2  = {
+        {[1 3 4 5]},
+        {[1 3],[4 5 6 8]},
+        {[1 3],[4 6 8]},
+        {[1 3],[4 6 8]},
+    };
+
+    inGf = {
+        [1; 2; 3; 4; 5],
+        [14; 15; 16; 17; 18; 24; 25; 26; 27; 28; 34; 35; 36; 37; 38];
+        [14; 15; 16; 17; 18; 24; 25; 26; 27; 28; 34; 35; 36];
+        [14; 15; 16; 17; 18; 24; 25; 26; 27; 28; 34; 35; 36; 37; 38; 39; 40];
+    };
+
+    out = {
+        'grid:Cartesian:restrictFunc:NonMatchingGrids',
+        'grid:Cartesian:restrictFunc:NonMatchingGrids',
+        'grid:Cartesian:restrictFunc:NonMatchingFunctionSize',
+        'grid:Cartesian:restrictFunc:NonMatchingFunctionSize',
+    };
+
+    for i = 1:length(inG1)
+        g1 = grid.Cartesian(inG1{i}{:});
+        g2 = grid.Cartesian(inG2{i}{:});
+        testCase.verifyError(@()g1.restrictFunc(inGf{i},g2),out{i});
+    end
+end
+
+function testRestrictFunc(testCase)
+    inG1  = {
+        {[1 2 3 4 5]},
+        {[1 2 3],[4 5 6 7 8]},
+    };
+
+    inG2  = {
+        {[1 3 5]},
+        {[1 3],[4 6 8]},
+    };
+
+    inGf = {
+        [1; 2; 3; 4; 5],
+        [14; 15; 16; 17; 18; 24; 25; 26; 27; 28; 34; 35; 36; 37; 38];
+    };
+
+    outGf = {
+        [1; 3; 5],
+        [14; 16; 18; 34; 36; 38];
+    };
+
+    for i = 1:length(inG1)
+        g1 = grid.Cartesian(inG1{i}{:});
+        g2 = grid.Cartesian(inG2{i}{:});
+        testCase.verifyEqual(g1.restrictFunc(inGf{i}, g2), outGf{i});
+    end
+end
+
+function testScaling(testCase)
+    in = {[1 2 3], [1 2]};
+    g = grid.Cartesian(in{:});
+
+    testCase.verifyError(@()g.scaling(),'grid:Cartesian:NoScalingSet');
+
+    g.h = [2 1];
+    testCase.verifyEqual(g.scaling(),[2 1]);
+
+end
+
+
+function testGetBoundaryNames(testCase)
+    in = {
+        {[1 2 3]},
+        {[1 2 3], [4 5]},
+        {[1 2 3], [4 5], [6 7 8]},
+    };
+
+    out = {
+        {'l', 'r'},
+        {'w', 'e', 's', 'n'},
+        {'w', 'e', 's', 'n', 'd', 'u'},
+    };
+
+    for i = 1:length(in)
+        g = grid.Cartesian(in{i}{:});
+        testCase.verifyEqual(g.getBoundaryNames(), out{i});
+    end
+end
+
+function testGetBoundary(testCase)
+    grids = {
+        {[1 2 3]},
+        {[1 2 3], [4 5]},
+        {[1 2 3], [4 5], [6 7 8]},
+    };
+
+    boundaries = {
+        {'l', 'r'},
+        {'w', 'e', 's', 'n'},
+        {'w', 'e', 's', 'n', 'd', 'u'},
+    };
+
+
+    % 1d
+    out{1,1} = 1;
+    out{1,2} = 3;
+
+    % 2d
+    out{2,1} = [
+        1,4;
+        1,5;
+    ];
+    out{2,2} = [
+        3,4;
+        3,5;
+    ];
+    out{2,3} = [
+        1,4;
+        2,4;
+        3,4;
+    ];
+    out{2,4} = [
+        1,5;
+        2,5;
+        3,5;
+    ];
+
+    % 3d
+    out{3,1} = [
+        1,4,6;
+        1,4,7;
+        1,4,8;
+        1,5,6;
+        1,5,7;
+        1,5,8;
+    ];
+    out{3,2} = [
+        3,4,6;
+        3,4,7;
+        3,4,8;
+        3,5,6;
+        3,5,7;
+        3,5,8;
+    ];
+    out{3,3} = [
+        1,4,6;
+        1,4,7;
+        1,4,8;
+        2,4,6;
+        2,4,7;
+        2,4,8;
+        3,4,6;
+        3,4,7;
+        3,4,8;
+    ];
+    out{3,4} = [
+        1,5,6;
+        1,5,7;
+        1,5,8;
+        2,5,6;
+        2,5,7;
+        2,5,8;
+        3,5,6;
+        3,5,7;
+        3,5,8;
+    ];
+    out{3,5} = [
+        1,4,6;
+        1,5,6;
+        2,4,6;
+        2,5,6;
+        3,4,6;
+        3,5,6;
+    ];
+    out{3,6} = [
+        1,4,8;
+        1,5,8;
+        2,4,8;
+        2,5,8;
+        3,4,8;
+        3,5,8;
+    ];
+
+    for ig = 1:length(grids)
+        g = grid.Cartesian(grids{ig}{:});
+        for ib = 1:length(boundaries{ig})
+            testCase.verifyEqual(g.getBoundary(boundaries{ig}{ib}), out{ig,ib});
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Curve.m
--- a/+grid/Curve.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,388 +0,0 @@
-classdef Curve
-    properties
-        g
-        gp
-        transformation
-    end
-
-    methods
-        %TODO:
-        % Concatenation of curves
-        % Subsections of curves
-        % Stretching of curve parameter - done for arc length.
-        % Curve to cell array of linesegments
-
-        % Returns a curve object.
-        %   g -- curve parametrization for parameter between 0 and 1
-        %  gp -- parametrization of curve derivative
-        function obj = Curve(g,gp,transformation)
-            default_arg('gp',[]);
-            default_arg('transformation',[]);
-            p_test = g(0);
-            assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.');
-
-            if ~isempty(transformation)
-                transformation.base_g = g;
-                transformation.base_gp = gp;
-                [g,gp] = grid.Curve.transform_g(g,gp,transformation);
-            end
-
-            obj.g = g;
-            obj.gp = gp;
-            obj.transformation = transformation;
-
-        end
-
-        function n = normal(obj,t)
-            assert(~isempty(obj.gp),'Curve has no derivative!');
-            deriv = obj.gp(t);
-            normalization = sqrt(sum(deriv.^2,1));
-            n = [-deriv(2,:)./normalization; deriv(1,:)./normalization];
-        end
-
-
-        % Plots a curve g(t) for 0<t<1, using n points. Returns a handle h to the plotted curve.
-        %   h = plot_curve(g,n)
-        function h = plot(obj,n)
-            default_arg('n',100);
-
-            t = linspace(0,1,n);
-            p = obj.g(t);
-            h = line(p(1,:),p(2,:));
-        end
-
-        function h= plot_normals(obj,l,n,m)
-            default_arg('l',0.1);
-            default_arg('n',10);
-            default_arg('m',100);
-            t_n = linspace(0,1,n);
-
-            normals = obj.normal(t_n)*l;
-
-            n0 = obj.g(t_n);
-            n1 = n0 + normals;
-
-            h = line([n0(1,:); n1(1,:)],[n0(2,:); n1(2,:)]);
-            set(h,'Color',Color.red);
-            obj.plot(m);
-        end
-
-        function h= show(obj,name)
-            p = obj.g(1/2);
-            n = obj.normal(1/2);
-            p = p + n*0.1;
-
-            % Add arrow
-
-            h = text(p(1),p(2),name);
-            h.HorizontalAlignment = 'center';
-            h.VerticalAlignment = 'middle';
-
-            obj.plot();
-        end
-            % Shows curve with name and arrow for direction.
-
-        % Length of arc from parameter t0 to t1 (which may be vectors).
-        % Computed using derivative.
-        function L = arcLength(obj,t0,t1)
-            assert(~isempty(obj.gp),'Curve has no derivative!');
-            speed = @(t) sqrt(sum(obj.gp(t).^2,1));
-            L =  integral_vec(speed,t0,t1);
-        end
-
-        % Creates the arc length parameterization of a curve.
-        %    N -- number of points used to approximate the arclength function
-        function curve = arcLengthParametrization(obj,N)
-            default_arg('N',100);
-            assert(~isempty(obj.gp),'Curve has no derivative!');
-
-            % Construct arcLength function using splines
-            tvec = linspace(0,1,N);
-            arcVec = obj.arcLength(0,tvec);
-            tFunc = spline(arcVec,tvec); % t as a function of arcLength
-            L = obj.arcLength(0,1);
-            arcPar = @(s) tFunc(s*L);
-
-            % New function and derivative
-            g_new = @(t)obj.g(arcPar(t));
-            gp_new = @(t) normalize(obj.gp(arcPar(t)));
-            curve = grid.Curve(g_new,gp_new);
-
-        end
-
-        % how to make it work for methods without returns
-        function p = subsref(obj,S)
-            %Should i add error checking here?
-            %Maybe if you want performance you fetch obj.g and then use that
-            switch S(1).type
-                case '()'
-                    p = obj.g(S.subs{1});
-                % case '.'
-
-                    % p = obj.(S.subs);
-                otherwise
-                    p = builtin('subsref',obj,S);
-                    % error()
-            end
-        end
-
-
-        %% TRANSFORMATION OF A CURVE
-        function D = reverse(C)
-            % g = C.g;
-            % gp = C.gp;
-            % D = grid.Curve(@(t)g(1-t),@(t)-gp(1-t));
-            D = C.transform([],[],-1);
-        end
-
-        function D = transform(C,A,b,flip)
-            default_arg('A',[1 0; 0 1]);
-            default_arg('b',[0; 0]);
-            default_arg('flip',1);
-            if isempty(C.transformation)
-                g  = C.g;
-                gp = C.gp;
-                transformation.A = A;
-                transformation.b = b;
-                transformation.flip = flip;
-            else
-                g  = C.transformation.base_g;
-                gp = C.transformation.base_gp;
-                A_old = C.transformation.A;
-                b_old = C.transformation.b;
-                flip_old = C.transformation.flip;
-
-                transformation.A = A*A_old;
-                transformation.b = A*b_old + b;
-                transformation.flip = flip*flip_old;
-            end
-
-            D = grid.Curve(g,gp,transformation);
-
-        end
-
-        function D = translate(C,a)
-            g = C.g;
-            gp = C.gp;
-
-            % function v = g_fun(t)
-            %     x = g(t);
-            %     v(1,:) = x(1,:)+a(1);
-            %     v(2,:) = x(2,:)+a(2);
-            % end
-
-            % D = grid.Curve(@g_fun,gp);
-
-            D = C.transform([],a);
-        end
-
-        function D = mirror(C, a, b)
-            assert_size(a,[2,1]);
-            assert_size(b,[2,1]);
-
-            g = C.g;
-            gp = C.gp;
-
-            l = b-a;
-            lx = l(1);
-            ly = l(2);
-
-
-            % fprintf('Singular?\n')
-
-            A = [lx^2-ly^2 2*lx*ly; 2*lx*ly ly^2-lx^2]/(l'*l);
-
-            % function v = g_fun(t)
-            %     % v = a + A*(g(t)-a)
-            %     x = g(t);
-
-            %     ax1 = x(1,:)-a(1);
-            %     ax2 = x(2,:)-a(2);
-            %     v(1,:) = a(1)+A(1,:)*[ax1;ax2];
-            %     v(2,:) = a(2)+A(2,:)*[ax1;ax2];
-            % end
-
-            % function v = gp_fun(t)
-            %     v = A*gp(t);
-            % end
-
-            % D = grid.Curve(@g_fun,@gp_fun);
-
-            % g = A(g-a)+a = Ag - Aa + a;
-            b = - A*a + a;
-            D = C.transform(A,b);
-
-        end
-
-        function D = rotate(C,a,rad)
-            assert_size(a, [2,1]);
-            assert_size(rad, [1,1]);
-            g = C.g;
-            gp = C.gp;
-
-
-            A = [cos(rad) -sin(rad); sin(rad) cos(rad)];
-
-            % function v = g_fun(t)
-            %     % v = a + A*(g(t)-a)
-            %     x = g(t);
-
-            %     ax1 = x(1,:)-a(1);
-            %     ax2 = x(2,:)-a(2);
-            %     v(1,:) = a(1)+A(1,:)*[ax1;ax2];
-            %     v(2,:) = a(2)+A(2,:)*[ax1;ax2];
-            % end
-
-            % function v = gp_fun(t)
-            %     v = A*gp(t);
-            % end
-
-            % D = grid.Curve(@g_fun,@gp_fun);
-
-
-             % g = A(g-a)+a = Ag - Aa + a;
-            b = - A*a + a;
-            D = C.transform(A,b);
-        end
-    end
-
-    methods (Static)
-
-        % Computes the derivative of g: R -> R^2 using an operator D1
-        function gp_out = numericalDerivative(g,D1)
-            m = length(D1);
-            t = linspace(0,1,m);
-            gVec = g(t)';
-            gpVec = (D1*gVec)';
-
-            gp1_fun = spline(t,gpVec(1,:));
-            gp2_fun = spline(t,gpVec(2,:));
-            gp_out = @(t) [gp1_fun(t);gp2_fun(t)];
-        end
-
-        function obj = line(p1, p2)
-
-            function v = g_fun(t)
-                v(1,:) = p1(1) + t.*(p2(1)-p1(1));
-                v(2,:) = p1(2) + t.*(p2(2)-p1(2));
-            end
-            g = @g_fun;
-
-            obj = grid.Curve(g);
-        end
-
-        function obj = circle(c,r,phi)
-            default_arg('phi',[0; 2*pi])
-            default_arg('c',[0; 0])
-            default_arg('r',1)
-
-            function v = g_fun(t)
-                w = phi(1)+t*(phi(2)-phi(1));
-                v(1,:) = c(1) + r*cos(w);
-                v(2,:) = c(2) + r*sin(w);
-            end
-
-            function v = g_fun_deriv(t)
-                w = phi(1)+t*(phi(2)-phi(1));
-                v(1,:) = -(phi(2)-phi(1))*r*sin(w);
-                v(2,:) =  (phi(2)-phi(1))*r*cos(w);
-            end
-
-            obj = grid.Curve(@g_fun,@g_fun_deriv);
-        end
-
-        function obj = bezier(p0, p1, p2, p3)
-            function v = g_fun(t)
-                v(1,:) = (1-t).^3*p0(1) + 3*(1-t).^2.*t*p1(1) + 3*(1-t).*t.^2*p2(1) + t.^3*p3(1);
-                v(2,:) = (1-t).^3*p0(2) + 3*(1-t).^2.*t*p1(2) + 3*(1-t).*t.^2*p2(2) + t.^3*p3(2);
-            end
-
-            function v = g_fun_deriv(t)
-                v(1,:) = 3*(1-t).^2*(p1(1)-p0(1)) + 6*(1-t).*t*(p2(1)-p1(1)) + 3*t.^2*(p3(1)-p2(1));
-                v(2,:) = 3*(1-t).^2*(p1(2)-p0(2)) + 6*(1-t).*t*(p2(2)-p1(2)) + 3*t.^2*(p3(2)-p2(2));
-            end
-
-            obj = grid.Curve(@g_fun,@g_fun_deriv);
-        end
-
-
-        function [g_out,gp_out] = transform_g(g,gp,tr)
-            A = tr.A;
-            b = tr.b;
-            flip = tr.flip;
-
-            function v = g_fun_noflip(t)
-                % v = A*g + b
-                x = g(t);
-
-                v(1,:) = A(1,:)*x+b(1);
-                v(2,:) = A(2,:)*x+b(2);
-            end
-
-            function v = g_fun_flip(t)
-                % v = A*g + b
-                x = g(1-t);
-
-                v(1,:) = A(1,:)*x+b(1);
-                v(2,:) = A(2,:)*x+b(2);
-            end
-
-
-            switch flip
-                case 1
-                    g_out  = @g_fun_noflip;
-                    gp_out = @(t)A*gp(t);
-                case -1
-                    g_out  = @g_fun_flip;
-                    gp_out = @(t)-A*gp(1-t);
-            end
-        end
-
-    end
-end
-
-
-
-function g_norm = normalize(g0)
-    g1 = g0(1,:);
-    g2 = g0(2,:);
-    normalization = sqrt(sum(g0.^2,1));
-    g_norm = [g1./normalization; g2./normalization];
-end
-
-function I = integral_vec(f,a,b)
-% Wrapper around the built-in function integral that
-% handles multiple limits.
-
-    Na = length(a);
-    Nb = length(b);
-    assert(Na == 1 || Nb == 1 || Na==Nb,...
-        'a and b must have same length, unless one is a scalar.');
-
-    if(Na>Nb);
-        I = zeros(size(a));
-        for i = 1:Na
-            I(i) = integral(f,a(i),b);
-        end
-    elseif(Nb>Na)
-        I = zeros(size(b));
-        for i = 1:Nb
-            I(i) = integral(f,a,b(i));
-        end
-    else
-        I = zeros(size(b));
-        for i = 1:Nb
-            I(i) = integral(f,a(i),b(i));
-        end
-    end
-end
-
-% Returns a function handle to the spline.
-function f = spline(tval,fval,spline_order)
-    default_arg('spline_order',4);
-    [m,~] = size(tval);
-    assert(m==1,'Need row vectors.');
-
-    f_spline = spapi( optknt(tval,spline_order), tval, fval );
-    f = @(t) fnval(f_spline,t);
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Curvilinear.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/Curvilinear.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,173 @@
+classdef Curvilinear < grid.Structured & grid.Mapped
+    properties
+        logic % Grid of Logical domain
+        coords % N x D matrix with coordinates of each point in the physical domain
+    end
+
+    methods
+        % Creates a curvilinear grid.
+        % Ex: grid.Curvilinear(mapping, xi, eta, ...)
+        %    mapping     -- either a function handle, a matrix or a cell array with physical coordinates.
+        %                   A function handle should be a vector valued function of the coordinate mapping.
+        %                   A matrix should be a grid function (N*D x 1 vector) or a N x D
+        %                   A cell array should be a 1 x D cell array with either N x 1 vectors
+        %                   or matrices of the same dimesions as the logical grid.
+        %   xi, eta, ... -- are the coordinate positions of the cartesian logical grid.
+        function obj = Curvilinear(mapping, varargin)
+            xi = varargin;
+            obj.logic = grid.Cartesian(xi{:});
+
+            % If mapping is a function evaluate it
+            if isa(mapping, 'function_handle')
+                if nargin(mapping) ~= length(varargin)
+                    error('The dimension of the mapping does not match the dimension of the logical coordinates')
+                end
+                mapping = grid.evalOn(obj.logic, mapping);
+            end
+
+            D = obj.logic.D();
+            N = obj.logic.N();
+
+            obj.coords = zeros(N,D);
+
+            if iscell(mapping)
+                obj.coords = cellMappingToCoords(mapping, N, D, obj.logic.m);
+            elseif isnumeric(mapping)
+                obj.coords = matrixMappingToCoords(mapping, N, D);
+            else
+                error('grid:Curvilinear:Curvilinear','mapping must be a function handle, a matrix or a cell array.');
+            end
+        end
+
+        function m = size(obj)
+            m = obj.logic.size();
+        end
+
+        % logicalGrid returns the domain grid of the mapping.
+        function g = logicalGrid(obj)
+            g = obj.logic;
+        end
+
+        % mapping returns the mapped coordinates as a grid.Function
+        function m = mapping(obj);
+            m = obj.coords;
+        end
+
+        % n returns the number of points in the grid
+        function o = N(obj)
+            o = obj.logic.N();
+        end
+
+        % d returns the spatial dimension of the grid
+        function o = D(obj)
+            o = obj.logic.D();
+        end
+
+        % points returns a n x d matrix containing the coordinates for all points.
+        function X = points(obj)
+            X = obj.coords;
+        end
+
+        % Restricts the grid function gf on obj to the subgrid g.
+        function gf = restrictFunc(obj, gf, g)
+            gf = obj.logic.restrictFunc(gf, g.logic);
+        end
+
+        % Projects the grid function gf on obj to the grid g.
+        function gf = projectFunc(obj, gf, g)
+            gf = obj.logic.projectFunc(gf,g.logic);
+        end
+
+        function h = scaling(obj)
+            if isempty(obj.logic.h)
+                error('grid:Curvilinear:NoScalingSet','No scaling set');
+            end
+            h = obj.logic.h;
+        end
+
+        % Return the names of all boundaries in this grid.
+        function bs = getBoundaryNames(obj)
+            bs = obj.logic.getBoundaryNames();
+        end
+
+        % Return coordinates for the given boundary
+        function X = getBoundary(obj, name)
+              % In what dimension is the boundary?
+            switch name
+                case {'l', 'r', 'w', 'e'}
+                    D = 1;
+                case {'s', 'n'}
+                    D = 2;
+                case {'d', 'u'}
+                    D = 3;
+                otherwise
+                    error('not implemented');
+            end
+
+            % At what index is the boundary?
+            switch name
+                case {'l', 'w', 's', 'd'}
+                    index = 1;
+                case {'r', 'e', 'n', 'u'}
+                    index = obj.logic.m(D);
+                otherwise
+                    error('not implemented');
+            end
+
+
+
+            I = cell(1, obj.D);
+            for i = 1:obj.D
+                if i == D
+                    I{i} = index;
+                else
+                    I{i} = ':';
+                end
+            end
+
+            % Calculate size of result:
+            m = obj.logic.m;
+            m(D) = [];
+            N = prod(m);
+
+            X = zeros(N, obj.D);
+
+            p = obj.points;
+            for i = 1:obj.D()
+                coordMat{i} = reshapeRowMaj(p(:,i), obj.logic.m);
+            end
+
+            for i = 1:length(coordMat)
+                Xtemp = coordMat{i}(I{:});
+                X(:,i) = reshapeRowMaj(Xtemp, [N,1]);
+            end
+        end
+    end
+end
+
+
+function coords = cellMappingToCoords(mapping, N, D, m)
+    if ~isequal(size(mapping),[1 D])
+        error('grid:Curvilinear:Curvilinear','The cell array must be a 1xD array.');
+    end
+
+    if isequal(size(mapping{1}),[N 1])
+        coords = cell2mat(mapping);
+    elseif isequal(size(mapping{1}), m)
+        for i = 1:length(mapping)
+            coords(:,i) = reshapeRowMaj(mapping{i}, [N 1]);
+        end
+    else
+        error('grid:Curvilinear:Curvilinear','The matrix must have size [N 1] or the same dimension as the grid. Actual: %s', toString(m));
+    end
+end
+
+function coords = matrixMappingToCoords(mapping, N, D)
+    if isequal(size(mapping), [N, D])
+        coords = mapping;
+    elseif isequal(size(mapping), [N*D, 1])
+        coords = reshapeRowMaj(mapping,[N D]);
+    else
+        error('grid:Curvilinear:Curvilinear','A matrix mapping must be of size [N D] or [N*D 1].');
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/CurvilinearTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/CurvilinearTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,131 @@
+function tests = CurvilinearTest()
+    tests = functiontests(localfunctions);
+end
+
+function testMappingInputGridFunction(testCase)
+    in = {
+        {{1:10}, @(x) exp(x)},
+        {{1:10,1:6}, @(x,y) [exp(x+y); exp(x-y)]},
+        {{1:10,1:5,1:7}, @(x,y,z)[exp(x+y+z); exp(x-y-z); 2+x+y-z]},
+    };
+
+    out = {
+        [10, 1];
+        [10*6, 2];
+        [10*5*7, 3];
+    };
+
+
+    % How to test this? Just make sure it runs without errors.
+
+    for i = 1:length(in)
+        g = grid.Curvilinear(in{i}{2},in{i}{1}{:});
+        testCase.verifyEqual(size(g.coords),out{i});
+    end
+end
+
+function testMappingInputComponentMatrix(testCase)
+    in = {
+        {{1:3}, [1 2 3]'},
+        {{1:2, 1:3}, [1 2 3 4 5 6; 7 8 9 10 11 12]'},
+    };
+
+    for i = 1:length(in)
+        g = grid.Curvilinear(in{i}{2},in{i}{1}{:});
+        testCase.verifyEqual(g.coords,in{i}{2});
+    end
+end
+
+function testMappingInputCellOfMatrix(testCase)
+
+    in = {
+        {{1:3}, {[1 2 3]'}},
+        {{1:2, 1:3}, {[1 2 3; 4 5 6], [7 8 9; 10 11 12]}},
+    };
+
+    out = {
+        [1 2 3]',
+        [1 2 3 4 5 6; 7 8 9 10 11 12]',
+    };
+
+    for i = 1:length(in)
+        g = grid.Curvilinear(in{i}{2},in{i}{1}{:});
+        testCase.verifyEqual(g.coords,out{i});
+    end
+end
+
+function testMappingInputCellOfVectors(testCase)
+    in = {
+        {{1:3}, {[1 2 3]'}},
+        {{1:2, 1:3}, {[1 2 3 4 5 6]', [7 8 9 10 11 12]'}},
+    };
+
+    out = {
+        [1 2 3]',
+        [1 2 3 4 5 6; 7 8 9 10 11 12]',
+    };
+end
+
+function testMappingInputError(testCase)
+    testCase.verifyFail();
+end
+
+function testScaling(testCase)
+    in = {{1:2, 1:3}, {[1 2 3 4 5 6]', [7 8 9 10 11 12]'}};
+    g = grid.Curvilinear(in{2},in{1}{:});
+
+    testCase.verifyError(@()g.scaling(),'grid:Curvilinear:NoScalingSet');
+
+    g.logicalGrid.h = [2 1];
+    testCase.verifyEqual(g.scaling(),[2 1]);
+end
+
+function testGetBoundaryNames(testCase)
+    in = {
+        {{1:10}, @(x) exp(x)},
+        {{1:10,1:6}, @(x,y) [exp(x+y); exp(x-y)]},
+        {{1:10,1:5,1:7}, @(x,y,z)[exp(x+y+z); exp(x-y-z); 2+x+y-z]},
+    };
+
+    out = {
+        {'l', 'r'},
+        {'w', 'e', 's', 'n'},
+        {'w', 'e', 's', 'n', 'd', 'u'},
+    };
+
+    for i = 1:length(in)
+        g = grid.Curvilinear(in{i}{2},in{i}{1}{:});
+        testCase.verifyEqual(g.getBoundaryNames(), out{i});
+    end
+end
+
+function testGetBoundary(testCase)
+    grids = {
+        {{1:10}, @(x) exp(x)},
+        {{1:10,1:6}, @(x,y) [exp(x+y); exp(x-y)]},
+        {{1:10,1:5,1:7}, @(x,y,z)[exp(x+y+z); exp(x-y-z); 2+x+y-z]},
+    };
+
+    boundaries = {
+        {'l', 'r'},
+        {'w', 'e', 's', 'n'},
+        {'w', 'e', 's', 'n', 'd', 'u'},
+    };
+
+
+    for ig = 1:length(grids)
+        g = grid.Curvilinear(grids{ig}{2},grids{ig}{1}{:});
+
+        logicalGrid = grid.Cartesian(grids{ig}{1}{:});
+
+        for ib = 1:length(boundaries{ig})
+
+            logicalBoundary = logicalGrid.getBoundary(boundaries{ig}{ib});
+
+            x = num2cell(logicalBoundary',2);
+            expectedBoundary = grids{ig}{2}(x{:})';
+            testCase.verifyEqual(g.getBoundary(boundaries{ig}{ib}), expectedBoundary);
+        end
+    end
+end
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Empty.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/Empty.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,53 @@
+classdef Empty < grid.Grid & grid.Structured
+    properties
+        dim
+    end
+
+    methods
+        function obj = Empty(D)
+            obj.dim = D;
+        end
+        % n returns the number of points in the grid
+        function o = N(obj)
+            o = 0;
+        end
+
+        % d returns the spatial dimension of the grid
+        function o = D(obj)
+            o = obj.dim;
+        end
+
+        % points returns a n x d matrix containing the coordinates for all points.
+        function X = points(obj)
+            X = sparse(0,obj.dim);
+        end
+
+        % Restricts the grid function gf on obj to the subgrid g.
+        function gf = restrictFunc(obj, gf, g)
+            error('Restrict does not make sense for an empty grid')
+        end
+
+        % Projects the grid function gf on obj to the grid g.
+        function gf = projectFunc(obj, gf, g)
+            error('Project does not make sense for an empty grid')
+        end
+
+        % Return the grid.boundaryIdentifiers of all boundaries in a cell array.
+        function bs = getBoundaryNames(obj)
+            bs = {};
+        end
+
+        % Return coordinates for the given boundary
+        function b = getBoundary(obj, name)
+            b = sparse(0,obj.dim-1);
+        end
+
+        function h = scaling(obj)
+            h = 1;
+        end
+
+        function s = size(obj)
+            s = zeros(1, obj.dim);
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Grid.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/Grid.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,25 @@
+classdef Grid < handle
+    % General d dimensional grid with n points
+    methods (Abstract)
+        % n returns the number of points in the grid
+        o = N(obj)
+
+        % d returns the spatial dimension of the grid
+        o = D(obj)
+
+        % points returns a n x d matrix containing the coordinates for all points.
+        X = points(obj)
+
+        % Restricts the grid function gf on obj to the subgrid g.
+        gf = restrictFunc(obj, gf, g)
+
+        % Projects the grid function gf on obj to the grid g.
+        gf = projectFunc(obj, gf, g)
+
+        % Return the grid.boundaryIdentifiers of all boundaries in a cell array.
+        bs = getBoundaryNames(obj)
+
+        % Return coordinates for the given boundary
+        b = getBoundary(obj, name)
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Mapped.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/Mapped.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,10 @@
+classdef Mapped < grid.Grid
+    % General grid mapping
+    methods (Abstract)
+        % logicalGrid returns the domain grid of the mapping.
+        g = logicalGrid(obj);
+
+        % mapping returns the mapped coordinates as a N x D component matrix
+        m = mapping(obj);
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Structured.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/Structured.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,7 @@
+classdef Structured < grid.Grid
+    methods (Abstract)
+        % Returns the size of the grid in each dimension m = [mx my mz ...]
+        m = size(obj); % Is this a good idea? Isn't immersed a structured grid?
+        h = scaling(obj);
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/TODO.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/TODO.txt	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,1 @@
+% TODO: Rename grid package. name conflicts with built in function
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Ti.m
--- a/+grid/Ti.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,201 +0,0 @@
-classdef Ti
-    properties
-        gs % {4}Curve
-        S  % FunctionHandle(u,v)
-    end
-
-    methods
-        % TODO function to label boundary names.
-        %  function to find largest and smallest delta h in the grid. Maybe shouldnt live here
-        function obj = Ti(C1,C2,C3,C4)
-            obj.gs = {C1,C2,C3,C4};
-
-            g1 = C1.g;
-            g2 = C2.g;
-            g3 = C3.g;
-            g4 = C4.g;
-
-            A = g1(0);
-            B = g2(0);
-            C = g3(0);
-            D = g4(0);
-
-            function o = S_fun(u,v)
-                x1 = g1(u);
-                x2 = g2(v);
-                x3 = g3(1-u);
-                x4 = g4(1-v);
-                o1 = (1-v).*x1(1,:) + u.*x2(1,:) + v.*x3(1,:) + (1-u).*x4(1,:) ...
-                    -((1-u)*(1-v).*A(1,:) + u*(1-v).*B(1,:) + u*v.*C(1,:) + (1-u)*v.*D(1,:));
-                o2 = (1-v).*x1(2,:) + u.*x2(2,:) + v.*x3(2,:) + (1-u).*x4(2,:) ...
-                    -((1-u)*(1-v).*A(2,:) + u*(1-v).*B(2,:) + u*v.*C(2,:) + (1-u)*v.*D(2,:));
-
-                o = [o1;o2];
-            end
-
-            obj.S = @S_fun;
-        end
-
-        function [X,Y] = map(obj,u,v)
-            default_arg('v',u);
-
-            if isscalar(u)
-                u = linspace(0,1,u);
-            end
-
-            if isscalar(v)
-                v = linspace(0,1,v);
-            end
-
-            S = obj.S;
-
-            nu = length(u);
-            nv = length(v);
-
-            X = zeros(nv,nu);
-            Y = zeros(nv,nu);
-
-            u = rowVector(u);
-            v = rowVector(v);
-
-            for i = 1:nv
-                p = S(u,v(i));
-                X(i,:) = p(1,:);
-                Y(i,:) = p(2,:);
-            end
-        end
-
-        function h = plot(obj,nu,nv)
-            S = obj.S;
-
-            default_arg('nv',nu)
-
-            u = linspace(0,1,nu);
-            v = linspace(0,1,nv);
-
-            m = 100;
-
-            X = zeros(nu+nv,m);
-            Y = zeros(nu+nv,m);
-
-
-            t = linspace(0,1,m);
-            for i = 1:nu
-                p = S(u(i),t);
-                X(i,:) = p(1,:);
-                Y(i,:) = p(2,:);
-            end
-
-            for i = 1:nv
-                p = S(t,v(i));
-                X(i+nu,:) = p(1,:);
-                Y(i+nu,:) = p(2,:);
-            end
-
-            h = line(X',Y');
-        end
-
-
-        function h = show(obj,nu,nv)
-            default_arg('nv',nu)
-            S = obj.S;
-
-            if(nu>2 || nv>2)
-                h_grid = obj.plot(nu,nv);
-                set(h_grid,'Color',[0 0.4470 0.7410]);
-            end
-
-            h_bord = obj.plot(2,2);
-            set(h_bord,'Color',[0.8500 0.3250 0.0980]);
-            set(h_bord,'LineWidth',2);
-        end
-
-
-        % TRANSFORMATIONS
-        function ti = translate(obj,a)
-            gs = obj.gs;
-
-            for i = 1:length(gs)
-                new_gs{i} = gs{i}.translate(a);
-            end
-
-            ti = grid.Ti(new_gs{:});
-        end
-
-        % Mirrors the Ti so that the resulting Ti is still left handed.
-        %  (Corrected by reversing curves and switching e and w)
-        function ti = mirror(obj, a, b)
-            gs = obj.gs;
-
-            new_gs = cell(1,4);
-
-            new_gs{1} = gs{1}.mirror(a,b).reverse();
-            new_gs{3} = gs{3}.mirror(a,b).reverse();
-            new_gs{2} = gs{4}.mirror(a,b).reverse();
-            new_gs{4} = gs{2}.mirror(a,b).reverse();
-
-            ti = grid.Ti(new_gs{:});
-        end
-
-        function ti = rotate(obj,a,rad)
-            gs = obj.gs;
-
-            for i = 1:length(gs)
-                new_gs{i} = gs{i}.rotate(a,rad);
-            end
-
-            ti = grid.Ti(new_gs{:});
-        end
-
-        function ti = rotate_edges(obj,n);
-            new_gs = cell(1,4);
-            for i = 0:3
-                new_i = mod(i - n,4);
-                new_gs{new_i+1} = obj.gs{i+1};
-            end
-            ti = grid.Ti(new_gs{:});
-        end
-    end
-
-    methods(Static)
-        function obj = points(p1, p2, p3, p4)
-            g1 = grid.Curve.line(p1,p2);
-            g2 = grid.Curve.line(p2,p3);
-            g3 = grid.Curve.line(p3,p4);
-            g4 = grid.Curve.line(p4,p1);
-
-            obj = grid.Ti(g1,g2,g3,g4);
-        end
-
-        function label(varargin)
-            if nargin == 2 && ischar(varargin{2})
-                label_impl(varargin{:});
-            else
-                for i = 1:length(varargin)
-                    label_impl(varargin{i},inputname(i));
-                end
-            end
-
-
-            function label_impl(ti,str)
-                S = ti.S;
-
-                pc = S(0.5,0.5);
-
-                margin = 0.1;
-                pw = S(  margin,      0.5);
-                pe = S(1-margin,      0.5);
-                ps = S(     0.5,   margin);
-                pn = S(     0.5, 1-margin);
-
-
-                ti.show(2,2);
-                grid.place_label(pc,str);
-                grid.place_label(pw,'w');
-                grid.place_label(pe,'e');
-                grid.place_label(ps,'s');
-                grid.place_label(pn,'n');
-            end
-        end
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/Ti3D.m
--- a/+grid/Ti3D.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,253 +0,0 @@
-classdef Ti3D
-    properties
-        gs % {6}Surfaces
-        V  % FunctionHandle(XI,ETA,ZETA)
-    end
-    
-    methods
-        % TODO write all fancy features for flipping around with the surfaces
-        % Each surface is defined with an outward facing outward and choosing
-        % the "corner" where XI=0 if not possible the corner where ETA=0 is choosen
-        function obj = Ti3D(CW,CE,CS,CN,CB,CT)
-            obj.gs = {CE,CW,CS,CN,CB,CT};
-            
-            gw = CW.g;
-            ge = CE.g;
-            gs = CS.g;
-            gn = CN.g;
-            gb = CB.g;
-            gt = CT.g;
-            
-            function o = V_fun(XI,ETA,ZETA)
-                XI=XI';
-                ETA=ETA';
-                ZETA=ZETA';
-                
-                one=0*ETA+1;
-                zero=0*ETA;
-                
-                Sw = gw(ETA,(1-ZETA));
-                Se = ge((1-ETA),(1-ZETA));
-                Ss = gs(XI,ZETA);
-                Sn = gn((1-XI),(1-ZETA));
-                Sb = gb((1-XI),ETA);
-                St = gt(XI,ETA);
-                
-                Ewt = gw(ETA,zero);
-                Ewb = gw(ETA,one);               
-                Ews = gw(zero,1-ZETA);
-                Ewn = gw(one,1-ZETA);
-                Eet = ge(1-ETA,zero);
-                Eeb = ge(1-ETA,one);
-                Ees = ge(one,1-ZETA);
-                Een = ge(zero,1-ZETA);
-                Enb = gn(1-XI,one);
-                Ent = gn(1-XI,zero);
-                Est = gs(XI,one);
-                Esb = gs(XI,zero);
-                
-                Cwbs = gw(zero,one);
-                Cwbn = gw(one,one);
-                Cwts = gw(zero,zero);
-                Cwtn = gw(one,zero);
-                Cebs = ge(one,one);
-                Cebn = ge(zero,one);
-                Cets = ge(one,zero);
-                Cetn = ge(zero,zero);
-                
-                
-                X1 = (1-XI).*Sw(1,:,:) + XI.*Se(1,:,:);
-                X2 = (1-ETA).*Ss(1,:,:) + ETA.*Sn(1,:,:);
-                X3 = (1-ZETA).*Sb(1,:,:) + ZETA.*St(1,:,:);
-                
-                X12 = (1-XI).*(1-ETA).*Ews(1,:,:) + (1-XI).*ETA.*Ewn(1,:,:) + XI.*(1-ETA).*Ees(1,:,:) + XI.*ETA.*Een(1,:,:);
-                X13 = (1-XI).*(1-ZETA).*Ewb(1,:,:) + (1-XI).*ZETA.*Ewt(1,:,:) + XI.*(1-ZETA).*Eeb(1,:,:) + XI.*ZETA.*Eet(1,:,:);
-                X23 = (1-ETA).*(1-ZETA).*Esb(1,:,:) + (1-ETA).*ZETA.*Est(1,:,:) + ETA.*(1-ZETA).*Enb(1,:,:) + ETA.*ZETA.*Ent(1,:,:);
-                
-                X123 = (1-XI).*(1-ETA).*(1-ZETA).*Cwbs(1,:,:) + (1-XI).*(1-ETA).*ZETA.*Cwts(1,:,:) + (1-XI).*ETA.*(1-ZETA).*Cwbn(1,:,:) + ...
-                    (1-XI).*ETA.*ZETA.*Cwtn(1,:,:) + XI.*(1-ETA).*(1-ZETA).*Cebs(1,:,:) + XI.*(1-ETA).*ZETA.*Cets(1,:,:) + ...
-                    XI.*ETA.*(1-ZETA).*Cebn(1,:,:) + XI.*ETA.*ZETA.*Cetn(1,:,:);
-                
-                X = X1 + X2 + X3 - X12 - X13 - X23 + X123;
-                
-                
-                Y1 = (1-XI).*Sw(2,:,:) + XI.*Se(2,:,:);
-                Y2 = (1-ETA).*Ss(2,:,:) + ETA.*Sn(2,:,:);
-                Y3 = (1-ZETA).*Sb(2,:,:) + ZETA.*St(2,:,:);
-                
-                Y12 = (1-XI).*(1-ETA).*Ews(2,:,:) + (1-XI).*ETA.*Ewn(2,:,:) + XI.*(1-ETA).*Ees(2,:,:) + XI.*ETA.*Een(2,:,:);
-                Y13 = (1-XI).*(1-ZETA).*Ewb(2,:,:) + (1-XI).*ZETA.*Ewt(2,:,:) + XI.*(1-ZETA).*Eeb(2,:,:) + XI.*ZETA.*Eet(2,:,:);
-                Y23 = (1-ETA).*(1-ZETA).*Esb(2,:,:) + (1-ETA).*ZETA.*Est(2,:,:) + ETA.*(1-ZETA).*Enb(2,:,:) + ETA.*ZETA.*Ent(2,:,:);
-                
-                Y123 = (1-XI).*(1-ETA).*(1-ZETA).*Cwbs(2,:,:) + (1-XI).*(1-ETA).*ZETA.*Cwts(2,:,:) + (1-XI).*ETA.*(1-ZETA).*Cwbn(2,:,:) + ...
-                    (1-XI).*ETA.*ZETA.*Cwtn(2,:,:) + XI.*(1-ETA).*(1-ZETA).*Cebs(2,:,:) + XI.*(1-ETA).*ZETA.*Cets(2,:,:) + ...
-                    XI.*ETA.*(1-ZETA).*Cebn(2,:,:) + XI.*ETA.*ZETA.*Cetn(2,:,:);
-                
-                Y = Y1 + Y2 + Y3 - Y12 - Y13 - Y23 + Y123;
-                
-                
-                Z1 = (1-XI).*Sw(3,:,:) + XI.*Se(3,:,:);
-                Z2 = (1-ETA).*Ss(3,:,:) + ETA.*Sn(3,:,:);
-                Z3 = (1-ZETA).*Sb(3,:,:) + ZETA.*St(3,:,:);
-                
-                Z12 = (1-XI).*(1-ETA).*Ews(3,:,:) + (1-XI).*ETA.*Ewn(3,:,:) + XI.*(1-ETA).*Ees(3,:,:) + XI.*ETA.*Een(3,:,:);
-                Z13 = (1-XI).*(1-ZETA).*Ewb(3,:,:) + (1-XI).*ZETA.*Ewt(3,:,:) + XI.*(1-ZETA).*Eeb(3,:,:) + XI.*ZETA.*Eet(3,:,:);
-                Z23 = (1-ETA).*(1-ZETA).*Esb(3,:,:) + (1-ETA).*ZETA.*Est(3,:,:) + ETA.*(1-ZETA).*Enb(3,:,:) + ETA.*ZETA.*Ent(3,:,:);
-                
-                Z123 = (1-XI).*(1-ETA).*(1-ZETA).*Cwbs(3,:,:) + (1-XI).*(1-ETA).*ZETA.*Cwts(3,:,:) + (1-XI).*ETA.*(1-ZETA).*Cwbn(3,:,:) + ...
-                    (1-XI).*ETA.*ZETA.*Cwtn(3,:,:) + XI.*(1-ETA).*(1-ZETA).*Cebs(3,:,:) + XI.*(1-ETA).*ZETA.*Cets(3,:,:) + ...
-                    XI.*ETA.*(1-ZETA).*Cebn(3,:,:) + XI.*ETA.*ZETA.*Cetn(3,:,:);
-                
-                Z = Z1 + Z2 + Z3 - Z12 - Z13 - Z23 + Z123;
-                o = [X;Y;Z];
-            end
-            
-            obj.V = @V_fun;
-        end
-        
-        %Should be rewritten so that the input is xi eta zeta 
-        function [X,Y,Z] = map(obj,XI,ETA,ZETA)
-            
-            V = obj.V;
-            
-            p = V(XI,ETA,ZETA);
-            X = p(1,:)';
-            Y = p(2,:)';
-            Z = p(3,:)';
-            
-        end
-        
-        %         function h = plot(obj,nu,nv)
-        %             S = obj.S;
-        %
-        %             default_arg('nv',nu)
-        %
-        %             u = linspace(0,1,nu);
-        %             v = linspace(0,1,nv);
-        %
-        %             m = 100;
-        %
-        %             X = zeros(nu+nv,m);
-        %             Y = zeros(nu+nv,m);
-        %
-        %
-        %             t = linspace(0,1,m);
-        %             for i = 1:nu
-        %                 p = S(u(i),t);
-        %                 X(i,:) = p(1,:);
-        %                 Y(i,:) = p(2,:);
-        %             end
-        %
-        %             for i = 1:nv
-        %                 p = S(t,v(i));
-        %                 X(i+nu,:) = p(1,:);
-        %                 Y(i+nu,:) = p(2,:);
-        %             end
-        %
-        %             h = line(X',Y');
-        %         end
-        %
-        %
-        %         function h = show(obj,nu,nv)
-        %             default_arg('nv',nu)
-        %             S = obj.S;
-        %
-        %             if(nu>2 || nv>2)
-        %                 h_grid = obj.plot(nu,nv);
-        %                 set(h_grid,'Color',[0 0.4470 0.7410]);
-        %             end
-        %
-        %             h_bord = obj.plot(2,2);
-        %             set(h_bord,'Color',[0.8500 0.3250 0.0980]);
-        %             set(h_bord,'LineWidth',2);
-        %         end
-        %
-        %
-        %         % TRANSFORMATIONS
-        %         function ti = translate(obj,a)
-        %             gs = obj.gs;
-        %
-        %             for i = 1:length(gs)
-        %                 new_gs{i} = gs{i}.translate(a);
-        %             end
-        %
-        %             ti = grid.Ti(new_gs{:});
-        %         end
-        %
-        %         % Mirrors the Ti so that the resulting Ti is still left handed.
-        %         %  (Corrected by reversing curves and switching e and w)
-        %         function ti = mirror(obj, a, b)
-        %             gs = obj.gs;
-        %
-        %             new_gs = cell(1,4);
-        %
-        %             new_gs{1} = gs{1}.mirror(a,b).reverse();
-        %             new_gs{3} = gs{3}.mirror(a,b).reverse();
-        %             new_gs{2} = gs{4}.mirror(a,b).reverse();
-        %             new_gs{4} = gs{2}.mirror(a,b).reverse();
-        %
-        %             ti = grid.Ti(new_gs{:});
-        %         end
-        %
-        %         function ti = rotate(obj,a,rad)
-        %             gs = obj.gs;
-        %
-        %             for i = 1:length(gs)
-        %                 new_gs{i} = gs{i}.rotate(a,rad);
-        %             end
-        %
-        %             ti = grid.Ti(new_gs{:});
-        %         end
-        %
-        %         function ti = rotate_edges(obj,n);
-        %             new_gs = cell(1,4);
-        %             for i = 0:3
-        %                 new_i = mod(i - n,4);
-        %                 new_gs{new_i+1} = obj.gs{i+1};
-        %             end
-        %             ti = grid.Ti(new_gs{:});
-        %         end
-        %     end
-        %
-        %     methods(Static)
-        %         function obj = points(p1, p2, p3, p4)
-        %             g1 = grid.Curve.line(p1,p2);
-        %             g2 = grid.Curve.line(p2,p3);
-        %             g3 = grid.Curve.line(p3,p4);
-        %             g4 = grid.Curve.line(p4,p1);
-        %
-        %             obj = grid.Ti(g1,g2,g3,g4);
-        %         end
-        %
-        %         function label(varargin)
-        %             if nargin == 2 && ischar(varargin{2})
-        %                 label_impl(varargin{:});
-        %             else
-        %                 for i = 1:length(varargin)
-        %                     label_impl(varargin{i},inputname(i));
-        %                 end
-        %             end
-        %
-        %
-        %             function label_impl(ti,str)
-        %                 S = ti.S;
-        %
-        %                 pc = S(0.5,0.5);
-        %
-        %                 margin = 0.1;
-        %                 pw = S(  margin,      0.5);
-        %                 pe = S(1-margin,      0.5);
-        %                 ps = S(     0.5,   margin);
-        %                 pn = S(     0.5, 1-margin);
-        %
-        %
-        %                 ti.show(2,2);
-        %                 grid.place_label(pc,str);
-        %                 grid.place_label(pw,'w');
-        %                 grid.place_label(pe,'e');
-        %                 grid.place_label(ps,'s');
-        %                 grid.place_label(pn,'n');
-        %             end
- %                end
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/boundaryIdentifier.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/boundaryIdentifier.txt	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,5 @@
+A grid.boundaryIdentifier identifies a boundary of a grid.
+For a Cartesian grid it is simply 's', 'n', 'w', 'e'.
+For a multiblock grid it might be something like {1, 's'}.
+For some other grid it will be up to the developer to chose
+a good way to identify boundaries.
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/equal_step_size.m
--- a/+grid/equal_step_size.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-% Calculates M so that the stepsize m/M is as close to n/M as possible
-function M = equal_step_size(n,N,m)
-    M = round((m*(N-1)+n)/n);
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/equidistant.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/equidistant.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,29 @@
+% Creates a cartesian grid of dimension length(m).
+% over the doman xlim, ylim, ...
+% Examples:
+%   g = grid.equidistant([mx, my], xlim, ylim)
+%   g = grid.equidistant([10, 15], {0,1}, {0,2})
+function g = equidistant(m, varargin)
+    if length(m) ~= length(varargin)
+        error('grid:equidistant:NonMatchingParameters','The number of provided dimensions do not match.')
+    end
+
+    for i = 1:length(m)
+        if ~iscell(varargin{i}) || numel(varargin{i}) ~= 2
+           error('grid:equidistant:InvalidLimits','The limits should be cell arrays with 2 elements.');
+        end
+
+        if varargin{i}{1} > varargin{i}{2}
+            error('grid:equidistant:InvalidLimits','The elements of the limit must be increasing.');
+        end
+    end
+
+    X = {};
+    h = [];
+    for i = 1:length(m)
+        [X{i}, h(i)] = util.get_grid(varargin{i}{:},m(i));
+    end
+
+    g = grid.Cartesian(X{:});
+    g.h = h;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/equidistantCurvilinear.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/equidistantCurvilinear.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,35 @@
+% Creates a curvilinear grid of dimension length(m).
+% over the logical domain xi_lim, eta_lim, ...
+% If all limits are ommited they are set to {0,1}.
+% Examples:
+%   g = grid.equidistantCurvilinear(mapping, [m_xi, m_eta])
+%   g = grid.equidistantCurvilinear(mapping, [m_xi, m_eta], xi_lim, eta_lim)
+%   g = grid.equidistantCurvilinear(mapping, [10, 15], {0,1}, {0,1})
+function g = equidistantCurvilinear(mapping, m, varargin)
+    if isempty(varargin)
+        varargin = repmat({{0,1}}, [1 length(m)]);
+    end
+
+    if length(m) ~= length(varargin)
+        error('grid:equidistant:NonMatchingParameters','The number of provided dimensions do not match.')
+    end
+
+    for i = 1:length(m)
+        if ~iscell(varargin{i}) || numel(varargin{i}) ~= 2
+           error('grid:equidistant:InvalidLimits','The limits should be cell arrays with 2 elements.');
+        end
+
+        if varargin{i}{1} > varargin{i}{2}
+            error('grid:equidistant:InvalidLimits','The elements of the limit must be increasing.');
+        end
+    end
+
+    X = {};
+    h = [];
+    for i = 1:length(m)
+        [X{i}, h(i)] = util.get_grid(varargin{i}{:},m(i));
+    end
+
+    g = grid.Curvilinear(mapping, X{:});
+    g.logic.h = h;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/equidistantCurvilinearTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/equidistantCurvilinearTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,7 @@
+function tests = equdistantCurvilinearTest()
+    tests = functiontests(localfunctions);
+end
+
+function testNoTests(testCase)
+    testCase.verifyFail();
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/equidistantTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/equidistantTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,50 @@
+function tests = equidistantTest()
+    tests = functiontests(localfunctions);
+end
+
+
+function testErrorInvalidLimits(testCase)
+     in  = {
+        {10,{1}},
+        {10,[0,1]},
+        {[10,10],{0,1},{1}},
+        {[10,10],{1},{1,0}},
+        {10,{1,0}},
+        {[10, 5],{1,0}, {0,-1}},
+    };
+
+    for i = 1:length(in)
+        testCase.verifyError(@()grid.equidistant(in{i}{:}),'grid:equidistant:InvalidLimits',sprintf('in(%d) = %s',i,toString(in{i})));
+    end
+end
+
+function testErrorNonMatchingParam(testCase)
+    in  = {
+        {[],{1}},
+        {[],{1},{0,1}},
+        {[5,5],{0,1},{0,1},{0,1}},
+        {[5,5,4],{0,1},{0,1}},
+    };
+
+    for i = 1:length(in)
+        testCase.verifyError(@()grid.equidistant(in{i}{:}),'grid:equidistant:NonMatchingParameters',sprintf('in(%d) = %s',i,toString(in{i})));
+    end
+end
+
+
+function testCompiles(testCase)
+    in  = {
+        {5, {0,1}},
+        {[3 3],{0,1},{0,2}},
+    };
+
+    out = {
+        [[0; 0.25; 0.5; 0.75; 1]],
+        [[0; 0; 0; 0.5; 0.5; 0.5; 1; 1; 1;],[0; 1; 2; 0; 1; 2; 0; 1; 2;]],
+    };
+
+    for i = 1:length(in)
+        g = grid.equidistant(in{i}{:});
+        testCase.verifyEqual(g.points(),out{i});
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/evalOn.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/evalOn.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,40 @@
+% Takes a function and evaluates it on a grid to return a grid function in the
+% form of a (n*k)x1 vector, where n is the number of grid points and k is the
+% number of components of the function.
+%      g -- Grid to evaluate on.
+%   func -- Function to evaluate. May be a function handle or a constant. If
+%           it is a vector value it has to be provided as a column vector,
+function gf = evalOn(g, func)
+    if ~isa(func, 'function_handle')
+        % We should have a constant.
+        assert(size(func,2) == 1,'grid:evalOn:VectorValuedWrongDim', 'A vector valued function must be given as a column vector');
+
+        gf = repmat(func,[g.N, 1]);
+        return
+    end
+    % func should now be a function_handle
+    assert(g.D == nargin(func) || nargin(func) < 0,'grid:evalOn:WrongNumberOfInputs', 'The number of inputs of the function must match the dimension of the domain.')
+
+    x = num2cell(g.points(),1);
+    k = numberOfComponents(func, g.D);
+
+    gf = func(x{:});
+    gf = reorderComponents(gf, k);
+end
+
+% Find the number of vector components of func
+function k = numberOfComponents(func, dim)
+    x0 = num2cell(ones(1, dim));
+    f0 = func(x0{:});
+    assert(size(f0,2) == 1, 'grid:evalOn:VectorValuedWrongDim', 'A vector valued function must be given as a column vector');
+    k = length(f0);
+end
+
+% Reorder the components of the function to sit together
+function gf = reorderComponents(a, k)
+    N = length(a)/k;
+    gf = zeros(N*k, 1);
+    for i = 1:k
+        gf(i:k:end) = a((i-1)*N + 1 : i*N);
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/evalOnScalar.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/evalOnScalar.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,41 @@
+% WHAT KIND OF A FUNCTION NAME IS THIS?!
+%  This functions send matrixa arguments to func unlike grid.evalOn()
+% Takes a funciton and evaluates it on a grid to return a grid function in the
+% form of a (n*k)x1 vector, where n is the number of grid points and k is the
+% number of components of the function.
+%      g -- Grid to evaluate on.
+%   func -- Function to evaluate. May be a function handle or a constant. If
+%           it is a vector value it has to be provided as a column vector,
+function gf = evalOn(g, func)
+    if ~isa(func, 'function_handle')
+        % We should have a constant.
+        if size(func,2) ~= 1
+            error('grid:evalOnScalar:VectorValuedWrongDim', 'A vector valued function must be given as a column vector')
+        end
+
+        gf = repmat(func,[g.N, 1]);
+        return
+    end
+    % func should now be a function_handle
+
+    % Get coordinates and convert to cell array for easier use as a parameter
+    x = g.points();
+    X = {};
+    for i = 1:size(x, 2)
+        X{i} = x(:,i);
+    end
+
+    % Find the number of components
+    x0 = num2cell(x(1,:));
+    f0 = func(x0{:});
+    k = length(f0);
+
+    if size(f0,2) ~= 1
+        error('grid:evalOnScalar:VectorValuedWrongDim', 'A vector valued function must be given as a column vector')
+    end
+
+    gf = func(X{:});
+    if  k > 1  % Reorder so that componets sits together.
+        gf = reshape(reshape(gf, [g.N, k])', [g.N*k, 1]);
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/evalOnScalarTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/evalOnScalarTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,118 @@
+function tests = evalOnScalarTest()
+    tests = functiontests(localfunctions);
+end
+
+function testInputConstant(testCase)
+    in  = {
+        0,
+        47,
+        1,
+        [1; 2],
+    };
+
+    out = {
+        [0; 0; 0],
+        [47; 47; 47],
+        [1; 1; 1],
+        [1; 2; 1; 2; 1; 2],
+    };
+
+    g = getTestGrid('1d');
+
+    for i = 1:length(in)
+        gf = grid.evalOnScalar(g,in{i});
+        testCase.verifyEqual(gf, out{i});
+    end
+end
+
+function testInputScalarFunction1d(testCase)
+    in  = {
+        @(x)1+x*0,
+        @(x)x,
+        @(x)x.*x,
+    };
+
+    out = {
+        [1; 1; 1],
+        [0; 1; 2],
+        [0; 1; 4],
+    };
+
+    g = getTestGrid('1d');
+
+    for i = 1:length(in)
+        gf = grid.evalOnScalar(g,in{i});
+        testCase.verifyEqual(gf, out{i});
+    end
+end
+
+function testInputScalarFunction2d(testCase)
+    in  = {
+        @(x,y)1+x*0,
+        @(x,y)x-y,
+        @(x,y)x./(1+y),
+    };
+
+    out = {
+        [1; 1; 1; 1; 1; 1; 1; 1; 1],
+        [0; -1; -2; 1; 0; -1; 2; 1; 0],
+        [0; 0; 0; 1; 1/2; 1/3; 2; 1; 2/3],
+    };
+
+    g = getTestGrid('2d');
+
+    for i = 1:length(in)
+        gf = grid.evalOnScalar(g, in{i});
+        testCase.verifyEqual(gf, out{i});
+    end
+end
+
+
+function testInputVectorFunction(testCase)
+    g = getTestGrid('1d');
+    in = @(x)[x; -2*x];
+    out = [0; 0; 1; -2; 2; -4];
+
+    gf = grid.evalOnScalar(g,in);
+    testCase.verifyEqual(gf, out);
+
+    g = getTestGrid('2d');
+    in = @(x,y)[x.^2; -2*y];
+    out = [
+        0;  0;
+        0; -2;
+        0; -4;
+        1;  0;
+        1; -2;
+        1; -4;
+        4;  0;
+        4; -2;
+        4; -4;
+    ];
+
+    gf = grid.evalOnScalar(g,in);
+    testCase.verifyEqual(gf, out);
+end
+
+
+function testInputErrorVectorValued(testCase)
+     in  = {
+        [1,2,3],
+        @(x,y)[x,-y];
+    };
+
+    g = getTestGrid('2d');
+
+    for i = 1:length(in)
+        testCase.verifyError(@()grid.evalOnScalar(g, in{i}),'grid:evalOnScalar:VectorValuedWrongDim',sprintf('in(%d) = %s',i,toString(in{i})));
+    end
+end
+
+function g = getTestGrid(d)
+    switch d
+        case '1d'
+            g = grid.equidistant(3,{0,2});
+        case '2d'
+            g = grid.equidistant([3,3],{0,2},{0,2});
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/evalOnTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/evalOnTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,133 @@
+function tests = evalOnTest()
+    tests = functiontests(localfunctions);
+end
+
+function testInputConstant(testCase)
+    in  = {
+        0,
+        47,
+        1,
+        [1; 2],
+    };
+
+    out = {
+        [0; 0; 0],
+        [47; 47; 47],
+        [1; 1; 1],
+        [1; 2; 1; 2; 1; 2],
+    };
+
+    g = getTestGrid('1d');
+
+    for i = 1:length(in)
+        gf = grid.evalOn(g,in{i});
+        testCase.verifyEqual(gf, out{i});
+    end
+end
+
+% evalOn should give and error if the number of inputs to func is not the same as
+% the number of dimensions of the grid.
+function testNumberOfInputs(testCase)
+    cases = {
+        {getTestGrid('1d'), @(x,y)x-y},
+        {getTestGrid('2d'), @(x)x    },
+    };
+
+    for i = 1:length(cases)
+        g = cases{i}{1};
+        f = cases{i}{2};
+        testCase.verifyError(@()grid.evalOn(g, f),'grid:evalOn:WrongNumberOfInputs',sprintf('in(%d) = %s',i,toString(f)));
+    end
+end
+
+function testInputScalarFunction1d(testCase)
+    in  = {
+        @(x)1+x*0,
+        @(x)x,
+        @(x)x.*x,
+    };
+
+    out = {
+        [1; 1; 1],
+        [0; 1; 2],
+        [0; 1; 4],
+    };
+
+    g = getTestGrid('1d');
+
+    for i = 1:length(in)
+        gf = grid.evalOn(g,in{i});
+        testCase.verifyEqual(gf, out{i});
+    end
+end
+
+function testInputScalarFunction2d(testCase)
+    in  = {
+        @(x,y)1+x*0,
+        @(x,y)x-y,
+        @(x,y)x./(1+y),
+    };
+
+    out = {
+        [1; 1; 1; 1; 1; 1; 1; 1; 1],
+        [0; -1; -2; 1; 0; -1; 2; 1; 0],
+        [0; 0; 0; 1; 1/2; 1/3; 2; 1; 2/3],
+    };
+
+    g = getTestGrid('2d');
+
+    for i = 1:length(in)
+        gf = grid.evalOn(g, in{i});
+        testCase.verifyEqual(gf, out{i});
+    end
+end
+
+
+function testInputVectorFunction(testCase)
+    g = getTestGrid('1d');
+    in = @(x)[x; -2*x];
+    out = [0; 0; 1; -2; 2; -4];
+
+    gf = grid.evalOn(g,in);
+    testCase.verifyEqual(gf, out);
+
+    g = getTestGrid('2d');
+    in = @(x,y)[x.^2; -2*y];
+    out = [
+        0;  0;
+        0; -2;
+        0; -4;
+        1;  0;
+        1; -2;
+        1; -4;
+        4;  0;
+        4; -2;
+        4; -4;
+    ];
+
+    gf = grid.evalOn(g,in);
+    testCase.verifyEqual(gf, out);
+end
+
+
+function testInputErrorVectorValued(testCase)
+    in  = {
+        [1,2,3],
+        @(x,y)[x,-y],
+    };
+
+    g = getTestGrid('2d');
+
+    for i = 1:length(in)
+        testCase.verifyError(@()grid.evalOn(g, in{i}),'grid:evalOn:VectorValuedWrongDim',sprintf('in(%d) = %s',i,toString(in{i})));
+    end
+end
+
+function g = getTestGrid(d)
+    switch d
+        case '1d'
+            g = grid.equidistant(3,{0,2});
+        case '2d'
+            g = grid.equidistant([3,3],{0,2},{0,2});
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/funcToComponents.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/funcToComponents.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,8 @@
+% funcToComponents converts a grid function to a N x k matrix, where
+% k is the number of vector components of the gridfunction and N is the
+% number of points in the grid.
+%
+% Takes a grid function and and a grid.
+function F = funcToComponents(g, gf);
+    F = reshapeRowMaj(gf, [g.N, length(gf)/g.N]);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/funcToComponentsTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/funcToComponentsTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,23 @@
+function tests = funcToComponentsTest()
+    tests = functiontests(localfunctions);
+end
+
+
+function testScalarGf(testCase)
+    g = getTestGrid();
+    gf_in = [1; 2; 3];
+
+    testCase.verifyEqual(grid.funcToComponents(g, gf_in), gf_in);
+end
+
+function testVectorGf(testCase)
+    g = getTestGrid();
+    gf_in = [1; 2; 3; 4; 5; 6];
+    out = [1 2; 3 4; 5 6];
+
+    testCase.verifyEqual(grid.funcToComponents(g, gf_in), out);
+end
+
+function g = getTestGrid()
+    g = grid.equidistant(3,{0,2});
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/funcToMatrix.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/funcToMatrix.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,5 @@
+% Converts a gridfunction to a matrix
+% Takes a grid function and and a structured grid.
+function F = funcToMatrix(g, gf)
+    F = reshapeRowMaj(gf, g.size());
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/funcToPlotMatrix.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/funcToPlotMatrix.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,5 @@
+% Converts a gridfunction to a plot matrix
+% Takes a grid function and and a structured grid.
+function F = funcToPlotMatrix(g, gf)
+    F = reshapeToPlotMatrix(gf, g.size());
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/gridFunction.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/gridFunction.txt	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,1 @@
+TODO: Add documentation for gridfunctions here
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/concat_curve.m
--- a/+grid/old/concat_curve.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-% Concatenate two curves g1 and g2 intop
-%   g = concat_curve(g1,g2)
-function g = concat_curve(g1,g2)
-    function v = g_fun(t)
-        if t < 1/2
-            v = g1(2*t);
-        else
-            v = g2(2*t-1);
-        end
-    end
-    g = @g_fun;
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/curve_discretise.m
--- a/+grid/old/curve_discretise.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-% Discretises the curve g with the smallest number of points such that all segments
-% are shorter than h. If do_plot is true the points of the discretisation and
-% the normals of the curve in those points are plotted.
-%
-%   [t,p,d] = curve_discretise(g,h,do_plot)
-%
-%   t is a vector of input values to g.
-%   p is a cector of points.
-%   d are the length of the segments.
-function [t,p,d] = curve_discretise(g,h,do_plot)
-    default_arg('do_plot',false)
-
-    n = 10;
-
-    [t,p,d] = curve_discretise_n(g,n);
-
-    % ni = 0;
-    while any(d>h)
-        [t,p,d] = curve_discretise_n(g,n);
-        n = ceil(n*d(1)/h);
-        % ni = ni+1;
-    end
-
-    % nj = 0;
-    while all(d<h)
-        [t,p,d] = curve_discretise_n(g,n);
-        n = n-1;
-        % nj = nj+1;
-    end
-    [t,p,d] = curve_discretise_n(g,n+1);
-
-    % fprintf('ni = %d, nj = %d\n',ni,nj);
-
-    if do_plot
-        fprintf('n:%d  max: %f min: %f\n', n, max(d),min(d));
-        p = grid.map_curve(g,t);
-        figure
-        show(g,t,h);
-    end
-
-end
-
-function [t,p,d] = curve_discretise_n(g,n)
-    t = linspace(0,1,n);
-    t = equalize_d(g,t);
-    d = D(g,t);
-    p = grid.map_curve(g,t);
-end
-
-function d = D(g,t)
-    p = grid.map_curve(g,t);
-
-    d = zeros(1,length(t)-1);
-    for i = 1:length(d)
-        d(i) = norm(p(:,i) - p(:,i+1));
-    end
-end
-
-function t = equalize_d(g,t)
-    d = D(g,t);
-    v = d-mean(d);
-    while any(abs(v)>0.01*mean(d))
-        dt = t(2:end)-t(1:end-1);
-        t(2:end) = t(2:end) - cumsum(dt.*v./d);
-
-        t = t/t(end);
-        d = D(g,t);
-        v = d-mean(d);
-    end
-end
-
-
-function show(g,t,hh)
-    p = grid.map_curve(g,t);
-
-
-
-    h = grid.plot_curve(g);
-    h.LineWidth = 2;
-    axis equal
-    hold on
-    h = plot(p(1,:),p(2,:),'.');
-    h.Color = [0.8500 0.3250 0.0980];
-    h.MarkerSize = 24;
-    hold off
-
-    n = grid.curve_normals(g,t);
-    hold on
-    for  i = 1:length(t)
-        p0 = p(:,i);
-        p1 = p0 + hh*n(:,i);
-        l = [p0, p1];
-        h = plot(l(1,:),l(2,:));
-        h.Color = [0.8500 0.3250 0.0980];
-    end
-
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/curve_interp.m
--- a/+grid/old/curve_interp.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-% Create a cubic spline from the points (x,y) using periodic conditions.
-%   g = curve_interp(x,y)
-function g = curve_interp(x,y)
-    default_arg('x',[0 2 2 1 1 0])
-    default_arg('y',[0 0 2 2 1 1])
-    % solve for xp and yp
-
-    % x(t) = at^4 + bt^2+ct+d
-
-    % a = xp1 -2x1 + 2x0 +  xp0
-    % b = 3x1 -xp1 - 3x0 + 2xp0
-    % c = xp0
-    % d = x0
-
-    assert(length(x) == length(y))
-    n = length(x);
-    A = spdiags(ones(n,1)*[2, 8, 2],-1:1,n,n);
-    A(n,1) = 2;
-    A(1,n) = 2;
-
-    bx = zeros(n,1);
-    for i = 2:n-1
-        bx(i) = -6*x(i-1)+6*x(i+1);
-    end
-    bx(1) = -6*x(n)+6*x(2);
-    bx(n) = -6*x(n-1)+6*x(1);
-
-    by = zeros(n,1);
-    for i = 2:n-1
-        by(i) = -6*y(i-1)+6*y(i+1);
-    end
-    by(1) = -6*y(n)+6*y(2);
-    by(n) = -6*y(n-1)+6*y(1);
-
-
-    xp = A\bx;
-    yp = A\by;
-
-    x(end+1) = x(1);
-    y(end+1) = y(1);
-
-    xp(end+1) = xp(1);
-    yp(end+1) = yp(1);
-
-    function v = g_fun(t)
-        t = mod(t,1);
-        i = mod(floor(t*n),n) + 1;
-        t = t * n -(i-1);
-        X = (2*x(i)-2*x(i+1)+xp(i)+xp(i+1))*t.^3 + (-3*x(i)+3*x(i+1)-2*xp(i)-xp(i+1))*t.^2 + (xp(i))*t + x(i);
-        Y = (2*y(i)-2*y(i+1)+yp(i)+yp(i+1))*t.^3 + (-3*y(i)+3*y(i+1)-2*yp(i)-yp(i+1))*t.^2 + (yp(i))*t + y(i);
-        v = [X;Y];
-    end
-
-    g = @g_fun;
-end
-
-
-
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/max_h.m
--- a/+grid/old/max_h.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-function [d_max, i1_max, j1_max, i2_max, j2_max] = max_h(X,Y)
-    ni = size(X,1);
-    nj = size(X,2);
-    d_max = 0;
-
-    i1_max = 0;
-    j1_max = 0;
-    i2_max = 0;
-    j2_max = 0;
-
-    D = {[0,-1],[1,0],[0,1],[-1,0]};
-
-    for i = 1:ni
-        for j = 1:nj
-            p1 = [X(i,j); Y(i,j)];
-            for k = 1:length(D)
-                i2 = i+D{k}(1);
-                j2 = j+D{k}(2);
-                if i2 >= 1 && i2 <= ni && j2 >= 1 && j2 <= nj
-                    p2 = [X(i2,j2); Y(i2,j2)];
-                    d = norm(p2-p1);
-                    if d > d_max;
-                        d_max = d;
-                        i1_max = i;
-                        j1_max = j;
-                        i2_max = i2;
-                        j2_max = j2;
-                    end
-                end
-            end
-        end
-    end
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/min_h.m
--- a/+grid/old/min_h.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-function [d_min, i1_min, j1_min, i2_min, j2_min] = min_h(X,Y)
-    ni = size(X,1);
-    nj = size(X,2);
-    d_min = norm([X(1,1);Y(1,1)] - [X(ni,nj);Y(ni,nj)]);
-
-    i1_min = 0;
-    j1_min = 0;
-    i2_min = 0;
-    j2_min = 0;
-
-    D = {[-1,-1],[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0]};
-    % D = {[0,-1],[1,0],[0,1],[-1,0]};
-
-    for i = 1:ni
-        for j = 1:nj
-            p1 = [X(i,j); Y(i,j)];
-            for k = 1:length(D)
-                i2 = i+D{k}(1);
-                j2 = j+D{k}(2);
-                if i2 >= 1 && i2 <= ni && j2 >= 1 && j2 <= nj
-                    p2 = [X(i2,j2); Y(i2,j2)];
-                    d = norm(p2-p1);
-                    if d < d_min;
-                        d_min = d;
-                        i1_min = i;
-                        j1_min = j;
-                        i2_min = i2;
-                        j2_min = j2;
-                    end
-                end
-            end
-        end
-    end
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/plot_shape.m
--- a/+grid/old/plot_shape.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-% Plot a shape using n points. Returns cell array of plot handles.
-%   hs = plot_shape(s,n)
-function hs = plot_shape(s,n)
-    default_arg('n',100);
-
-    hs = {};
-    hold on
-    for i = 1:length(s)
-        hs{end+1} = grid.plot_curve(s{i},n);
-    end
-    hold off
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/shape.m
--- a/+grid/old/shape.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-% Creates a shape from a number of curves. A shape is a cell array of curves.
-function s = shape(varargin);
-    s = varargin;
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/shape_discretise.m
--- a/+grid/old/shape_discretise.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-% Discretises a shape such that points on the curves are no further than h appart.
-function p = shape_discretise(s,h)
-    p = [];
-    for i = 1:length(s)
-        [~,pt] = grid.curve_discretise(s{i},h);
-        p = [p, pt];
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/shape_linesegments.m
--- a/+grid/old/shape_linesegments.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,9 +0,0 @@
-% Converts a shape into a cell array of linesegments shorter than h.
-function l = shape_linesegments(s,h)
-    l = {};
-
-    for i = 1:length(s)
-        t = grid.curve_discretise(s{i},h);
-        l = [l, grid.curve_linesegments(s{i},t)];
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/triang_interp.m
--- a/+grid/old/triang_interp.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,132 +0,0 @@
-classdef triang_interp
-    properties
-        g1, g2 ,g3  % Curves encirling the tirangle in the positive direction.
-        A,B,C  % The corners of the triangle
-        Sa, Sb, Sc % Mappings from square with different sides collapsed
-    end
-
-    methods
-        function o = triang_interp(g1,g2,g3)
-            o.g1 = g1;
-            o.g2 = g2;
-            o.g3 = g3;
-            o.A = g1(0);
-            o.B = g2(0);
-            o.C = g3(0);
-            o.Sa = grid.triang_interp.square_to_triangle_interp(g2,g3,g1);
-            o.Sb = grid.triang_interp.square_to_triangle_interp(g3,g1,g2);
-            o.Sc = grid.triang_interp.square_to_triangle_interp(g1,g2,g3);
-        end
-
-
-        function show(o,N)
-            % Show the mapped meridians of the triangle.
-            % Might be used for the barycentric coordinates.
-            ma = @(t)o.Sa(1/2,1-t);
-            mb = @(t)o.Sb(1/2,1-t);
-            mc = @(t)o.Sc(1/2,1-t);
-
-            na = @(t)o.Sa(t,1/2);
-
-            ka = @(t)(o.g1(1-t)+o.g2(t))/2;
-
-            h = grid.plot_curve(ma);
-            h.Color = Color.blue;
-            h = grid.plot_curve(mb);
-            h.Color = Color.blue;
-            h = grid.plot_curve(mc);
-            h.Color = Color.blue;
-
-            h = grid.plot_curve(na);
-            h.Color = Color.red;
-
-            h = grid.plot_curve(ka);
-            h.Color = Color.red;
-
-            [a(1),a(2)] = ma(1/3);
-            [b(1),b(2)] = mb(1/3);
-            [c(1),c(2)] = mc(1/3);
-
-            d = ka(1-1/3);
-
-
-            grid.label_pt(a,b,c,d);
-
-
-            % t = linspace(0,1,N);
-            % for i = 1:N
-            %     sa = @(s)o.Sa(s,t(i));
-            %     sb = @(s)o.Sb(s,t(i));
-            %     sc = @(s)o.Sc(s,t(i));
-
-            %     h = grid.plot_curve(sa);
-            %     h.Color = Color.blue;
-            %     h = grid.plot_curve(sb);
-            %     h.Color = Color.blue;
-            %     h = grid.plot_curve(sc);
-            %     h.Color = Color.blue;
-            % end
-
-            h = grid.plot_curve(o.g1);
-            h.LineWidth = 2;
-            h.Color = Color.red;
-
-            h = grid.plot_curve(o.g2);
-            h.LineWidth = 2;
-            h.Color = Color.red;
-
-            h = grid.plot_curve(o.g3);
-            h.LineWidth = 2;
-            h.Color = Color.red;
-
-        end
-
-
-    end
-
-    methods(Static)
-        % Makes a mapping from the unit square to a triangle by collapsing
-        % one of the sides of the squares to a corner on the triangle
-        % The collapsed side is mapped to the corner oposite to g1.
-        % This is done such that for S(s,t), S(s,1) = g1(s)
-        function S = square_to_triangle_interp(g1,g2,g3)
-            corner = grid.line_segment(g3(0),g3(0));
-            S = grid.transfinite_interp(corner,g3,f(g1),f(g2))
-
-            % Function to flip a curve
-            function h = f(g)
-                h = @(t)g(1-t);
-            end
-        end
-    end
-
-end
-
-% % Return a mapping from u.v to x,y of the domain encircled by g1 g2 g3 in the the positive direction. created be using transfinite interpolation.
-% function S = triang_interp(g1,g2,g3)
-%     A = g1(0)
-%     B = g2(0)
-%     C = g3(0)
-
-%     function [x,y] = S_fun(u,v)
-%         w = sqrt((u-1)^2+v^2)/sqrt(2); % Parameter for g3
-%         v = v*(1-u-v)*g1(u) + u*(1-u-v)*g2(v) + u*v*g3(w) ...
-%             +(1-u)*(1-v)*A+u*(1-v)*B + (1-u)*v*C;
-%         x = v(1);
-%         y = v(2);
-%     end
-%     S = @S_fun;
-% end
-
-
-
-% function subsref(obj,S)
-%       if ~all(isnumeric(S.subs{:}))
-%         error('Only supports calling object with number')
-%       end
-%       if numel(S.subs{:}) > 1
-%         disp('You''ve called the object with more than one argument');
-%       else
-%         disp(['You called the object with argument = ',num2str(S.subs{:})]);
-%       end
-%     end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/triang_interp_pts.m
--- a/+grid/old/triang_interp_pts.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-% Creates a transfinite interpolation from connecting the four points wiht straight lines.
-function [S, g1, g2, g3] = triang_interp_pts(p1,p2,p3)
-    if size(p1) ~= [2 1]
-        error('p1 is strange!');
-    end
-
-    g1 = @(t)(p1 + t*(p2-p1));
-    g2 = @(t)(p2 + t*(p3-p2));
-    g3 = @(t)(p3 + t*(p1-p3));
-
-    S = grid.triang_interp(g1,g2,g3);
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/triang_map.m
--- a/+grid/old/triang_map.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,29 +0,0 @@
-% Creates a grid [X,Y] from the mapping function S at points in vectors u,v
-function [X, Y] = traing_map(S,u,v)
-    error('not done')
-    if nargin == 2
-        v = u;
-    end
-
-    if isscalar(u)
-        u = linspace(0,1,u);
-    end
-
-    if isscalar(v)
-        v = linspace(0,1,v);
-    end
-
-    nu = length(u);
-    nv = length(v);
-
-    X = zeros(nu,nv);
-    Y = zeros(nu,nv);
-
-    for i = 1:nu
-        for j = 1:nv
-            [x,y] = S(u(i),v(j));
-            X(i,j) = x;
-            Y(i,j) = y;
-        end
-    end
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/triang_plot_interp.m
--- a/+grid/old/triang_plot_interp.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-% Plots a transfinite interpolation in x,y space using nu and nv curves along u and v axes.
-
-
-
-
-
-
-% Plots a interp of a triangle where one the interpolation is from a square
-% with one side collapsed to
-function h = triang_plot_interp_kindaworking(S,n)
-    u = linspace(0,1,n);
-    v = linspace(0,1,n);
-
-    m = 100;
-    m = 20;
-
-    Xl_curves = cell(n,1);
-    Xr_curves = cell(n,1);
-    Y_curves = cell(n,1);
-
-
-    function u = wierdness(v,d,N)
-        if N == 0
-            u = 0;
-        else
-            u = N*d./(1-v);
-        end
-    end
-
-
-    %Y curves
-    t = linspace(0,1,m);
-    for i = 1:n
-        x = []; y = [];
-        for j = 1:length(t)
-            [x(j),y(j)] = S(t(j),v(i));
-        end
-        Y_curves{i} = [x', y'];
-    end
-
-
-    % Right and left X curves
-    t = linspace(0,1,m);
-    d = u(2);
-    for i = 1:n
-        xl = []; yl = [];
-        xr = []; yr = [];
-        N = i-1;
-        t = linspace(0,1-N*d,m);
-        for j = 1:length(t)
-            w = wierdness(t(j),d,N);
-            [xr(j),yr(j)] = S(w,t(j));
-            [xl(j),yl(j)] = S(1-w,t(j));
-        end
-        Xl_curves{i} = [xl', yl'];
-        Xr_curves{i} = [xr', yr'];
-    end
-
-    for i = 1:n-1
-        line(Xl_curves{i}(:,1),Xl_curves{i}(:,2))
-        line(Xr_curves{i}(:,1),Xr_curves{i}(:,2))
-        line(Y_curves{i}(:,1),Y_curves{i}(:,2))
-    end
-end
-
-
-
-
-function h = triang_plot_interp_nonworking(S,n)
-
-    u = linspace(0,1,n);
-    v = linspace(0,1,n);
-
-    m = 100;
-
-    X_curves = cell(n-1,1);
-    Y_curves = cell(n-1,1);
-    K_curves = cell(n-1,1);
-
-
-    t = linspace(0,1,m);
-    for i = 1:n-1
-        x = []; y = [];
-        for j = find(t+u(i) <= 1)
-            [x(j),y(j)] = S(u(i),t(j));
-        end
-        X_curves{i} = [x', y'];
-    end
-
-    for i = 1:n-1
-        x = []; y = [];
-        for j = find(t+v(i) <= 1)
-            [x(j),y(j)] = S(t(j),v(i));
-        end
-        Y_curves{i} = [x', y'];
-    end
-
-    for i = 2:n
-        x = []; y = [];
-        for j = find(t<u(i))
-            [x(j),y(j)] = S(t(j), u(i)-t(j));
-        end
-        K_curves{i-1} = [x', y'];
-    end
-
-    for i = 1:n-1
-        line(X_curves{i}(:,1),X_curves{i}(:,2))
-        line(Y_curves{i}(:,1),Y_curves{i}(:,2))
-        line(K_curves{i}(:,1),K_curves{i}(:,2))
-    end
-
-    h = -1;
-    % h = plot(X_curves{:},Y_curves{:},K_curves{:});
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/old/triang_show.m
--- a/+grid/old/triang_show.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,23 +0,0 @@
-% Show a grid as a matlab figure.
-function triang_show(S,n)
-
-    ih = ishold();
-
-    hold on
-    h_grid = grid.triang_plot_interp(S,n);
-    h_bord = grid.triang_plot_interp(S,2);
-
-    set(h_grid,'Color',[0 0.4470 0.7410]);
-    set(h_bord,'Color',[0.8500 0.3250 0.0980]);
-    set(h_bord,'LineWidth',2);
-
-    % axis auto
-    % axis equal
-    % axis square
-
-    if ih
-        hold on
-    else
-        hold off
-    end
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +grid/place_label.m
--- a/+grid/place_label.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,12 +0,0 @@
-% 'left' | 'center' | 'right'
-% 'baseline' | 'top' | 'cap' | 'middle' | 'bottom'
-function place_label(pt,str,horzAl,vertAl)
-    default_arg('horzAl','center');
-    default_arg('vertAl', 'middle');
-
-    x = pt(1);
-    y = pt(2);
-    h = text(x,y,str);
-    h.HorizontalAlignment = horzAl;
-    h.VerticalAlignment = vertAl;
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/+domain/Circle.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/+domain/Circle.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,98 @@
+classdef Circle < multiblock.DefCurvilinear
+    properties
+        r, c
+
+        hs
+        r_arc
+        omega
+    end
+
+    methods
+        function obj = Circle(r, c, hs)
+            default_arg('r', 1);
+            default_arg('c', [0; 0]);
+            default_arg('hs', 0.435);
+
+
+            % alpha = 0.75;
+            % hs = alpha*r/sqrt(2);
+
+            % Square should not be a square, it should be an arc. The arc radius
+            % is chosen so that the three angles of the meshes are all equal.
+            % This gives that the (half)arc opening angle of should be omega = pi/12
+            omega = pi/12;
+            r_arc = hs*(2*sqrt(2))/(sqrt(3)-1); %  = hs* 1/sin(omega)
+            c_arc = c - [(1/(2-sqrt(3))-1)*hs; 0];
+
+            cir = parametrization.Curve.circle(c,r,[-pi/4 pi/4]);
+
+            c2 = cir(0);
+            c3 = cir(1);
+
+            s1 = [-hs; -hs];
+            s2 = [ hs; -hs];
+            s3 = [ hs;  hs];
+            s4 = [-hs;  hs];
+
+            sp2 = parametrization.Curve.line(s2,c2);
+            sp3 = parametrization.Curve.line(s3,c3);
+
+            Se1 = parametrization.Curve.circle(c_arc,r_arc,[-omega, omega]);
+            Se2 = Se1.rotate(c,pi/2);
+            Se3 = Se2.rotate(c,pi/2);
+            Se4 = Se3.rotate(c,pi/2);
+
+
+            S = parametrization.Ti(Se1,Se2,Se3,Se4).rotate_edges(-1);
+
+            A = parametrization.Ti(sp2, cir, sp3.reverse, Se1.reverse);
+            B = A.rotate(c,1*pi/2).rotate_edges(-1);
+            C = A.rotate(c,2*pi/2).rotate_edges(-1);
+            D = A.rotate(c,3*pi/2).rotate_edges(0);
+
+            blocks = {S,A,B,C,D};
+            blocksNames = {'S','A','B','C','D'};
+
+            conn = cell(5,5);
+            conn{1,2} = {'e','w'};
+            conn{1,3} = {'n','s'};
+            conn{1,4} = {'w','s'};
+            conn{1,5} = {'s','w'};
+
+            conn{2,3} = {'n','e'};
+            conn{3,4} = {'w','e'};
+            conn{4,5} = {'w','s'};
+            conn{5,2} = {'n','s'};
+
+            boundaryGroups = struct();
+            boundaryGroups.E = multiblock.BoundaryGroup({2,'e'});
+            boundaryGroups.N = multiblock.BoundaryGroup({3,'n'});
+            boundaryGroups.W = multiblock.BoundaryGroup({4,'n'});
+            boundaryGroups.S = multiblock.BoundaryGroup({5,'e'});
+            boundaryGroups.all = multiblock.BoundaryGroup({{2,'e'},{3,'n'},{4,'n'},{5,'e'}});
+
+            obj = obj@multiblock.DefCurvilinear(blocks, conn, boundaryGroups, blocksNames);
+
+            obj.r     = r;
+            obj.c     = c;
+            obj.hs    = hs;
+            obj.r_arc = r_arc;
+            obj.omega = omega;
+        end
+
+        function ms = getGridSizes(obj, m)
+            m_S = m;
+
+            % m_Radial
+            s = 2*obj.hs;
+            innerArc = obj.r_arc*obj.omega;
+            outerArc = obj.r*pi/2;
+            shortSpoke = obj.r-s/sqrt(2);
+            x = (1/(2-sqrt(3))-1)*obj.hs;
+            longSpoke =  (obj.r+x)-obj.r_arc;
+            m_R = parametrization.equal_step_size((innerArc+outerArc)/2, m_S, (shortSpoke+longSpoke)/2);
+
+            ms = {[m_S m_S], [m_R m_S], [m_S m_R], [m_S m_R], [m_R m_S]};
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/+domain/Rectangle.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/+domain/Rectangle.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,188 @@
+classdef Rectangle < multiblock.Definition
+    properties
+
+    blockTi % Transfinite interpolation objects used for plotting
+    xlims
+    ylims
+    blockNames % Cell array of block labels
+    nBlocks
+    connections % Cell array specifying connections between blocks
+    boundaryGroups % Structure of boundaryGroups
+
+    end
+
+
+    methods
+        % Creates a divided rectangle
+        % x and y are vectors of boundary and interface positions.
+        % blockNames: cell array of labels. The id is default.
+        function obj = Rectangle(x,y,blockNames)
+            default_arg('blockNames',[]);
+
+            n = length(y)-1; % number of blocks in the y direction.
+            m = length(x)-1; % number of blocks in the x direction.
+            N = n*m; % number of blocks
+
+            if ~issorted(x)
+                error('The elements of x seem to be in the wrong order');
+            end
+            if ~issorted(flip(y))
+                error('The elements of y seem to be in the wrong order');
+            end
+
+            % Dimensions of blocks and number of points
+            blockTi = cell(N,1);
+            xlims = cell(N,1);
+            ylims = cell(N,1);
+            for i = 1:n
+                for j = 1:m
+                    p1 = [x(j), y(i+1)];
+                    p2 = [x(j+1), y(i)];
+                    I = flat_index(m,j,i);
+                    blockTi{I} = parametrization.Ti.rectangle(p1,p2);
+                    xlims{I} = {x(j), x(j+1)};
+                    ylims{I} = {y(i+1), y(i)};
+                end
+            end
+
+            % Interface couplings
+            conn = cell(N,N);
+            for i = 1:n
+                for j = 1:m
+                    I = flat_index(m,j,i);
+                    if i < n
+                        J = flat_index(m,j,i+1);
+                        conn{I,J} = {'s','n'};
+                    end
+
+                    if j < m
+                        J = flat_index(m,j+1,i);
+                        conn{I,J} = {'e','w'};
+                    end
+                end
+            end
+
+            % Block names (id number as default)
+            if isempty(blockNames)
+                obj.blockNames = cell(1, N);
+                for i = 1:N
+                    obj.blockNames{i} = sprintf('%d', i);
+                end
+            else
+                assert(length(blockNames) == N);
+                obj.blockNames = blockNames;
+            end
+            nBlocks = N;
+
+            % Boundary groups
+            boundaryGroups = struct();
+            nx = m;
+            ny = n;
+            E = cell(1,ny);
+            W = cell(1,ny);
+            S = cell(1,nx);
+            N = cell(1,nx);
+            for i = 1:ny
+                E_id = flat_index(m,nx,i);
+                W_id = flat_index(m,1,i);
+                E{i} = {E_id,'e'};
+                W{i} = {W_id,'w'};
+            end
+            for j = 1:nx
+                S_id = flat_index(m,j,ny);
+                N_id = flat_index(m,j,1);
+                S{j} = {S_id,'s'};
+                N{j} = {N_id,'n'};
+            end  
+            boundaryGroups.E = multiblock.BoundaryGroup(E);
+            boundaryGroups.W = multiblock.BoundaryGroup(W);
+            boundaryGroups.S = multiblock.BoundaryGroup(S);
+            boundaryGroups.N = multiblock.BoundaryGroup(N);
+            boundaryGroups.all = multiblock.BoundaryGroup([E,W,S,N]);
+            boundaryGroups.WS = multiblock.BoundaryGroup([W,S]);
+            boundaryGroups.WN = multiblock.BoundaryGroup([W,N]);
+            boundaryGroups.ES = multiblock.BoundaryGroup([E,S]);
+            boundaryGroups.EN = multiblock.BoundaryGroup([E,N]);
+
+            obj.connections = conn;
+            obj.nBlocks = nBlocks;
+            obj.boundaryGroups = boundaryGroups;
+            obj.blockTi = blockTi;
+            obj.xlims = xlims;
+            obj.ylims = ylims;
+
+        end
+
+
+        % Returns a multiblock.Grid given some parameters
+        % ms: cell array of [mx, my] vectors
+        % For same [mx, my] in every block, just input one vector.
+        function g = getGrid(obj, ms, varargin)
+
+            default_arg('ms',[21,21])
+
+            % Extend ms if input is a single vector
+            if (numel(ms) == 2) && ~iscell(ms)
+                m = ms;
+                ms = cell(1,obj.nBlocks);
+                for i = 1:obj.nBlocks
+                    ms{i} = m;
+                end
+            end
+
+            grids = cell(1, obj.nBlocks);
+            for i = 1:obj.nBlocks
+                grids{i} = grid.equidistant(ms{i}, obj.xlims{i}, obj.ylims{i});
+            end
+
+            g = multiblock.Grid(grids, obj.connections, obj.boundaryGroups);
+        end
+
+        % label is the type of label used for plotting,
+        % default is block name, 'id' show the index for each block.
+        function show(obj, label, gridLines, varargin)
+            default_arg('label', 'name')
+            default_arg('gridLines', false);
+
+            if isempty('label') && ~gridLines
+                for i = 1:obj.nBlocks
+                    obj.blockTi{i}.show(2,2);
+                end
+                axis equal
+                return
+            end
+
+            if gridLines
+                m = 10;
+                for i = 1:obj.nBlocks
+                    obj.blockTi{i}.show(m,m);
+                end
+            end
+
+
+            switch label
+                case 'name'
+                    labels = obj.blockNames;
+                case 'id'
+                    labels = {};
+                    for i = 1:obj.nBlocks
+                        labels{i} = num2str(i);
+                    end
+                otherwise
+                    axis equal
+                    return
+            end
+
+            for i = 1:obj.nBlocks
+                parametrization.Ti.label(obj.blockTi{i}, labels{i});
+            end
+
+            axis equal
+        end
+
+        % Returns the grid size of each block in a cell array
+        % The input parameters are determined by the subclass
+        function ms = getGridSizes(obj, varargin)
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/BoundaryGroup.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/BoundaryGroup.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,19 @@
+% BoundaryGroup defines a boundary grouping in a multiblock grid.
+% It workds like a cell array and collects boundary identifiers
+% Within the multiblock package a BoundaryGroup is a valid boundary identifier as well.
+classdef BoundaryGroup < Cell
+    methods
+        function obj = BoundaryGroup(data)
+            obj = obj@Cell(data);
+        end
+
+        function display(obj, name)
+
+            disp(' ')
+            disp([name, ' ='])
+            disp(' ')
+
+            fprintf('    BoundaryGroup%s\n\n', toString(obj.data));
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/Contour.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Contour.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,65 @@
+classdef Contour < handle
+    properties
+        grid
+        contours
+        nContours
+
+        ZData
+        CData
+
+    end
+
+    methods
+        function obj = Contour(g, gf, nContours)
+            obj.grid = g;
+            obj.nContours = nContours;
+
+            coords = obj.grid.points();
+            X = obj.grid.funcToPlotMatrices(coords(:,1));
+            Y = obj.grid.funcToPlotMatrices(coords(:,2));
+
+            V = obj.grid.funcToPlotMatrices(gf);
+
+
+            holdState = ishold();
+            hold on
+
+            contours = {1, obj.grid.nBlocks};
+            for i = 1:obj.grid.nBlocks
+                [~, contours{i}] = contour(X{i}, Y{i}, V{i},obj.nContours);
+                contours{i}.LevelList = contours{1}.LevelList;
+            end
+
+            if holdState == false
+                hold off
+            end
+
+            obj.contours = [contours{:}];
+
+            obj.ZData = gf;
+            obj.CData = gf;
+        end
+
+        function set(obj, propertyName, propertyValue)
+            set(obj.contours, propertyName, propertyValue);
+        end
+
+        function obj = set.ZData(obj, gf)
+            obj.ZData = gf;
+
+            V = obj.grid.funcToPlotMatrices(gf);
+            for i = 1:obj.grid.nBlocks
+                obj.contours(i).ZData = V{i};
+            end
+        end
+
+        function obj = set.CData(obj, gf)
+            obj.CData = gf;
+
+            V = obj.grid.funcToPlotMatrices(gf);
+            for i = 1:obj.grid.nBlocks
+                obj.contours(i).CData = V{i};
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/DefCurvilinear.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/DefCurvilinear.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,102 @@
+classdef DefCurvilinear < multiblock.Definition
+    properties
+        nBlocks
+        blockMaps % Maps from logical blocks to physical blocks build from transfinite interpolation
+        blockNames
+        connections % Cell array specifying connections between blocks
+        boundaryGroups % Structure of boundaryGroups
+    end
+
+    methods
+        % Defines a multiblock setup for transfinite interpolation blocks
+        % TODO: How to bring in plotting of points?
+        function obj = DefCurvilinear(blockMaps, connections, boundaryGroups, blockNames)
+            default_arg('boundaryGroups', struct());
+            default_arg('blockNames',{});
+
+            nBlocks = length(blockMaps);
+
+            obj.nBlocks = nBlocks;
+
+            obj.blockMaps = blockMaps;
+
+            assert(all(size(connections) == [nBlocks, nBlocks]));
+            obj.connections = connections;
+
+
+            if isempty(blockNames)
+                obj.blockNames = cell(1, nBlocks);
+                for i = 1:length(blockMaps)
+                    obj.blockNames{i} = sprintf('%d', i);
+                end
+            else
+                assert(length(blockNames) == nBlocks);
+                obj.blockNames = blockNames;
+            end
+
+            obj.boundaryGroups = boundaryGroups;
+        end
+
+        function g = getGrid(obj, varargin)
+            ms = obj.getGridSizes(varargin{:});
+
+            grids = cell(1, obj.nBlocks);
+            for i = 1:obj.nBlocks
+                grids{i} = grid.equidistantCurvilinear(obj.blockMaps{i}.S, ms{i});
+            end
+
+            g = multiblock.Grid(grids, obj.connections, obj.boundaryGroups);
+        end
+
+        function h = show(obj, label, gridLines, varargin)
+            default_arg('label', 'name')
+            default_arg('gridLines', false);
+
+            h = [];
+            if isempty('label') && ~gridLines
+                for i = 1:obj.nBlocks
+                    h = [h, obj.blockMaps{i}.show(2,2)];
+                end
+                axis equal
+                return
+            end
+
+            if gridLines
+                ms = obj.getGridSizes(varargin{:});
+                for i = 1:obj.nBlocks
+                    h = [h, obj.blockMaps{i}.show(ms{i}(1),ms{i}(2))];
+                end
+            end
+
+
+            switch label
+                case 'name'
+                    labels = obj.blockNames;
+                case 'id'
+                    labels = {};
+                    for i = 1:obj.nBlocks
+                        labels{i} = num2str(i);
+                    end
+                case 'none'
+                    axis equal
+                    return
+            end
+
+            for i = 1:obj.nBlocks
+                parametrization.Ti.label(obj.blockMaps{i}, labels{i});
+            end
+
+            axis equal
+        end
+    end
+
+    methods (Abstract)
+        % Returns the grid size of each block in a cell array
+        % The input parameters are determined by the subclass
+        ms = getGridSizes(obj, varargin)
+        % end
+    end
+
+end
+
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/Definition.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Definition.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,11 @@
+classdef Definition
+    methods (Abstract)
+
+        % Returns a multiblock.Grid given some parameters
+        g = getGrid(obj, varargin)
+
+        % label is the type of label used for plotting,
+        % default is block name, 'id' show the index for each block.
+        show(obj, label, gridLines, varargin)
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/DiffOp.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/DiffOp.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,245 @@
+classdef DiffOp < scheme.Scheme
+    properties
+        grid
+        order
+        diffOps
+        D
+        H
+
+        blockmatrixDiv
+    end
+
+    methods
+        function obj = DiffOp(doHand, g, order, doParam)
+            %  doHand -- may either be a function handle or a cell array of
+            %            function handles for each grid. The function handle(s)
+            %            should be on the form do = doHand(grid, order, ...)
+            %            Additional parameters for each doHand may be provided in
+            %            the doParam input.
+            %       g -- a multiblock grid
+            %   order -- integer specifying the order of accuracy
+            % doParam -- may either be a cell array or a cell array of cell arrays
+            %            for each block. If it is a cell array with length equal
+            %            to the number of blocks then each element is sent to the
+            %            corresponding function handle as extra parameters:
+            %            doHand(..., doParam{i}{:}) Otherwise doParam is sent as
+            %            extra parameters to all doHand: doHand(..., doParam{:})
+            default_arg('doParam', [])
+
+            [getHand, getParam] = parseInput(doHand, g, doParam);
+
+            nBlocks = g.nBlocks();
+
+            obj.order = order;
+
+            % Create the diffOps for each block
+            obj.diffOps = cell(1, nBlocks);
+            for i = 1:nBlocks
+                h = getHand(i);
+                p = getParam(i);
+                if ~iscell(p)
+                    p = {p};
+                end
+                obj.diffOps{i} = h(g.grids{i}, order, p{:});
+            end
+
+
+            % Build the norm matrix
+            H = cell(nBlocks, nBlocks);
+            for i = 1:nBlocks
+                H{i,i} = obj.diffOps{i}.H;
+            end
+            obj.H = blockmatrix.toMatrix(H);
+
+
+            % Build the differentiation matrix
+            Ns = zeros(nBlocks,1);
+            for i = 1:nBlocks
+                Ns(i) = length(obj.diffOps{i}.D);
+            end
+            obj.blockmatrixDiv = {Ns, Ns};
+            D = blockmatrix.zero(obj.blockmatrixDiv);
+            for i = 1:nBlocks
+                D{i,i} = obj.diffOps{i}.D;
+            end
+
+            for i = 1:nBlocks
+                for j = 1:nBlocks
+                    intf = g.connections{i,j};
+                    if isempty(intf)
+                        continue
+                    end
+
+
+                    [ii, ij] = obj.diffOps{i}.interface(intf{1}, obj.diffOps{j}, intf{2});
+                    D{i,i} = D{i,i} + ii;
+                    D{i,j} = D{i,j} + ij;
+
+                    [jj, ji] = obj.diffOps{j}.interface(intf{2}, obj.diffOps{i}, intf{1});
+                    D{j,j} = D{j,j} + jj;
+                    D{j,i} = D{j,i} + ji;
+                end
+            end
+            obj.D = blockmatrix.toMatrix(D);
+            obj.grid = g;
+
+
+            function [getHand, getParam] = parseInput(doHand, g, doParam)
+                if ~isa(g, 'multiblock.Grid')
+                    error('multiblock:DiffOp:DiffOp:InvalidGrid', 'Requires a multiblock grid.');
+                end
+
+                if iscell(doHand) && length(doHand) == g.nBlocks()
+                    getHand = @(i)doHand{i};
+                elseif isa(doHand, 'function_handle')
+                    getHand = @(i)doHand;
+                else
+                    error('multiblock:DiffOp:DiffOp:InvalidGridDoHand', 'doHand must be a function handle or a cell array of length grid.nBlocks');
+                end
+
+                if isempty(doParam)
+                    getParam = @(i){};
+                    return
+                end
+
+                if ~iscell(doParam)
+                    getParam = @(i)doParam;
+                    return
+                end
+
+                % doParam is a non-empty cell-array
+
+                if length(doParam) == g.nBlocks() && all(cellfun(@iscell, doParam))
+                    % doParam is a cell-array of cell-arrays
+                    getParam = @(i)doParam{i};
+                    return
+                end
+
+                getParam = @(i)doParam;
+            end
+        end
+
+        function ops = splitOp(obj, op)
+            % Splits a matrix operator into a cell-matrix of matrix operators for
+            % each grid.
+            ops = sparse2cell(op, obj.NNN);
+        end
+
+        % Get a boundary operator specified by opName for the given boundary/BoundaryGroup
+        function op = getBoundaryOperator(obj, opName, boundary)
+            switch class(boundary)
+                case 'cell'
+                    localOpName = [opName '_' boundary{2}];
+                    blockId = boundary{1};
+                    localOp = obj.diffOps{blockId}.(localOpName);
+
+                    div = {obj.blockmatrixDiv{1}, size(localOp,2)};
+                    blockOp = blockmatrix.zero(div);
+                    blockOp{blockId,1} = localOp;
+                    op = blockmatrix.toMatrix(blockOp);
+                    return
+                case 'multiblock.BoundaryGroup'
+                    op = sparse(size(obj.D,1),0);
+                    for i = 1:length(boundary)
+                        op = [op, obj.getBoundaryOperator(opName, boundary{i})];
+                    end
+                otherwise
+                    error('Unknown boundary indentifier')
+            end
+        end
+
+        function op = getBoundaryQuadrature(obj, boundary)
+            opName = 'H';
+            switch class(boundary)
+                case 'cell'
+                    localOpName = [opName '_' boundary{2}];
+                    blockId = boundary{1};
+                    op = obj.diffOps{blockId}.(localOpName);
+
+                    return
+                case 'multiblock.BoundaryGroup'
+                    N = length(boundary);
+                    H_bm = cell(N,N);
+                    for i = 1:N
+                        H_bm{i,i} = obj.getBoundaryQuadrature(boundary{i});
+                    end
+                    op = blockmatrix.toMatrix(H_bm);
+                otherwise
+                    error('Unknown boundary indentifier')
+            end
+        end
+
+        % Creates the closure and penalty matrix for a given boundary condition,
+        %    boundary -- the name of the boundary on the form {id,name} where
+        %                id is the number of a block and name is the name of a
+        %                boundary of that block example: {1,'s'} or {3,'w'}. It
+        %                can also be a boundary group
+        function [closure, penalty] = boundary_condition(obj, boundary, type)
+            switch class(boundary)
+                case 'cell'
+                    [closure, penalty] = obj.singleBoundaryCondition(boundary, type);
+                case 'multiblock.BoundaryGroup'
+                    [n,m] = size(obj.D);
+                    closure = sparse(n,m);
+                    penalty = sparse(n,0);
+                    for i = 1:length(boundary)
+                        [closurePart, penaltyPart] = obj.boundary_condition(boundary{i}, type);
+                        closure = closure + closurePart;
+                        penalty = [penalty, penaltyPart];
+                    end
+                otherwise
+                    error('Unknown boundary indentifier')
+            end
+
+        end
+
+        function [closure, penalty] = singleBoundaryCondition(obj, boundary, type)
+            I = boundary{1};
+            name = boundary{2};
+
+            % Get the closure and penaly matrices
+            [blockClosure, blockPenalty] = obj.diffOps{I}.boundary_condition(name, type);
+
+            % Expand to matrix for full domain.
+            div = obj.blockmatrixDiv;
+            if ~iscell(blockClosure)
+                temp = blockmatrix.zero(div);
+                temp{I,I} = blockClosure;
+                closure = blockmatrix.toMatrix(temp);
+            else
+                for i = 1:length(blockClosure)
+                    temp = blockmatrix.zero(div);
+                    temp{I,I} = blockClosure{i};
+                    closure{i} = blockmatrix.toMatrix(temp);
+                end
+            end
+
+            if ~iscell(blockPenalty)
+                div{2} = size(blockPenalty, 2); % Penalty is a column vector
+                p = blockmatrix.zero(div);
+                p{I} = blockPenalty;
+                penalty = blockmatrix.toMatrix(p);
+            else
+                % TODO: used by beam equation, should be eliminated. SHould only set one BC per call
+                for i = 1:length(blockPenalty)
+                    div{2} = size(blockPenalty{i}, 2); % Penalty is a column vector
+                    p = blockmatrix.zero(div);
+                    p{I} = blockPenalty{i};
+                    penalty{i} = blockmatrix.toMatrix(p);
+                end
+            end
+        end
+
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            error('not implemented')
+        end
+
+        % Size returns the number of degrees of freedom
+        function N = size(obj)
+            N = 0;
+            for i = 1:length(obj.diffOps)
+                N = N + obj.diffOps{i}.size();
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/DiffOpTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/DiffOpTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,59 @@
+function tests = DiffOpTest()
+    tests = functiontests(localfunctions);
+end
+
+function testCreation(testCase)
+    do = newMultiblockOp();
+end
+
+function testSplitOp(testCase)
+    testCase.verifyFail();
+end
+
+function testBoundary_condition(testCase)
+    testCase.verifyFail();
+end
+
+function testInterface(testCase)
+    testCase.verifyFail();
+end
+
+function testSize(testCase)
+    mbDo = newMultiblockOp();
+    testCase.verifyEqual(mbDo.size(), 15)
+end
+
+
+function do = mockDiffOp(size, bc, interface)
+    do.H = 1;
+    do.D = 1;
+
+    do.size = size;
+    do.boundary_condition = bc;
+    do.interface = interface;
+end
+
+
+function do = newMultiblockOp()
+    grids = {
+        grid.Cartesian([0 1 2], [3 4 5]);
+        grid.Cartesian([1 2 3], [10 20]);
+    };
+
+    conn = cell(2,2);
+    conn{1, 2} = {'s','n'};
+
+    mbGrid = multiblock.Grid(grids, conn);
+
+    function [c, p] = boundary_condition(~,~,~,~)
+        c = 1; p = 1;
+    end
+
+    function [c, p] = interface(~,~,~,~)
+        c = 1; p = 1;
+    end
+
+    doHand = @(grid,~)mockDiffOp(@(~)prod(grid.size()), @boundary_condition, @interface);
+
+    do = multiblock.DiffOp(doHand, mbGrid, 0);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/EmptyGrid.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/EmptyGrid.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,47 @@
+classdef EmptyGrid < grid.Empty & multiblock.Grid
+    methods
+        function obj = EmptyGrid(D)
+            obj@multiblock.Grid({},cell(0,0));
+            obj@grid.Empty(D);
+        end
+
+        % n returns the number of points in the grid
+        function o = N(obj)
+            o = N@grid.Empty(obj);
+        end
+
+        % d returns the spatial dimension of the grid
+        function o = D(obj)
+            o = D@grid.Empty(obj);
+        end
+
+        % points returns a n x d matrix containing the coordinates for all points.
+        function X = points(obj)
+            X = points@grid.Empty(obj);
+        end
+
+        % Restricts the grid function gf on obj to the subgrid g.
+        function gf = restrictFunc(obj, gf, g)
+            gf = restrictFunc@grid.Empty(obj);
+        end
+
+        % Projects the grid function gf on obj to the grid g.
+        function gf = projectFunc(obj, gf, g)
+            gf = projectFunc@grid.Empty(obj);
+        end
+
+        % Return the grid.boundaryIdentifiers of all boundaries in a cell array.
+        function bs = getBoundaryNames(obj)
+            bs = getBoundaryNames@grid.Empty(obj);
+        end
+
+        % Return coordinates for the given boundary
+        function b = getBoundary(obj, name)
+            b = getBoundary@grid.Empty(name);
+        end
+
+        function s = size(obj)
+            s = size@multiblock.Grid(obj);
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/Grid.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Grid.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,174 @@
+classdef Grid < grid.Grid
+    properties
+        grids
+        connections
+        boundaryGroups
+
+        nPoints
+    end
+
+    % General multiblock grid
+    methods
+        % grids          -- cell array of N grids
+        % connections    -- NxN upper triangular cell matrix. connections{i,j}
+        %                   specifies the connection between block i and j. If
+        %                   it's empty there is no connection otherwise it's a 2
+        %                   -cell-vector with strings naming the boundaries to be
+        %                   connected. (inverted coupling?)
+        % boundaryGroups -- A struct of BoundaryGroups. The field names of the
+        %                   struct are the names of each boundary group.
+        %                   The boundary groups can be used to collect block
+        %                   boundaries into physical boundaries to simplify
+        %                   getting boundary operators and setting boundary conditions
+        function obj = Grid(grids, connections, boundaryGroups)
+            default_arg('boundaryGroups', struct());
+            assertType(grids, 'cell')
+            obj.grids = grids;
+            obj.connections = connections;
+
+            obj.nPoints = 0;
+            for i = 1:length(grids)
+                obj.nPoints = obj.nPoints + grids{i}.N();
+            end
+
+            obj.boundaryGroups = boundaryGroups;
+        end
+
+        function n = size(obj)
+            n = length(obj.grids);
+        end
+
+        % N returns the number of points in the grid
+        function o = N(obj)
+            o = obj.nPoints;
+        end
+
+        % Ns returns the number of points in each sub grid as a vector
+        function o = Ns(obj)
+            ns = zeros(1,obj.nBlocks);
+            for i = 1:obj.nBlocks
+                ns(i) = obj.grids{i}.N();
+            end
+            o = ns;
+        end
+
+        function n = nBlocks(obj)
+            n = length(obj.grids);
+        end
+
+        % d returns the spatial dimension of the grid
+        function o = D(obj)
+            o = obj.grids{1}.D();
+        end
+
+        % points returns a n x d matrix containing the coordinates for all points.
+        function X = points(obj)
+            X = sparse(0,obj.D());
+            for i = 1:length(obj.grids)
+                X = [X; obj.grids{i}.points];
+            end
+        end
+
+        % Split a grid function on obj to a cell array of grid function on each block
+        function gfs = splitFunc(obj, gf)
+            nComponents = length(gf)/obj.nPoints;
+            nBlocks = length(obj.grids);
+
+            % Collect number of points in each block
+            N = zeros(1,nBlocks);
+            for i = 1:nBlocks
+                N(i) = obj.grids{i}.N()*nComponents;
+            end
+
+            gfs = blockmatrix.fromMatrix(gf, {N,1});
+        end
+
+        % TODO: Split op?
+        % Should the method to split an operator be moved here instead of being in multiblock.DiffOp?
+
+        % Converts a gridfunction to a set of plot matrices
+        % Takes a grid function and and a structured grid.
+        function F = funcToPlotMatrices(obj, gf)
+            % TODO: This method should problably not be here.
+            % The funcToPlotMatrix uses .size poperty of the grids
+            % Which doesn't always exist for all types of grids.
+            % It's only valid for structured grids
+            gfs = obj.splitFunc(gf);
+
+            F = cell(1, obj.nBlocks());
+
+            for i = 1:obj.nBlocks()
+                F{i} = grid.funcToPlotMatrix(obj.grids{i}, gfs{i});
+            end
+        end
+
+
+        % Restricts the grid function gf on obj to the subgrid g.
+        function gf = restrictFunc(obj, gf, g)
+            gfs = obj.splitFunc(gf);
+
+            for i = 1:length(obj.grids)
+                gfs{i} = obj.grids{i}.restrictFunc(gfs{i}, g.grids{i});
+            end
+
+            gf = cell2mat(gfs);
+        end
+
+        % Projects the grid function gf on obj to the grid g.
+        function o = projectFunc(obj, gf, g)
+            error('not implemented')
+
+            p = g.points();
+            o = zeros(length(p),1);
+            for i = 1:length(p)
+                I = whatGrid(p(i));
+                o(i) = obj.grids{I}.projectFunc(gf, p(i));
+            end
+
+
+            function I = whatGrid(p)
+                % Find what grid a point lies on
+            end
+
+        end
+
+        % Find all non interface boundaries of all blocks.
+        % Return their grid.boundaryIdentifiers in a cell array.
+        function bs = getBoundaryNames(obj)
+            bs = {};
+            for i = 1:obj.nBlocks()
+                candidates = obj.grids{i}.getBoundaryNames();
+                for j = 1:obj.nBlocks()
+                    if ~isempty(obj.connections{i,j})
+                        candidates = setdiff(candidates, obj.connections{i,j}{1});
+                    end
+
+                    if ~isempty(obj.connections{j,i})
+                        candidates = setdiff(candidates, obj.connections{j,i}{2});
+                    end
+                end
+
+                for k = 1:length(candidates)
+                    bs{end+1} = {i, candidates{k}};
+                end
+            end
+        end
+
+        % Return coordinates for the given boundary/boundaryGroup
+        function b = getBoundary(obj, boundary)
+            switch class(boundary)
+                case 'cell'
+                    I = boundary{1};
+                    name = boundary{2};
+                    b = obj.grids{I}.getBoundary(name);
+                case 'multiblock.BoundaryGroup'
+                    b = sparse(0,obj.D());
+                    for i = 1:length(boundary)
+                        b = [b; obj.getBoundary(boundary{i})];
+                    end
+                otherwise
+                    error('Unknown boundary indentifier')
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/GridTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/GridTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,37 @@
+function tests = GridTest()
+    tests = functiontests(localfunctions);
+end
+
+function testCreation(testCase)
+    g = multiblock.Grid({},{});
+end
+
+function testMissing(testCase)
+    testCase.verifyFail();
+end
+
+function testGetBoundaryNames(testCase)
+    [grids, conn] = prepareAdjecentBlocks();
+
+    mbg = multiblock.Grid(grids, conn, multiblock.BoundaryGroup({1,'w'},{2,'w'}) );
+
+    testCase.verifyFail();
+end
+
+function testGetBoundary(testCase)
+    [grids, conn] = prepareAdjecentBlocks();
+
+    mbg = multiblock.Grid(grids, conn, multiblock.BoundaryGroup({1,'w'},{2,'w'}) );
+    testCase.verifyFail();
+end
+
+
+function [grids, conn] = prepareAdjecentBlocks()
+    grids = {
+        grid.Cartesian([0 1 2], [3 4 5]);
+        grid.Cartesian([1 2], [10 20]);
+    };
+
+    conn = cell(2,2);
+    conn{1, 2} = {'s','n'};
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/Laplace.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Laplace.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,56 @@
+classdef Laplace < scheme.Scheme
+    properties
+        grid
+        order
+        mbDiffOp
+
+        D
+        H
+        J
+    end
+    methods
+        function obj = Laplace(g, order, a, b, opGen)
+            default_arg('order', 4);
+            default_arg('a', 1);
+            default_arg('b', 1);
+            default_arg('opGen', @sbp.D4Variable);
+
+            obj.grid = g;
+            obj.order = order;
+            obj.mbDiffOp = multiblock.DiffOp(@scheme.LaplaceCurvilinear, obj.grid, order, {a,b,opGen});
+
+            obj.D = obj.mbDiffOp.D;
+            obj.J = obj.jacobian();
+            obj.H = obj.mbDiffOp.H;
+        end
+
+        function s = size(obj)
+            s = size(obj.mbDiffOp);
+        end
+
+        function J = jacobian(obj)
+            N = obj.grid.nBlocks;
+            J = cell(N,N);
+
+            for i = 1:N
+                J{i,i} = obj.mbDiffOp.diffOps{i}.J;
+            end
+            J = blockmatrix.toMatrix(J);
+        end
+
+        function op = getBoundaryOperator(obj, opName, boundary)
+            op = getBoundaryOperator(obj.mbDiffOp, opName, boundary);
+        end
+
+        function op = getBoundaryQuadrature(obj, boundary)
+            op = getBoundaryQuadrature(obj.mbDiffOp, boundary);
+        end
+
+        function [closure, penalty] = boundary_condition(obj,boundary,type) % TODO: Change name to boundaryCondition
+            [closure, penalty] = boundary_condition(obj.mbDiffOp, boundary, type);
+        end
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            error('Not implemented')
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/Line.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Line.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,47 @@
+classdef Line < handle
+    properties
+        grid
+        lines
+
+        YData
+    end
+
+    methods
+        function obj = Line(g, gf)
+            assertType(g, 'multiblock.Grid')
+            obj.grid = g;
+
+            X = obj.grid.splitFunc(obj.grid.points());
+            Y = obj.grid.splitFunc(gf);
+
+            holdState = ishold();
+            hold on
+
+            lines = cell(1, obj.grid.nBlocks);
+            for i = 1:obj.grid.nBlocks
+                lines{i} = plot(X{i}, Y{i});
+            end
+
+            if holdState == false
+                hold off
+            end
+
+            obj.lines = [lines{:}];
+
+            obj.YData = gf;
+        end
+
+        function set(obj, propertyName, propertyValue)
+            set(obj.lines, propertyName, propertyValue);
+        end
+
+        function obj = set.YData(obj, gf)
+            obj.YData = gf;
+
+            Y = obj.grid.funcToPlotMatrices(gf);
+            for i = 1:obj.grid.nBlocks
+                obj.lines(i).YData = Y{i};
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/Surface.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Surface.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,62 @@
+classdef Surface < handle
+    properties
+        grid
+        surfs
+
+        ZData
+        CData
+
+    end
+
+    methods
+        function obj = Surface(g, gf)
+            obj.grid = g;
+
+            coords = obj.grid.points();
+            X = obj.grid.funcToPlotMatrices(coords(:,1));
+            Y = obj.grid.funcToPlotMatrices(coords(:,2));
+
+            V = obj.grid.funcToPlotMatrices(gf);
+
+
+            holdState = ishold();
+            hold on
+
+            surfs = cell(1, obj.grid.nBlocks);
+            for i = 1:obj.grid.nBlocks
+                surfs{i} = surf(X{i}, Y{i}, V{i});
+            end
+
+            if holdState == false
+                hold off
+            end
+
+            obj.surfs = [surfs{:}];
+
+            obj.ZData = gf;
+            obj.CData = gf;
+        end
+
+        function set(obj, propertyName, propertyValue)
+            set(obj.surfs, propertyName, propertyValue);
+        end
+
+        function obj = set.ZData(obj, gf)
+            obj.ZData = gf;
+
+            V = obj.grid.funcToPlotMatrices(gf);
+            for i = 1:obj.grid.nBlocks
+                obj.surfs(i).ZData = V{i};
+            end
+        end
+
+        function obj = set.CData(obj, gf)
+            obj.CData = gf;
+
+            V = obj.grid.funcToPlotMatrices(gf);
+            for i = 1:obj.grid.nBlocks
+                obj.surfs(i).CData = V{i};
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/evalOn.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/evalOn.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,27 @@
+% Evaluate different function handle for each block in a multiblock.Grid
+% Function handles may optionaly take a time argument
+% f -- cell array of function handles
+%       f{i} = f_i(t,x,y,...)
+% t -- optional time point. If not specified, it is assumed that the functions take only spatial arguments.
+function gf = evalOn(g, f, t)
+    assertType(g, 'multiblock.Grid');
+    assertType(f, 'cell');
+
+    default_arg('t', []);
+
+    grids = g.grids;
+    nBlocks = length(grids);
+    gf = cell(nBlocks, 1);
+
+    if isempty(t)
+        for i = 1:nBlocks
+            gf{i} = grid.evalOn(grids{i}, f{i});
+        end
+    else
+        for i = 1:nBlocks
+            gf{i} = grid.evalOn(grids{i}, @(varargin)f{i}(t,varargin{:}));
+        end
+    end
+
+    gf = blockmatrix.toMatrix(gf);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/gridVector1d.m
--- a/+multiblock/gridVector1d.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,8 +0,0 @@
-function x = gridVector1d(schms)
-    n = length(schms);
-    x = cell(n,1);
-
-    for i = 1:n
-        x{i} = schms{i}.x;
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/gridVector2d.m
--- a/+multiblock/gridVector2d.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-function [x,y] = gridVector2d(schms)
-    n = length(schms);
-    x = cell(n,1);
-    y = cell(n,1);
-
-    for i = 1:n
-        x{i} = schms{i}.x;
-        y{i} = schms{i}.y;
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/multiblockgrid.m
--- a/+multiblock/multiblockgrid.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,70 +0,0 @@
-% Creates a multi block square grid with defined boundary conditions.
-%   x,y defines the grid lines. Rember to think of the indexing as a matrix. Order matters!
-%   bc is a struct defining the boundary conditions on each side of the block.
-%       bc.w = {'dn',[function or value]}
-function [block,conn,bound,ms] = multiblockgrid(x,y,mx,my,bc)
-    n = length(y)-1; % number of blocks in the y direction.
-    m = length(x)-1; % number of blocks in the x direction.
-    N = n*m; % number of blocks
-
-    if ~issorted(x)
-        error('The elements of x seem to be in the wrong order');
-    end
-    if ~issorted(flip(y))
-        error('The elements of y seem to be in the wrong order');
-    end
-    % y = sort(y,'descend');
-
-    % Dimensions of blocks and number of points
-    block = cell(n,m);
-    for i = 1:n
-        for j = 1:m
-            block{i,j} = {
-                {x(j),x(j+1)}, {y(i+1),y(i)};
-            };
-
-            ms{i,j} = [mx(i),my(j)];
-        end
-    end
-
-    % Interface couplings
-    conn = cell(N,N);
-    for i = 1:n
-        for j = 1:m
-            I = flat_index(n,i,j);
-            if i < n
-                J = flat_index(n,i+1,j);
-                conn{I,J} = {'s','n'};
-            end
-
-            if j < m
-                J = flat_index(n,i,j+1);
-                conn{I,J} = {'e','w'};
-            end
-        end
-    end
-
-
-    % Boundary conditions
-    bound = cell(n,m);
-    for i = 1:n
-        if isfield(bc,'w')
-            bound{i,1}.w = bc.w;
-        end
-
-        if isfield(bc,'e')
-            bound{i,n}.e = bc.e;
-        end
-    end
-
-    for j = 1:m
-        if isfield(bc,'n')
-            bound{1,j}.n = bc.n;
-        end
-
-        if isfield(bc,'s')
-            bound{m,j}.s = bc.s;
-        end
-    end
-end
-
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/solutionVector2cell.m
--- a/+multiblock/solutionVector2cell.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,15 +0,0 @@
-function v_cell = solutionVector2cell(schms,v,components)
-    if nargin == 2
-        components = 1;
-    end
-
-    N = length(schms);
-    v_cell = cell(N,1);
-
-    i_start = 1;
-    for i =1:N
-        i_end = i_start + schms{i}.size()*components - 1;
-        v_cell{i} = v(i_start:i_end);
-        i_start = i_end+1;
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +multiblock/stitchSchemes.m
--- a/+multiblock/stitchSchemes.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,92 +0,0 @@
-% Stitch schemes together given connection matrix and BC vector.
-%     schmHand  - function_handle to a Scheme constructor
-%     order     - order of accuracy
-%     schmParam - cell array of extra parameters sent to each Scheme stored as cell arrays
-%     blocks    - block definitions, On whatever form the scheme expects.
-%     ms        - grid points in each direction for each block. Ex {[10,10], [10, 20]}
-%     conn      - connection matrix
-%     bound     - boundary condition vector, array of structs with fields w,e,s,n
-%                 each field with a parameter array that is sent to schm.boundary_condition
-%
-% Output parameters are cell arrays and cell matrices.
-%
-% Ex: [schms, D, H] = stitchSchemes(schmHand, order, schmParam, blocks, ms, conn, bound)
-function [schms, D, H] = stitchSchemes(schmHand, order, schmParam, blocks, ms, conn, bound)
-    default_arg('schmParam',[]);
-
-    n_blocks = numel(blocks);
-
-    % Creating Schemes
-    for i = 1:n_blocks
-        if isempty(schmParam);
-            schms{i} = schmHand(ms{i},blocks{i},order,[]);
-        elseif ~iscell(schmParam)
-            param = schmParam(i);
-            schms{i} = schmHand(ms{i},blocks{i},order,param);
-        else
-            param = schmParam{i};
-            if iscell(param)
-                schms{i} = schmHand(ms{i},blocks{i},order,param{:});
-            else
-                schms{i} = schmHand(ms{i},blocks{i},order,param);
-            end
-        end
-
-        % class(schmParam)
-        % class(ms)
-        % class(blocks)
-        % class(schmParam{i})
-        % class(ms)
-
-
-    end
-
-
-    % Total norm
-    H = cell(n_blocks,n_blocks);
-    for i = 1:n_blocks
-        H{i,i} = schms{i}.H;
-    end
-
-    %% Total system matrix
-
-    % Differentiation terms
-    D = cell(n_blocks,n_blocks);
-    for i = 1:n_blocks
-        D{i,i} = schms{i}.D;
-    end
-
-    % Boundary penalty terms
-    for i = 1:n_blocks
-        if ~isstruct(bound{i})
-            continue
-        end
-
-        fn = fieldnames(bound{i});
-        for j = 1:length(fn);
-            bc = bound{i}.(fn{j});
-            if isempty(bc)
-                continue
-            end
-
-            [closure, ~] = schms{i}.boundary_condition(fn{j},bc{:});
-            D{i,i} = D{i,i}+closure;
-        end
-    end
-
-    % Interface penalty terms
-    for i = 1:n_blocks
-        for j = 1:n_blocks
-            intf = conn{i,j};
-            if isempty(intf)
-                continue
-            end
-
-            [uu,uv,vv,vu] = schms{i}.interface_coupling(schms{i},intf{1},schms{j},intf{2});
-            D{i,i} = D{i,i} + uu;
-            D{i,j} = uv;
-            D{j,j} = D{j,j} + vv;
-            D{j,i} = vu;
-        end
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/Animation.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+noname/Animation.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,75 @@
+classdef Animation < handle
+    properties
+        timeStepper
+        representationMaker
+        updaters
+    end
+
+    % add input validation
+
+    methods
+        function obj = Animation(timeStepper, representationMaker, updaters);
+            obj.timeStepper = timeStepper;
+            obj.updaters = updaters;
+            obj.representationMaker = representationMaker;
+        end
+
+        function update(obj, r)
+            for i = 1:length(obj.updaters)
+                obj.updaters{i}(r);
+            end
+            drawnow
+        end
+
+        function run(obj, tEnd, timeModifier, do_pause)
+            default_arg('do_pause', false)
+
+            function next_t = G(next_t)
+                obj.timeStepper.evolve(next_t);
+                r = obj.representationMaker(obj.timeStepper);
+                obj.update(r);
+
+                if do_pause
+                    pause
+                end
+            end
+
+            anim.animate(@G, obj.timeStepper.t, tEnd, timeModifier);
+        end
+
+        function step(obj, tEnd, do_pause)
+            default_arg('do_pause', false)
+
+            while obj.timeStepper.t < tEnd
+                obj.timeStepper.step();
+
+                r = obj.representationMaker(obj.timeStepper);
+                obj.update(r);
+
+                % TODO: Make it never go faster than a certain fram rate
+
+                if do_pause
+                    pause
+                end
+            end
+        end
+
+        function saveMovie(obj, tEnd, timeModifier, figureHandle, dirname)
+            save_frame = anim.setup_fig_mov(figureHandle, dirname);
+
+            function next_t = G(next_t)
+                obj.timeStepper.evolve(next_t);
+                r = obj.representationMaker(obj.timeStepper);
+                obj.update(r);
+
+                save_frame();
+            end
+
+            fprintf('Generating and saving frames to: ..\n')
+            anim.animate(@G, obj.timeStepper.t, tEnd, timeModifier);
+            fprintf('Generating movies...\n')
+            cmd = sprintf('bash %s/+anim/make_movie.sh %s', sbplibLocation(),dirname);
+            system(cmd);
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/animate.m
--- a/+noname/animate.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+noname/animate.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,14 +1,18 @@
-% hand = noname.animate(discretization, time_modifier, Tend, dirname, opt)
+% noname.animate(discretization, time_modifier, Tend, dirname, opt)
 %
 % Example:
 %      noname.animate(discr,timemodifier,tend)
 %      noname.animate(discr,1, [tstart tend],'my_mov', opt)
 
-function hand = animate(discretization, time_modifier, Tend, dirname, opt)
-    default_arg('time_modifier',1);
+function animate(discretization, time_modifier, Tend, dirname, opt)
+    default_arg('time_modifier', 1);
     default_arg('Tend', Inf);
-    default_arg('dirname','');
-    default_arg('opt', []);
+    default_arg('dirname', '');
+
+    optDefault.plotType = 'animation';
+    optDefault.time = [];
+
+    default_struct('opt', optDefault);
 
 
     if time_modifier < 0
@@ -34,7 +38,7 @@
     fprintf('m        : %d\n',size(discretization));
 
 
-    ts = discretization.getTimestepper(opt);
+    ts = discretization.getTimestepper(opt.time);
 
     if numel(Tend) == 2
         Tstart = Tend(1);
@@ -50,7 +54,7 @@
         Tstart = start_solution.t;
     end
 
-    [update, figure_handle] = discretization.setupPlot('animation');
+    [update, figure_handle] = discretization.setupPlot(opt.plotType);
     if makemovies
         save_frame = anim.setup_fig_mov(figure_handle,dirname);
     end
@@ -83,7 +87,8 @@
         pause
         anim.animate(@G, Tstart, Tend, time_modifier);
     else
-        while true
+        pause
+        while ts.t < Tend
             ts.step();
             sol = discretization.getTimeSnapshot(ts);
             update(sol);
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/calcSol.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+noname/calcSol.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,10 @@
+% Calculates the solution of a discr at a given time using aligned timesteps.
+% Returns the solution as a grid function as defined in +grid
+function gf = calculateSolution(discr, T, tsOpt)
+    k_max = discr.getTimestep(tsOpt);
+    [k,N] = alignedTimestep(k_max,T);
+    tsOpt.k = k;
+    ts = discr.getTimestepper(tsOpt);
+
+    gf = ts.stepN(N-ts.n);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/calculateErrors.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+noname/calculateErrors.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,53 @@
+% [discr, trueSolution] =  schemeFactory(m)
+%     where trueSolution should be a timeSnapshot of the true solution a time T
+% T is the end time
+% m are grid size parameters.
+% N are number of timesteps to use for each gird size
+% timeOpt are options for the timeStepper
+% errorFun is a function_handle taking 2 or 3 arguments, errorFun(trueSolution, approxSolution), errorFun(trueSolution, approxSolution, discr)
+function e = calculateErrors(schemeFactory, T, m, N, errorFun, timeOpt)
+    %TODO: Ability to choose paralell or not
+    assertType(schemeFactory, 'function_handle');
+    assertNumberOfArguments(schemeFactory, 1);
+    assertScalar(T);
+    assert(length(m) == length(N), 'Vectors m and N must have the same length');
+    assertType(errorFun, 'function_handle');
+
+    if ~ismember(nargin(errorFun), [2,3])
+        error('sbplib:noname:calculateErrors:wrongNumberOfArguments', '"%s" must have 2 or 3, found %d', toString(errorFun), nargin(errorFun));
+    end
+
+    default_arg('timeOpt', struct());
+
+
+    e = zeros(1,length(m));
+    parfor i = 1:length(m)
+        done = timeTask('m = %3d ', m(i));
+
+        [discr, trueSolution] = schemeFactory(m(i));
+
+        timeOptTemp = timeOpt;
+        timeOptTemp.k = T/N(i);
+        ts = discr.getTimestepper(timeOptTemp);
+        ts.stepTo(N(i), true);
+        approxSolution = discr.getTimeSnapshot(ts);
+
+        switch nargin(errorFun)
+            case 2
+                e(i) = errorFun(trueSolution, approxSolution);
+            case 3
+                e(i) = errorFun(trueSolution, approxSolution, discr);
+        end
+
+        fprintf('e = %.4e', e(i))
+        done()
+    end
+    fprintf('\n')
+end
+
+
+%% Example error function
+% u_true = grid.evalOn(dr.grid, @(x,y)trueSolution(T,x,y));
+% err = u_true-u_false;
+% e(i) = norm(err)/norm(u_true);
+% % e(i) = sqrt(err'*d.H*d.J*err/(u_true'*d.H*d.J*u_true));
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/calculateSolution.m
--- a/+noname/calculateSolution.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+noname/calculateSolution.m	Fri Sep 07 14:40:58 2018 +0200
@@ -13,7 +13,7 @@
         fprintf('File ''%s'' already exist.',filename);
         do_append = yesnoQuestion('Do you want to append to it?');
         if ~do_append
-            fprintf('Exiting...\n');
+            fprintf('Exiting. No Solutions calculated.\n');
             return
         end
     end
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/convergence.m
--- a/+noname/convergence.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+noname/convergence.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,5 +1,5 @@
 % Reference is either a key or a function handle
-function [q, e, h, runtime] = convergence(filename, errorFunc, reference, method, order, m, T)
+function [q, e, h, runtime] = convergence(filename, errorFunc, reference, name, order, m, T)
     default_arg('errorFunc', @scheme.error1d);
 
     sf = SolutionFile(filename);
@@ -7,7 +7,7 @@
 
     % Generate convergence, error, and efficiency plots for each search key with more than one entry.
     for i = 1:length(m)
-        key.method = method;
+        key.name = name;
         key.order = order;
         key.m = m(i);
         key.T = T;
@@ -30,18 +30,11 @@
 
     % Get the reference solution vector
     if isa(reference,'function_handle');
-        x = v_repr.x;
+        x = v_repr.grid.points();
         v_ref = reference(x,T);
     else
         % Downsample the reference solution
-        x = v_repr.x;
-        x_ref = reference.x;
-
-        [~,I] = ismember(x,x_ref,'rows');
-        if any(I == 0)
-            error('Solution and reference solution seem to be on different grids.');
-        end
-        v_ref = reference.v(I);
+        v_ref = reference.grid.restrictFunc(reference.v, v_repr.grid);
     end
 
     e = errorFunc(discr,v, v_ref);
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/plotSolutions.m
--- a/+noname/plotSolutions.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+noname/plotSolutions.m	Fri Sep 07 14:40:58 2018 +0200
@@ -10,7 +10,7 @@
         key = sf.keys{i};
         entry = sf.get(key);
 
-        method  = key.method;
+        name  = key.name;
         order   = key.order;
         m       = key.m;
         T       = key.T;
@@ -23,11 +23,11 @@
         update(repr);
 
         if save_figures
-            figname = sprintf('%s_%s_o%d_m%d_T%d',figename_prefix,method,order,m,i);
+            figname = sprintf('%s_%s_o%d_m%d_T%d',figename_prefix,name,order,m,i);
             fprintf('Saving figure to ''%s''\n',figname);
             saveeps(hand,figname);
         end
 
     end
 
-end
\ No newline at end of file
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +noname/testCfl.m
--- a/+noname/testCfl.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+noname/testCfl.m	Fri Sep 07 14:40:58 2018 +0200
@@ -27,29 +27,37 @@
         end
     end
 
+    if silentFlag
+        rsInterval = util.ReplaceableString('');
+    end
+
     % Use bisection to find sharp estimate
     while( (alpha0(2)-alpha0(1))/alpha0(1) > tol)
         alpha = mean(alpha0);
 
         if ~silentFlag
             fprintf('[%.3e,%.3e]: ', alpha0(1), alpha0(2));
+        else
+            rsInterval.update('[%.3e,%.3e]: ', alpha0(1), alpha0(2));
         end
 
         [ok, n_step, maxVal] = testAlpha(alpha);
 
         if ok
             alpha0(1) = alpha;
+            stability = 'STABLE';
         else
             alpha0(2) = alpha;
+            stability = 'UNSTABLE';
         end
 
         if ~silentFlag
-            fprintf('a = %.3e, n_step=%d  max = %.2e\n', alpha, n_step, maxVal);
+            fprintf('a = %.3e, n_step=%d %8s max = %.2e\n', alpha, n_step, stability, maxVal);
         end
     end
 
     if silentFlag
-        fprintf('Last calculated: a = %.3e, n_step=%d  max = %.2e\n', alpha, n_step, maxVal);
+        rsInterval = util.ReplaceableString('');
     end
 
     fprintf('T = %-3d dof = %-4d order = %d: clf = %.4e\n',T, discr.size(), discr.order, alpha0(1));
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/Curve.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/Curve.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,396 @@
+classdef Curve
+    properties
+        g
+        gp
+        transformation
+    end
+
+    methods
+        %TODO:
+        % Concatenation of curves
+        % Subsections of curves
+        % Stretching of curve parameter - done for arc length.
+        % Curve to cell array of linesegments
+
+        % Returns a curve object.
+        %   g -- curve parametrization for parameter between 0 and 1
+        %  gp -- parametrization of curve derivative
+        function obj = Curve(g,gp,transformation)
+            default_arg('gp',[]);
+            default_arg('transformation',[]);
+            p_test = g(0);
+            assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.');
+
+            if ~isempty(transformation)
+                transformation.base_g = g;
+                transformation.base_gp = gp;
+                [g,gp] = parametrization.Curve.transform_g(g,gp,transformation);
+            end
+
+            obj.g = g;
+            obj.gp = gp;
+            obj.transformation = transformation;
+
+        end
+
+        function n = normal(obj,t)
+            assert(~isempty(obj.gp),'Curve has no derivative!');
+            deriv = obj.gp(t);
+            normalization = sqrt(sum(deriv.^2,1));
+            n = [-deriv(2,:)./normalization; deriv(1,:)./normalization];
+        end
+
+
+        % Plots a curve g(t) for 0<t<1, using n points. Returns a handle h to the plotted curve.
+        %   h = plot_curve(g,n)
+        function h = plot(obj,n)
+            default_arg('n',100);
+
+            t = linspace(0,1,n);
+            p = obj.g(t);
+            h = line(p(1,:),p(2,:));
+        end
+
+        function h= plot_normals(obj,l,n,m)
+            default_arg('l',0.1);
+            default_arg('n',10);
+            default_arg('m',100);
+            t_n = linspace(0,1,n);
+
+            normals = obj.normal(t_n)*l;
+
+            n0 = obj.g(t_n);
+            n1 = n0 + normals;
+
+            h = line([n0(1,:); n1(1,:)],[n0(2,:); n1(2,:)]);
+            set(h,'Color',Color.red);
+            obj.plot(m);
+        end
+
+        function h= show(obj,name)
+            default_arg('name', '')
+            p = obj.g(1/2);
+            n = obj.normal(1/2);
+            p = p + n*0.1;
+
+            % Add arrow
+
+
+            if ~isempty(name)
+                h = text(p(1),p(2),name);
+                h.HorizontalAlignment = 'center';
+                h.VerticalAlignment = 'middle';
+            end
+
+            h = obj.plot();
+        end
+            % Shows curve with name and arrow for direction.
+
+        % Length of arc from parameter t0 to t1 (which may be vectors).
+        % Computed using derivative.
+        function L = arcLength(obj,t0,t1)
+            assert(~isempty(obj.gp),'Curve has no derivative!');
+            speed = @(t) sqrt(sum(obj.gp(t).^2,1));
+            L =  integral_vec(speed,t0,t1);
+        end
+
+        % Creates the arc length parameterization of a curve.
+        %    N -- number of points used to approximate the arclength function
+        function curve = arcLengthParametrization(obj,N)
+            default_arg('N',100);
+            assert(~isempty(obj.gp),'Curve has no derivative!');
+
+            % Construct arcLength function using splines
+            tvec = linspace(0,1,N);
+            arcVec = obj.arcLength(0,tvec);
+            tFunc = spline(arcVec,tvec); % t as a function of arcLength
+            L = obj.arcLength(0,1);
+            arcPar = @(s) tFunc(s*L);
+
+            % New function and derivative
+            g_new = @(t)obj.g(arcPar(t));
+            gp_new = @(t) normalize(obj.gp(arcPar(t)));
+            curve = parametrization.Curve(g_new,gp_new);
+
+        end
+
+        % how to make it work for methods without returns
+        function p = subsref(obj,S)
+            %Should i add error checking here?
+            %Maybe if you want performance you fetch obj.g and then use that
+            switch S(1).type
+                case '()'
+                    p = obj.g(S.subs{1});
+                % case '.'
+
+                    % p = obj.(S.subs);
+                otherwise
+                    p = builtin('subsref',obj,S);
+                    % error()
+            end
+        end
+
+
+        %% TRANSFORMATION OF A CURVE
+        function D = reverse(C)
+            % g = C.g;
+            % gp = C.gp;
+            % D = parametrization.Curve(@(t)g(1-t),@(t)-gp(1-t));
+            D = C.transform([],[],-1);
+        end
+
+        function D = transform(C,A,b,flip)
+            default_arg('A',[1 0; 0 1]);
+            default_arg('b',[0; 0]);
+            default_arg('flip',1);
+            if isempty(C.transformation)
+                g  = C.g;
+                gp = C.gp;
+                transformation.A = A;
+                transformation.b = b;
+                transformation.flip = flip;
+            else
+                g  = C.transformation.base_g;
+                gp = C.transformation.base_gp;
+                A_old = C.transformation.A;
+                b_old = C.transformation.b;
+                flip_old = C.transformation.flip;
+
+                transformation.A = A*A_old;
+                transformation.b = A*b_old + b;
+                transformation.flip = flip*flip_old;
+            end
+
+            D = parametrization.Curve(g,gp,transformation);
+
+        end
+
+        function D = translate(C,a)
+            g = C.g;
+            gp = C.gp;
+
+            % function v = g_fun(t)
+            %     x = g(t);
+            %     v(1,:) = x(1,:)+a(1);
+            %     v(2,:) = x(2,:)+a(2);
+            % end
+
+            % D = parametrization.Curve(@g_fun,gp);
+
+            D = C.transform([],a);
+        end
+
+        function D = mirror(C, a, b)
+            assertSize(a,[2,1]);
+            assertSize(b,[2,1]);
+
+            g = C.g;
+            gp = C.gp;
+
+            l = b-a;
+            lx = l(1);
+            ly = l(2);
+
+
+            % fprintf('Singular?\n')
+
+            A = [lx^2-ly^2 2*lx*ly; 2*lx*ly ly^2-lx^2]/(l'*l);
+
+            % function v = g_fun(t)
+            %     % v = a + A*(g(t)-a)
+            %     x = g(t);
+
+            %     ax1 = x(1,:)-a(1);
+            %     ax2 = x(2,:)-a(2);
+            %     v(1,:) = a(1)+A(1,:)*[ax1;ax2];
+            %     v(2,:) = a(2)+A(2,:)*[ax1;ax2];
+            % end
+
+            % function v = gp_fun(t)
+            %     v = A*gp(t);
+            % end
+
+            % D = parametrization.Curve(@g_fun,@gp_fun);
+
+            % g = A(g-a)+a = Ag - Aa + a;
+            b = - A*a + a;
+            D = C.transform(A,b);
+
+        end
+
+        function D = rotate(C,a,rad)
+            assertSize(a, [2,1]);
+            assertSize(rad, [1,1]);
+            g = C.g;
+            gp = C.gp;
+
+
+            A = [cos(rad) -sin(rad); sin(rad) cos(rad)];
+
+            % function v = g_fun(t)
+            %     % v = a + A*(g(t)-a)
+            %     x = g(t);
+
+            %     ax1 = x(1,:)-a(1);
+            %     ax2 = x(2,:)-a(2);
+            %     v(1,:) = a(1)+A(1,:)*[ax1;ax2];
+            %     v(2,:) = a(2)+A(2,:)*[ax1;ax2];
+            % end
+
+            % function v = gp_fun(t)
+            %     v = A*gp(t);
+            % end
+
+            % D = parametrization.Curve(@g_fun,@gp_fun);
+
+
+             % g = A(g-a)+a = Ag - Aa + a;
+            b = - A*a + a;
+            D = C.transform(A,b);
+        end
+    end
+
+    methods (Static)
+
+        % Computes the derivative of g: R -> R^2 using an operator D1
+        function gp_out = numericalDerivative(g,D1)
+            m = length(D1);
+            t = linspace(0,1,m);
+            gVec = g(t)';
+            gpVec = (D1*gVec)';
+
+            gp1_fun = spline(t,gpVec(1,:));
+            gp2_fun = spline(t,gpVec(2,:));
+            gp_out = @(t) [gp1_fun(t);gp2_fun(t)];
+        end
+
+        function obj = line(p1, p2)
+
+            function v = g_fun(t)
+                v(1,:) = p1(1) + t.*(p2(1)-p1(1));
+                v(2,:) = p1(2) + t.*(p2(2)-p1(2));
+            end
+
+            function v = g_fun_deriv(t)
+                v(1,:) = t.*0 + (p2(1)-p1(1));
+                v(2,:) = t.*0 + (p2(2)-p1(2));
+            end
+
+            obj = parametrization.Curve(@g_fun, @g_fun_deriv);
+        end
+
+        function obj = circle(c,r,phi)
+            default_arg('phi',[0; 2*pi])
+            default_arg('c',[0; 0])
+            default_arg('r',1)
+
+            function v = g_fun(t)
+                w = phi(1)+t*(phi(2)-phi(1));
+                v(1,:) = c(1) + r*cos(w);
+                v(2,:) = c(2) + r*sin(w);
+            end
+
+            function v = g_fun_deriv(t)
+                w = phi(1)+t*(phi(2)-phi(1));
+                v(1,:) = -(phi(2)-phi(1))*r*sin(w);
+                v(2,:) =  (phi(2)-phi(1))*r*cos(w);
+            end
+
+            obj = parametrization.Curve(@g_fun,@g_fun_deriv);
+        end
+
+        function obj = bezier(p0, p1, p2, p3)
+            function v = g_fun(t)
+                v(1,:) = (1-t).^3*p0(1) + 3*(1-t).^2.*t*p1(1) + 3*(1-t).*t.^2*p2(1) + t.^3*p3(1);
+                v(2,:) = (1-t).^3*p0(2) + 3*(1-t).^2.*t*p1(2) + 3*(1-t).*t.^2*p2(2) + t.^3*p3(2);
+            end
+
+            function v = g_fun_deriv(t)
+                v(1,:) = 3*(1-t).^2*(p1(1)-p0(1)) + 6*(1-t).*t*(p2(1)-p1(1)) + 3*t.^2*(p3(1)-p2(1));
+                v(2,:) = 3*(1-t).^2*(p1(2)-p0(2)) + 6*(1-t).*t*(p2(2)-p1(2)) + 3*t.^2*(p3(2)-p2(2));
+            end
+
+            obj = parametrization.Curve(@g_fun,@g_fun_deriv);
+        end
+
+
+        function [g_out,gp_out] = transform_g(g,gp,tr)
+            A = tr.A;
+            b = tr.b;
+            flip = tr.flip;
+
+            function v = g_fun_noflip(t)
+                % v = A*g + b
+                x = g(t);
+
+                v(1,:) = A(1,:)*x+b(1);
+                v(2,:) = A(2,:)*x+b(2);
+            end
+
+            function v = g_fun_flip(t)
+                % v = A*g + b
+                x = g(1-t);
+
+                v(1,:) = A(1,:)*x+b(1);
+                v(2,:) = A(2,:)*x+b(2);
+            end
+
+
+            switch flip
+                case 1
+                    g_out  = @g_fun_noflip;
+                    gp_out = @(t)A*gp(t);
+                case -1
+                    g_out  = @g_fun_flip;
+                    gp_out = @(t)-A*gp(1-t);
+            end
+        end
+
+    end
+end
+
+
+
+function g_norm = normalize(g0)
+    g1 = g0(1,:);
+    g2 = g0(2,:);
+    normalization = sqrt(sum(g0.^2,1));
+    g_norm = [g1./normalization; g2./normalization];
+end
+
+function I = integral_vec(f,a,b)
+% Wrapper around the built-in function integral that
+% handles multiple limits.
+
+    Na = length(a);
+    Nb = length(b);
+    assert(Na == 1 || Nb == 1 || Na==Nb,...
+        'a and b must have same length, unless one is a scalar.');
+
+    if(Na>Nb);
+        I = zeros(size(a));
+        for i = 1:Na
+            I(i) = integral(f,a(i),b);
+        end
+    elseif(Nb>Na)
+        I = zeros(size(b));
+        for i = 1:Nb
+            I(i) = integral(f,a,b(i));
+        end
+    else
+        I = zeros(size(b));
+        for i = 1:Nb
+            I(i) = integral(f,a(i),b(i));
+        end
+    end
+end
+
+% Returns a function handle to the spline.
+function f = spline(tval,fval,spline_order)
+    default_arg('spline_order',4);
+    [m,~] = size(tval);
+    assert(m==1,'Need row vectors.');
+
+    f_spline = spapi( optknt(tval,spline_order), tval, fval );
+    f = @(t) fnval(f_spline,t);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/Ti.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/Ti.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,255 @@
+classdef Ti
+    properties
+        gs % {4}Curve
+        S  % FunctionHandle(u,v)
+    end
+
+    methods
+        % TODO function to label boundary names.
+        %  function to find largest and smallest delta h in the grid. Maybe shouldnt live here
+        function obj = Ti(C1,C2,C3,C4)
+            obj.gs = {C1,C2,C3,C4};
+
+            g1 = C1.g;
+            g2 = C2.g;
+            g3 = C3.g;
+            g4 = C4.g;
+
+            A = g1(0);
+            B = g2(0);
+            C = g3(0);
+            D = g4(0);
+
+            function o = S_fun(u,v)
+                if isrow(u) && isrow(v)
+                    flipped = false;
+                else
+                    flipped = true;
+                    u = u';
+                    v = v';
+                end
+
+                x1 = g1(u);
+                x2 = g2(v);
+                x3 = g3(1-u);
+                x4 = g4(1-v);
+
+                o1 = (1-v).*x1(1,:) + u.*x2(1,:) + v.*x3(1,:) + (1-u).*x4(1,:) ...
+                    -((1-u).*(1-v).*A(1,:) + u.*(1-v).*B(1,:) + u.*v.*C(1,:) + (1-u).*v.*D(1,:));
+                o2 = (1-v).*x1(2,:) + u.*x2(2,:) + v.*x3(2,:) + (1-u).*x4(2,:) ...
+                    -((1-u).*(1-v).*A(2,:) + u.*(1-v).*B(2,:) + u.*v.*C(2,:) + (1-u).*v.*D(2,:));
+
+                if ~flipped
+                    o = [o1;o2];
+                else
+                    o = [o1'; o2'];
+                end
+            end
+
+            obj.S = @S_fun;
+        end
+
+        % Does this funciton make sense?
+        % Should it always be eval?
+        function [X,Y] = map(obj,u,v)
+            default_arg('v',u);
+
+            if isscalar(u)
+                u = linspace(0,1,u);
+            end
+
+            if isscalar(v)
+                v = linspace(0,1,v);
+            end
+
+            S = obj.S;
+
+            nu = length(u);
+            nv = length(v);
+
+            X = zeros(nv,nu);
+            Y = zeros(nv,nu);
+
+            u = rowVector(u);
+            v = rowVector(v);
+
+            for i = 1:nv
+                p = S(u,v(i));
+                X(i,:) = p(1,:);
+                Y(i,:) = p(2,:);
+            end
+        end
+
+        % Evaluate S for each pair of u and v,
+        % Return same shape as u
+        function [x, y] = eval(obj, u, v)
+            x = zeros(size(u));
+            y = zeros(size(u));
+
+            for i = 1:numel(u)
+                p = obj.S(u(i), v(i));
+                x(i) = p(1,:);
+                y(i) = p(2,:);
+            end
+        end
+
+        function h = plot(obj,nu,nv)
+            S = obj.S;
+
+            default_arg('nv',nu)
+
+            u = linspace(0,1,nu);
+            v = linspace(0,1,nv);
+
+            m = 100;
+
+            X = zeros(nu+nv,m);
+            Y = zeros(nu+nv,m);
+
+
+            t = linspace(0,1,m);
+            for i = 1:nu
+                p = S(u(i),t);
+                X(i,:) = p(1,:);
+                Y(i,:) = p(2,:);
+            end
+
+            for i = 1:nv
+                p = S(t,v(i));
+                X(i+nu,:) = p(1,:);
+                Y(i+nu,:) = p(2,:);
+            end
+
+            h = line(X',Y');
+        end
+
+
+        function h = show(obj,nu,nv)
+            default_arg('nv',nu)
+            S = obj.S;
+
+            if(nu>2 || nv>2)
+                h.grid = obj.plot(nu,nv);
+                set(h.grid,'Color',[0 0.4470 0.7410]);
+            end
+
+            h.border = obj.plot(2,2);
+            set(h.border,'Color',[0.8500 0.3250 0.0980]);
+            set(h.border,'LineWidth',2);
+        end
+
+
+        % TRANSFORMATIONS
+        function ti = translate(obj,a)
+            gs = obj.gs;
+
+            for i = 1:length(gs)
+                new_gs{i} = gs{i}.translate(a);
+            end
+
+            ti = parametrization.Ti(new_gs{:});
+        end
+
+        % Mirrors the Ti so that the resulting Ti is still left handed.
+        %  (Corrected by reversing curves and switching e and w)
+        function ti = mirror(obj, a, b)
+            gs = obj.gs;
+
+            new_gs = cell(1,4);
+
+            new_gs{1} = gs{1}.mirror(a,b).reverse();
+            new_gs{3} = gs{3}.mirror(a,b).reverse();
+            new_gs{2} = gs{4}.mirror(a,b).reverse();
+            new_gs{4} = gs{2}.mirror(a,b).reverse();
+
+            ti = parametrization.Ti(new_gs{:});
+        end
+
+        function ti = rotate(obj,a,rad)
+            gs = obj.gs;
+
+            for i = 1:length(gs)
+                new_gs{i} = gs{i}.rotate(a,rad);
+            end
+
+            ti = parametrization.Ti(new_gs{:});
+        end
+
+        function ti = rotate_edges(obj,n);
+            new_gs = cell(1,4);
+            for i = 0:3
+                new_i = mod(i - n,4);
+                new_gs{new_i+1} = obj.gs{i+1};
+            end
+            ti = parametrization.Ti(new_gs{:});
+        end
+    end
+
+    methods(Static)
+        function obj = points(p1, p2, p3, p4)
+            g1 = parametrization.Curve.line(p1,p2);
+            g2 = parametrization.Curve.line(p2,p3);
+            g3 = parametrization.Curve.line(p3,p4);
+            g4 = parametrization.Curve.line(p4,p1);
+
+            obj = parametrization.Ti(g1,g2,g3,g4);
+        end
+
+        function obj = rectangle(a, b)
+            p1 = a;
+            p2 = [b(1), a(2)];
+            p3 = b;
+            p4 = [a(1), b(2)];
+
+            obj = parametrization.Ti.points(p1,p2,p3,p4);
+        end
+
+        % Like the constructor but allows inputing line curves as 2-cell arrays:
+        %     example: parametrization.Ti.linesAndCurves(g1, g2, {a, b} g4)
+        function obj = linesAndCurves(C1, C2, C3, C4)
+            C = {C1, C2, C3, C4};
+            c = cell(1,4);
+
+            for i = 1:4
+                if ~iscell(C{i})
+                    c{i} = C{i};
+                else
+                    c{i} = parametrization.Curve.line(C{i}{:});
+                end
+            end
+
+            obj = parametrization.Ti(c{:});
+        end
+
+        function label(varargin)
+            if nargin == 2 && ischar(varargin{2})
+                label_impl(varargin{:});
+            else
+                for i = 1:length(varargin)
+                    label_impl(varargin{i},inputname(i));
+                end
+            end
+
+
+            function label_impl(ti,str)
+                S = ti.S;
+
+                pc = S(0.5,0.5);
+
+                margin = 0.1;
+                pw = S(  margin,      0.5);
+                pe = S(1-margin,      0.5);
+                ps = S(     0.5,   margin);
+                pn = S(     0.5, 1-margin);
+
+
+                ti.show(2,2);
+                parametrization.place_label(pc,str);
+                parametrization.place_label(pw,'w');
+                parametrization.place_label(pe,'e');
+                parametrization.place_label(ps,'s');
+                parametrization.place_label(pn,'n');
+            end
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/Ti3D.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/Ti3D.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,253 @@
+classdef Ti3D
+    properties
+        gs % {6}Surfaces
+        V  % FunctionHandle(XI,ETA,ZETA)
+    end
+    
+    methods
+        % TODO write all fancy features for flipping around with the surfaces
+        % Each surface is defined with an outward facing outward and choosing
+        % the "corner" where XI=0 if not possible the corner where ETA=0 is choosen
+        function obj = Ti3D(CW,CE,CS,CN,CB,CT)
+            obj.gs = {CE,CW,CS,CN,CB,CT};
+            
+            gw = CW.g;
+            ge = CE.g;
+            gs = CS.g;
+            gn = CN.g;
+            gb = CB.g;
+            gt = CT.g;
+            
+            function o = V_fun(XI,ETA,ZETA)
+                XI=XI';
+                ETA=ETA';
+                ZETA=ZETA';
+                
+                one=0*ETA+1;
+                zero=0*ETA;
+                
+                Sw = gw(ETA,(1-ZETA));
+                Se = ge((1-ETA),(1-ZETA));
+                Ss = gs(XI,ZETA);
+                Sn = gn((1-XI),(1-ZETA));
+                Sb = gb((1-XI),ETA);
+                St = gt(XI,ETA);
+                
+                Ewt = gw(ETA,zero);
+                Ewb = gw(ETA,one);               
+                Ews = gw(zero,1-ZETA);
+                Ewn = gw(one,1-ZETA);
+                Eet = ge(1-ETA,zero);
+                Eeb = ge(1-ETA,one);
+                Ees = ge(one,1-ZETA);
+                Een = ge(zero,1-ZETA);
+                Enb = gn(1-XI,one);
+                Ent = gn(1-XI,zero);
+                Est = gs(XI,one);
+                Esb = gs(XI,zero);
+                
+                Cwbs = gw(zero,one);
+                Cwbn = gw(one,one);
+                Cwts = gw(zero,zero);
+                Cwtn = gw(one,zero);
+                Cebs = ge(one,one);
+                Cebn = ge(zero,one);
+                Cets = ge(one,zero);
+                Cetn = ge(zero,zero);
+                
+                
+                X1 = (1-XI).*Sw(1,:,:) + XI.*Se(1,:,:);
+                X2 = (1-ETA).*Ss(1,:,:) + ETA.*Sn(1,:,:);
+                X3 = (1-ZETA).*Sb(1,:,:) + ZETA.*St(1,:,:);
+                
+                X12 = (1-XI).*(1-ETA).*Ews(1,:,:) + (1-XI).*ETA.*Ewn(1,:,:) + XI.*(1-ETA).*Ees(1,:,:) + XI.*ETA.*Een(1,:,:);
+                X13 = (1-XI).*(1-ZETA).*Ewb(1,:,:) + (1-XI).*ZETA.*Ewt(1,:,:) + XI.*(1-ZETA).*Eeb(1,:,:) + XI.*ZETA.*Eet(1,:,:);
+                X23 = (1-ETA).*(1-ZETA).*Esb(1,:,:) + (1-ETA).*ZETA.*Est(1,:,:) + ETA.*(1-ZETA).*Enb(1,:,:) + ETA.*ZETA.*Ent(1,:,:);
+                
+                X123 = (1-XI).*(1-ETA).*(1-ZETA).*Cwbs(1,:,:) + (1-XI).*(1-ETA).*ZETA.*Cwts(1,:,:) + (1-XI).*ETA.*(1-ZETA).*Cwbn(1,:,:) + ...
+                    (1-XI).*ETA.*ZETA.*Cwtn(1,:,:) + XI.*(1-ETA).*(1-ZETA).*Cebs(1,:,:) + XI.*(1-ETA).*ZETA.*Cets(1,:,:) + ...
+                    XI.*ETA.*(1-ZETA).*Cebn(1,:,:) + XI.*ETA.*ZETA.*Cetn(1,:,:);
+                
+                X = X1 + X2 + X3 - X12 - X13 - X23 + X123;
+                
+                
+                Y1 = (1-XI).*Sw(2,:,:) + XI.*Se(2,:,:);
+                Y2 = (1-ETA).*Ss(2,:,:) + ETA.*Sn(2,:,:);
+                Y3 = (1-ZETA).*Sb(2,:,:) + ZETA.*St(2,:,:);
+                
+                Y12 = (1-XI).*(1-ETA).*Ews(2,:,:) + (1-XI).*ETA.*Ewn(2,:,:) + XI.*(1-ETA).*Ees(2,:,:) + XI.*ETA.*Een(2,:,:);
+                Y13 = (1-XI).*(1-ZETA).*Ewb(2,:,:) + (1-XI).*ZETA.*Ewt(2,:,:) + XI.*(1-ZETA).*Eeb(2,:,:) + XI.*ZETA.*Eet(2,:,:);
+                Y23 = (1-ETA).*(1-ZETA).*Esb(2,:,:) + (1-ETA).*ZETA.*Est(2,:,:) + ETA.*(1-ZETA).*Enb(2,:,:) + ETA.*ZETA.*Ent(2,:,:);
+                
+                Y123 = (1-XI).*(1-ETA).*(1-ZETA).*Cwbs(2,:,:) + (1-XI).*(1-ETA).*ZETA.*Cwts(2,:,:) + (1-XI).*ETA.*(1-ZETA).*Cwbn(2,:,:) + ...
+                    (1-XI).*ETA.*ZETA.*Cwtn(2,:,:) + XI.*(1-ETA).*(1-ZETA).*Cebs(2,:,:) + XI.*(1-ETA).*ZETA.*Cets(2,:,:) + ...
+                    XI.*ETA.*(1-ZETA).*Cebn(2,:,:) + XI.*ETA.*ZETA.*Cetn(2,:,:);
+                
+                Y = Y1 + Y2 + Y3 - Y12 - Y13 - Y23 + Y123;
+                
+                
+                Z1 = (1-XI).*Sw(3,:,:) + XI.*Se(3,:,:);
+                Z2 = (1-ETA).*Ss(3,:,:) + ETA.*Sn(3,:,:);
+                Z3 = (1-ZETA).*Sb(3,:,:) + ZETA.*St(3,:,:);
+                
+                Z12 = (1-XI).*(1-ETA).*Ews(3,:,:) + (1-XI).*ETA.*Ewn(3,:,:) + XI.*(1-ETA).*Ees(3,:,:) + XI.*ETA.*Een(3,:,:);
+                Z13 = (1-XI).*(1-ZETA).*Ewb(3,:,:) + (1-XI).*ZETA.*Ewt(3,:,:) + XI.*(1-ZETA).*Eeb(3,:,:) + XI.*ZETA.*Eet(3,:,:);
+                Z23 = (1-ETA).*(1-ZETA).*Esb(3,:,:) + (1-ETA).*ZETA.*Est(3,:,:) + ETA.*(1-ZETA).*Enb(3,:,:) + ETA.*ZETA.*Ent(3,:,:);
+                
+                Z123 = (1-XI).*(1-ETA).*(1-ZETA).*Cwbs(3,:,:) + (1-XI).*(1-ETA).*ZETA.*Cwts(3,:,:) + (1-XI).*ETA.*(1-ZETA).*Cwbn(3,:,:) + ...
+                    (1-XI).*ETA.*ZETA.*Cwtn(3,:,:) + XI.*(1-ETA).*(1-ZETA).*Cebs(3,:,:) + XI.*(1-ETA).*ZETA.*Cets(3,:,:) + ...
+                    XI.*ETA.*(1-ZETA).*Cebn(3,:,:) + XI.*ETA.*ZETA.*Cetn(3,:,:);
+                
+                Z = Z1 + Z2 + Z3 - Z12 - Z13 - Z23 + Z123;
+                o = [X;Y;Z];
+            end
+            
+            obj.V = @V_fun;
+        end
+        
+        %Should be rewritten so that the input is xi eta zeta 
+        function [X,Y,Z] = map(obj,XI,ETA,ZETA)
+            
+            V = obj.V;
+            
+            p = V(XI,ETA,ZETA);
+            X = p(1,:)';
+            Y = p(2,:)';
+            Z = p(3,:)';
+            
+        end
+        
+        %         function h = plot(obj,nu,nv)
+        %             S = obj.S;
+        %
+        %             default_arg('nv',nu)
+        %
+        %             u = linspace(0,1,nu);
+        %             v = linspace(0,1,nv);
+        %
+        %             m = 100;
+        %
+        %             X = zeros(nu+nv,m);
+        %             Y = zeros(nu+nv,m);
+        %
+        %
+        %             t = linspace(0,1,m);
+        %             for i = 1:nu
+        %                 p = S(u(i),t);
+        %                 X(i,:) = p(1,:);
+        %                 Y(i,:) = p(2,:);
+        %             end
+        %
+        %             for i = 1:nv
+        %                 p = S(t,v(i));
+        %                 X(i+nu,:) = p(1,:);
+        %                 Y(i+nu,:) = p(2,:);
+        %             end
+        %
+        %             h = line(X',Y');
+        %         end
+        %
+        %
+        %         function h = show(obj,nu,nv)
+        %             default_arg('nv',nu)
+        %             S = obj.S;
+        %
+        %             if(nu>2 || nv>2)
+        %                 h_grid = obj.plot(nu,nv);
+        %                 set(h_grid,'Color',[0 0.4470 0.7410]);
+        %             end
+        %
+        %             h_bord = obj.plot(2,2);
+        %             set(h_bord,'Color',[0.8500 0.3250 0.0980]);
+        %             set(h_bord,'LineWidth',2);
+        %         end
+        %
+        %
+        %         % TRANSFORMATIONS
+        %         function ti = translate(obj,a)
+        %             gs = obj.gs;
+        %
+        %             for i = 1:length(gs)
+        %                 new_gs{i} = gs{i}.translate(a);
+        %             end
+        %
+        %             ti = grid.Ti(new_gs{:});
+        %         end
+        %
+        %         % Mirrors the Ti so that the resulting Ti is still left handed.
+        %         %  (Corrected by reversing curves and switching e and w)
+        %         function ti = mirror(obj, a, b)
+        %             gs = obj.gs;
+        %
+        %             new_gs = cell(1,4);
+        %
+        %             new_gs{1} = gs{1}.mirror(a,b).reverse();
+        %             new_gs{3} = gs{3}.mirror(a,b).reverse();
+        %             new_gs{2} = gs{4}.mirror(a,b).reverse();
+        %             new_gs{4} = gs{2}.mirror(a,b).reverse();
+        %
+        %             ti = grid.Ti(new_gs{:});
+        %         end
+        %
+        %         function ti = rotate(obj,a,rad)
+        %             gs = obj.gs;
+        %
+        %             for i = 1:length(gs)
+        %                 new_gs{i} = gs{i}.rotate(a,rad);
+        %             end
+        %
+        %             ti = grid.Ti(new_gs{:});
+        %         end
+        %
+        %         function ti = rotate_edges(obj,n);
+        %             new_gs = cell(1,4);
+        %             for i = 0:3
+        %                 new_i = mod(i - n,4);
+        %                 new_gs{new_i+1} = obj.gs{i+1};
+        %             end
+        %             ti = grid.Ti(new_gs{:});
+        %         end
+        %     end
+        %
+        %     methods(Static)
+        %         function obj = points(p1, p2, p3, p4)
+        %             g1 = grid.Curve.line(p1,p2);
+        %             g2 = grid.Curve.line(p2,p3);
+        %             g3 = grid.Curve.line(p3,p4);
+        %             g4 = grid.Curve.line(p4,p1);
+        %
+        %             obj = grid.Ti(g1,g2,g3,g4);
+        %         end
+        %
+        %         function label(varargin)
+        %             if nargin == 2 && ischar(varargin{2})
+        %                 label_impl(varargin{:});
+        %             else
+        %                 for i = 1:length(varargin)
+        %                     label_impl(varargin{i},inputname(i));
+        %                 end
+        %             end
+        %
+        %
+        %             function label_impl(ti,str)
+        %                 S = ti.S;
+        %
+        %                 pc = S(0.5,0.5);
+        %
+        %                 margin = 0.1;
+        %                 pw = S(  margin,      0.5);
+        %                 pe = S(1-margin,      0.5);
+        %                 ps = S(     0.5,   margin);
+        %                 pn = S(     0.5, 1-margin);
+        %
+        %
+        %                 ti.show(2,2);
+        %                 grid.place_label(pc,str);
+        %                 grid.place_label(pw,'w');
+        %                 grid.place_label(pe,'e');
+        %                 grid.place_label(ps,'s');
+        %                 grid.place_label(pn,'n');
+        %             end
+ %                end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/TiTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/TiTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,52 @@
+function tests = TiTest()
+    tests = functiontests(localfunctions);
+end
+
+function testScalarInput(testCase)
+    ti = getMinimumTi();
+
+    cases = {
+        % {u, v, out},
+        {0, 0, [1; 2]},
+        {0, 1, [1; 4]},
+        {1, 0, [3; 2]},
+        {1, 1, [3; 4]},
+        {0.5, 0.5, [2; 3]},
+    };
+
+    for i = 1:length(cases)
+        u = cases{i}{1};
+        v = cases{i}{2};
+        expected = cases{i}{3};
+
+        testCase.verifyEqual(ti.S(u,v), expected, sprintf('Case: %d',i));
+    end
+end
+
+function testRowVectorInput(testCase)
+    ti = getMinimumTi();
+
+    u = [0, 0.5, 1];
+    v = [0, 0, 0.5];
+    expected = [
+        1, 2, 3;
+        2, 2, 3;
+    ];
+
+    testCase.verifyEqual(ti.S(u,v), expected);
+end
+
+function testColumnvectorInput(testCase)
+   ti = getMinimumTi();
+
+    u = [0; 0.5; 1];
+    v = [0; 0; 0.5];
+    expected = [1; 2; 3; 2; 2; 3];
+
+    testCase.verifyEqual(ti.S(u,v), expected);
+end
+
+
+function ti = getMinimumTi()
+    ti = parametrization.Ti.rectangle([1; 2], [3; 4]);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/equal_step_size.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/equal_step_size.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+% Calculates M so that the stepsize m/M is as close to n/M as possible
+function M = equal_step_size(n,N,m)
+    M = round((m*(N-1)+n)/n);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/concat_curve.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/concat_curve.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,12 @@
+% Concatenate two curves g1 and g2 intop
+%   g = concat_curve(g1,g2)
+function g = concat_curve(g1,g2)
+    function v = g_fun(t)
+        if t < 1/2
+            v = g1(2*t);
+        else
+            v = g2(2*t-1);
+        end
+    end
+    g = @g_fun;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/curve_discretise.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/curve_discretise.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,97 @@
+% Discretises the curve g with the smallest number of points such that all segments
+% are shorter than h. If do_plot is true the points of the discretisation and
+% the normals of the curve in those points are plotted.
+%
+%   [t,p,d] = curve_discretise(g,h,do_plot)
+%
+%   t is a vector of input values to g.
+%   p is a cector of points.
+%   d are the length of the segments.
+function [t,p,d] = curve_discretise(g,h,do_plot)
+    default_arg('do_plot',false)
+
+    n = 10;
+
+    [t,p,d] = curve_discretise_n(g,n);
+
+    % ni = 0;
+    while any(d>h)
+        [t,p,d] = curve_discretise_n(g,n);
+        n = ceil(n*d(1)/h);
+        % ni = ni+1;
+    end
+
+    % nj = 0;
+    while all(d<h)
+        [t,p,d] = curve_discretise_n(g,n);
+        n = n-1;
+        % nj = nj+1;
+    end
+    [t,p,d] = curve_discretise_n(g,n+1);
+
+    % fprintf('ni = %d, nj = %d\n',ni,nj);
+
+    if do_plot
+        fprintf('n:%d  max: %f min: %f\n', n, max(d),min(d));
+        p = parametrization.map_curve(g,t);
+        figure
+        show(g,t,h);
+    end
+
+end
+
+function [t,p,d] = curve_discretise_n(g,n)
+    t = linspace(0,1,n);
+    t = equalize_d(g,t);
+    d = D(g,t);
+    p = parametrization.map_curve(g,t);
+end
+
+function d = D(g,t)
+    p = parametrization.map_curve(g,t);
+
+    d = zeros(1,length(t)-1);
+    for i = 1:length(d)
+        d(i) = norm(p(:,i) - p(:,i+1));
+    end
+end
+
+function t = equalize_d(g,t)
+    d = D(g,t);
+    v = d-mean(d);
+    while any(abs(v)>0.01*mean(d))
+        dt = t(2:end)-t(1:end-1);
+        t(2:end) = t(2:end) - cumsum(dt.*v./d);
+
+        t = t/t(end);
+        d = D(g,t);
+        v = d-mean(d);
+    end
+end
+
+
+function show(g,t,hh)
+    p = parametrization.map_curve(g,t);
+
+
+
+    h = parametrization.plot_curve(g);
+    h.LineWidth = 2;
+    axis equal
+    hold on
+    h = plot(p(1,:),p(2,:),'.');
+    h.Color = [0.8500 0.3250 0.0980];
+    h.MarkerSize = 24;
+    hold off
+
+    n = parametrization.curve_normals(g,t);
+    hold on
+    for  i = 1:length(t)
+        p0 = p(:,i);
+        p1 = p0 + hh*n(:,i);
+        l = [p0, p1];
+        h = plot(l(1,:),l(2,:));
+        h.Color = [0.8500 0.3250 0.0980];
+    end
+
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/curve_interp.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/curve_interp.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,58 @@
+% Create a cubic spline from the points (x,y) using periodic conditions.
+%   g = curve_interp(x,y)
+function g = curve_interp(x,y)
+    default_arg('x',[0 2 2 1 1 0])
+    default_arg('y',[0 0 2 2 1 1])
+    % solve for xp and yp
+
+    % x(t) = at^4 + bt^2+ct+d
+
+    % a = xp1 -2x1 + 2x0 +  xp0
+    % b = 3x1 -xp1 - 3x0 + 2xp0
+    % c = xp0
+    % d = x0
+
+    assert(length(x) == length(y))
+    n = length(x);
+    A = spdiags(ones(n,1)*[2, 8, 2],-1:1,n,n);
+    A(n,1) = 2;
+    A(1,n) = 2;
+
+    bx = zeros(n,1);
+    for i = 2:n-1
+        bx(i) = -6*x(i-1)+6*x(i+1);
+    end
+    bx(1) = -6*x(n)+6*x(2);
+    bx(n) = -6*x(n-1)+6*x(1);
+
+    by = zeros(n,1);
+    for i = 2:n-1
+        by(i) = -6*y(i-1)+6*y(i+1);
+    end
+    by(1) = -6*y(n)+6*y(2);
+    by(n) = -6*y(n-1)+6*y(1);
+
+
+    xp = A\bx;
+    yp = A\by;
+
+    x(end+1) = x(1);
+    y(end+1) = y(1);
+
+    xp(end+1) = xp(1);
+    yp(end+1) = yp(1);
+
+    function v = g_fun(t)
+        t = mod(t,1);
+        i = mod(floor(t*n),n) + 1;
+        t = t * n -(i-1);
+        X = (2*x(i)-2*x(i+1)+xp(i)+xp(i+1))*t.^3 + (-3*x(i)+3*x(i+1)-2*xp(i)-xp(i+1))*t.^2 + (xp(i))*t + x(i);
+        Y = (2*y(i)-2*y(i+1)+yp(i)+yp(i+1))*t.^3 + (-3*y(i)+3*y(i+1)-2*yp(i)-yp(i+1))*t.^2 + (yp(i))*t + y(i);
+        v = [X;Y];
+    end
+
+    g = @g_fun;
+end
+
+
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/max_h.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/max_h.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,33 @@
+function [d_max, i1_max, j1_max, i2_max, j2_max] = max_h(X,Y)
+    ni = size(X,1);
+    nj = size(X,2);
+    d_max = 0;
+
+    i1_max = 0;
+    j1_max = 0;
+    i2_max = 0;
+    j2_max = 0;
+
+    D = {[0,-1],[1,0],[0,1],[-1,0]};
+
+    for i = 1:ni
+        for j = 1:nj
+            p1 = [X(i,j); Y(i,j)];
+            for k = 1:length(D)
+                i2 = i+D{k}(1);
+                j2 = j+D{k}(2);
+                if i2 >= 1 && i2 <= ni && j2 >= 1 && j2 <= nj
+                    p2 = [X(i2,j2); Y(i2,j2)];
+                    d = norm(p2-p1);
+                    if d > d_max;
+                        d_max = d;
+                        i1_max = i;
+                        j1_max = j;
+                        i2_max = i2;
+                        j2_max = j2;
+                    end
+                end
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/min_h.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/min_h.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,34 @@
+function [d_min, i1_min, j1_min, i2_min, j2_min] = min_h(X,Y)
+    ni = size(X,1);
+    nj = size(X,2);
+    d_min = norm([X(1,1);Y(1,1)] - [X(ni,nj);Y(ni,nj)]);
+
+    i1_min = 0;
+    j1_min = 0;
+    i2_min = 0;
+    j2_min = 0;
+
+    D = {[-1,-1],[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0]};
+    % D = {[0,-1],[1,0],[0,1],[-1,0]};
+
+    for i = 1:ni
+        for j = 1:nj
+            p1 = [X(i,j); Y(i,j)];
+            for k = 1:length(D)
+                i2 = i+D{k}(1);
+                j2 = j+D{k}(2);
+                if i2 >= 1 && i2 <= ni && j2 >= 1 && j2 <= nj
+                    p2 = [X(i2,j2); Y(i2,j2)];
+                    d = norm(p2-p1);
+                    if d < d_min;
+                        d_min = d;
+                        i1_min = i;
+                        j1_min = j;
+                        i2_min = i2;
+                        j2_min = j2;
+                    end
+                end
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/plot_shape.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/plot_shape.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,12 @@
+% Plot a shape using n points. Returns cell array of plot handles.
+%   hs = plot_shape(s,n)
+function hs = plot_shape(s,n)
+    default_arg('n',100);
+
+    hs = {};
+    hold on
+    for i = 1:length(s)
+        hs{end+1} = parametrization.plot_curve(s{i},n);
+    end
+    hold off
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/shape.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/shape.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+% Creates a shape from a number of curves. A shape is a cell array of curves.
+function s = shape(varargin);
+    s = varargin;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/shape_discretise.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/shape_discretise.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,8 @@
+% Discretises a shape such that points on the curves are no further than h appart.
+function p = shape_discretise(s,h)
+    p = [];
+    for i = 1:length(s)
+        [~,pt] = parametrization.curve_discretise(s{i},h);
+        p = [p, pt];
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/shape_linesegments.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/shape_linesegments.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,9 @@
+% Converts a shape into a cell array of linesegments shorter than h.
+function l = shape_linesegments(s,h)
+    l = {};
+
+    for i = 1:length(s)
+        t = parametrization.curve_discretise(s{i},h);
+        l = [l, parametrization.curve_linesegments(s{i},t)];
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/triang_interp.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/triang_interp.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,132 @@
+classdef triang_interp
+    properties
+        g1, g2 ,g3  % Curves encirling the tirangle in the positive direction.
+        A,B,C  % The corners of the triangle
+        Sa, Sb, Sc % Mappings from square with different sides collapsed
+    end
+
+    methods
+        function o = triang_interp(g1,g2,g3)
+            o.g1 = g1;
+            o.g2 = g2;
+            o.g3 = g3;
+            o.A = g1(0);
+            o.B = g2(0);
+            o.C = g3(0);
+            o.Sa = parametrization.triang_interp.square_to_triangle_interp(g2,g3,g1);
+            o.Sb = parametrization.triang_interp.square_to_triangle_interp(g3,g1,g2);
+            o.Sc = parametrization.triang_interp.square_to_triangle_interp(g1,g2,g3);
+        end
+
+
+        function show(o,N)
+            % Show the mapped meridians of the triangle.
+            % Might be used for the barycentric coordinates.
+            ma = @(t)o.Sa(1/2,1-t);
+            mb = @(t)o.Sb(1/2,1-t);
+            mc = @(t)o.Sc(1/2,1-t);
+
+            na = @(t)o.Sa(t,1/2);
+
+            ka = @(t)(o.g1(1-t)+o.g2(t))/2;
+
+            h = parametrization.plot_curve(ma);
+            h.Color = Color.blue;
+            h = parametrization.plot_curve(mb);
+            h.Color = Color.blue;
+            h = parametrization.plot_curve(mc);
+            h.Color = Color.blue;
+
+            h = parametrization.plot_curve(na);
+            h.Color = Color.red;
+
+            h = parametrization.plot_curve(ka);
+            h.Color = Color.red;
+
+            [a(1),a(2)] = ma(1/3);
+            [b(1),b(2)] = mb(1/3);
+            [c(1),c(2)] = mc(1/3);
+
+            d = ka(1-1/3);
+
+
+            parametrization.label_pt(a,b,c,d);
+
+
+            % t = linspace(0,1,N);
+            % for i = 1:N
+            %     sa = @(s)o.Sa(s,t(i));
+            %     sb = @(s)o.Sb(s,t(i));
+            %     sc = @(s)o.Sc(s,t(i));
+
+            %     h = parametrization.plot_curve(sa);
+            %     h.Color = Color.blue;
+            %     h = parametrization.plot_curve(sb);
+            %     h.Color = Color.blue;
+            %     h = parametrization.plot_curve(sc);
+            %     h.Color = Color.blue;
+            % end
+
+            h = parametrization.plot_curve(o.g1);
+            h.LineWidth = 2;
+            h.Color = Color.red;
+
+            h = parametrization.plot_curve(o.g2);
+            h.LineWidth = 2;
+            h.Color = Color.red;
+
+            h = parametrization.plot_curve(o.g3);
+            h.LineWidth = 2;
+            h.Color = Color.red;
+
+        end
+
+
+    end
+
+    methods(Static)
+        % Makes a mapping from the unit square to a triangle by collapsing
+        % one of the sides of the squares to a corner on the triangle
+        % The collapsed side is mapped to the corner oposite to g1.
+        % This is done such that for S(s,t), S(s,1) = g1(s)
+        function S = square_to_triangle_interp(g1,g2,g3)
+            corner = parametrization.line_segment(g3(0),g3(0));
+            S = parametrization.transfinite_interp(corner,g3,f(g1),f(g2))
+
+            % Function to flip a curve
+            function h = f(g)
+                h = @(t)g(1-t);
+            end
+        end
+    end
+
+end
+
+% % Return a mapping from u.v to x,y of the domain encircled by g1 g2 g3 in the the positive direction. created be using transfinite interpolation.
+% function S = triang_interp(g1,g2,g3)
+%     A = g1(0)
+%     B = g2(0)
+%     C = g3(0)
+
+%     function [x,y] = S_fun(u,v)
+%         w = sqrt((u-1)^2+v^2)/sqrt(2); % Parameter for g3
+%         v = v*(1-u-v)*g1(u) + u*(1-u-v)*g2(v) + u*v*g3(w) ...
+%             +(1-u)*(1-v)*A+u*(1-v)*B + (1-u)*v*C;
+%         x = v(1);
+%         y = v(2);
+%     end
+%     S = @S_fun;
+% end
+
+
+
+% function subsref(obj,S)
+%       if ~all(isnumeric(S.subs{:}))
+%         error('Only supports calling object with number')
+%       end
+%       if numel(S.subs{:}) > 1
+%         disp('You''ve called the object with more than one argument');
+%       else
+%         disp(['You called the object with argument = ',num2str(S.subs{:})]);
+%       end
+%     end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/triang_interp_pts.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/triang_interp_pts.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,12 @@
+% Creates a transfinite interpolation from connecting the four points wiht straight lines.
+function [S, g1, g2, g3] = triang_interp_pts(p1,p2,p3)
+    if size(p1) ~= [2 1]
+        error('p1 is strange!');
+    end
+
+    g1 = @(t)(p1 + t*(p2-p1));
+    g2 = @(t)(p2 + t*(p3-p2));
+    g3 = @(t)(p3 + t*(p1-p3));
+
+    S = parametrization.triang_interp(g1,g2,g3);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/triang_map.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/triang_map.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,29 @@
+% Creates a grid [X,Y] from the mapping function S at points in vectors u,v
+function [X, Y] = traing_map(S,u,v)
+    error('not done')
+    if nargin == 2
+        v = u;
+    end
+
+    if isscalar(u)
+        u = linspace(0,1,u);
+    end
+
+    if isscalar(v)
+        v = linspace(0,1,v);
+    end
+
+    nu = length(u);
+    nv = length(v);
+
+    X = zeros(nu,nv);
+    Y = zeros(nu,nv);
+
+    for i = 1:nu
+        for j = 1:nv
+            [x,y] = S(u(i),v(j));
+            X(i,j) = x;
+            Y(i,j) = y;
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/triang_plot_interp.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/triang_plot_interp.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,114 @@
+% Plots a transfinite interpolation in x,y space using nu and nv curves along u and v axes.
+
+
+
+
+
+
+% Plots a interp of a triangle where one the interpolation is from a square
+% with one side collapsed to
+function h = triang_plot_interp_kindaworking(S,n)
+    u = linspace(0,1,n);
+    v = linspace(0,1,n);
+
+    m = 100;
+    m = 20;
+
+    Xl_curves = cell(n,1);
+    Xr_curves = cell(n,1);
+    Y_curves = cell(n,1);
+
+
+    function u = wierdness(v,d,N)
+        if N == 0
+            u = 0;
+        else
+            u = N*d./(1-v);
+        end
+    end
+
+
+    %Y curves
+    t = linspace(0,1,m);
+    for i = 1:n
+        x = []; y = [];
+        for j = 1:length(t)
+            [x(j),y(j)] = S(t(j),v(i));
+        end
+        Y_curves{i} = [x', y'];
+    end
+
+
+    % Right and left X curves
+    t = linspace(0,1,m);
+    d = u(2);
+    for i = 1:n
+        xl = []; yl = [];
+        xr = []; yr = [];
+        N = i-1;
+        t = linspace(0,1-N*d,m);
+        for j = 1:length(t)
+            w = wierdness(t(j),d,N);
+            [xr(j),yr(j)] = S(w,t(j));
+            [xl(j),yl(j)] = S(1-w,t(j));
+        end
+        Xl_curves{i} = [xl', yl'];
+        Xr_curves{i} = [xr', yr'];
+    end
+
+    for i = 1:n-1
+        line(Xl_curves{i}(:,1),Xl_curves{i}(:,2))
+        line(Xr_curves{i}(:,1),Xr_curves{i}(:,2))
+        line(Y_curves{i}(:,1),Y_curves{i}(:,2))
+    end
+end
+
+
+
+
+function h = triang_plot_interp_nonworking(S,n)
+
+    u = linspace(0,1,n);
+    v = linspace(0,1,n);
+
+    m = 100;
+
+    X_curves = cell(n-1,1);
+    Y_curves = cell(n-1,1);
+    K_curves = cell(n-1,1);
+
+
+    t = linspace(0,1,m);
+    for i = 1:n-1
+        x = []; y = [];
+        for j = find(t+u(i) <= 1)
+            [x(j),y(j)] = S(u(i),t(j));
+        end
+        X_curves{i} = [x', y'];
+    end
+
+    for i = 1:n-1
+        x = []; y = [];
+        for j = find(t+v(i) <= 1)
+            [x(j),y(j)] = S(t(j),v(i));
+        end
+        Y_curves{i} = [x', y'];
+    end
+
+    for i = 2:n
+        x = []; y = [];
+        for j = find(t<u(i))
+            [x(j),y(j)] = S(t(j), u(i)-t(j));
+        end
+        K_curves{i-1} = [x', y'];
+    end
+
+    for i = 1:n-1
+        line(X_curves{i}(:,1),X_curves{i}(:,2))
+        line(Y_curves{i}(:,1),Y_curves{i}(:,2))
+        line(K_curves{i}(:,1),K_curves{i}(:,2))
+    end
+
+    h = -1;
+    % h = plot(X_curves{:},Y_curves{:},K_curves{:});
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/old/triang_show.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/old/triang_show.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,23 @@
+% Show a grid as a matlab figure.
+function triang_show(S,n)
+
+    ih = ishold();
+
+    hold on
+    h_grid = parametrization.triang_plot_interp(S,n);
+    h_bord = parametrization.triang_plot_interp(S,2);
+
+    set(h_grid,'Color',[0 0.4470 0.7410]);
+    set(h_bord,'Color',[0.8500 0.3250 0.0980]);
+    set(h_bord,'LineWidth',2);
+
+    % axis auto
+    % axis equal
+    % axis square
+
+    if ih
+        hold on
+    else
+        hold off
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +parametrization/place_label.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/place_label.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,12 @@
+% 'left' | 'center' | 'right'
+% 'baseline' | 'top' | 'cap' | 'middle' | 'bottom'
+function place_label(pt,str,horzAl,vertAl)
+    default_arg('horzAl','center');
+    default_arg('vertAl', 'middle');
+
+    x = pt(1);
+    y = pt(2);
+    h = text(x,y,str);
+    h.HorizontalAlignment = horzAl;
+    h.VerticalAlignment = vertAl;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d1_upwind_3.m
--- a/+sbp/+implementations/d1_upwind_3.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/+implementations/d1_upwind_3.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,12 +1,12 @@
 function [H, HI, Dp, Dm, e_1, e_m] = d1_upwind_3(m,h)
-    
+
     if(m<6)
         error('Operator requires at least 6 grid points');
     end
 
     Hv = ones(m,1);
     Hv(1:3) = [3/8; 7/6; 23/24];
-    Hv(m-2:m) = rot90(Hv(1:3),2);
+    Hv(m-2:m) = rot90(Hv(1:3), 2);
     Hv = Hv*h;
     H = spdiag(Hv,0);
     HI = spdiag(1./Hv,0);
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d1_upwind_4.m
--- a/+sbp/+implementations/d1_upwind_4.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/+implementations/d1_upwind_4.m	Fri Sep 07 14:40:58 2018 +0200
@@ -23,7 +23,7 @@
     ];
 
     Qp(1:4,1:4)=Q_U;
-    Qp(m-3:m,m-3:m)=rot90(Q_U,2)'; %%% This is different from standard SBP
+    Qp(m-3:m,m-3:m)=rot90(Q_U, 2)'; %%% This is different from standard SBP
 
     Qm=-Qp';
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d2_2.m
--- a/+sbp/+implementations/d2_2.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/+implementations/d2_2.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,5 +1,5 @@
 function [H, HI, D1, D2, e_1, e_m, M, Q, S_1, S_m] = d2_2(m,h)
-    
+
     BP = 1;
     if(m<2*BP)
         error(['Operator requires at least ' num2str(2*BP) ' grid points']);
@@ -11,33 +11,40 @@
     H=(speye(m,m));H(1,1)=0.5;H(m,m)=0.5;
     H=h*H;
     HI=inv(H);
-    
+
     diags   = -1:1;
     stencil = [-1/2 0 1/2];
     D1 = stripeMatrix(stencil, diags, m);
-    
-    D1(1,1)=-1;D1(1,2)=1;D1(m,m-1)=-1;D1(m,m)=1;
-    D1(m,m-1)=-1;D1(m,m)=1;
-    D1=D1/h;
+
+    D1(1,1) = -1;
+    D1(1,2) = 1;
 
-    Q=H*D1 + 1/2*(e_1*e_1') - 1/2*(e_m*e_m');
+    D1(m,m-1) = -1;
+    D1(m,m)   = 1;
+
+    D1 = D1/h;
+
+    Q = H*D1 + 1/2*(e_1*e_1') - 1/2*(e_m*e_m');
 
     diags   = -1:1;
     stencil = [1 -2 1];
     D2 = stripeMatrix(stencil, diags, m);
-    
-    D2(1,1)=1;D2(1,2)=-2;D2(1,3)=1;
-    D2(m,m-2)=1;D2(m,m-1)=-2;D2(m,m)=1;
-    D2=D2/h^2;
 
-    S_U=[-3/2, 2, -1/2]/h;
-    S_1=sparse(1,m);
-    S_1(1:3)=S_U;
-    S_m=sparse(1,m);
-    S_m(m-2:m)=fliplr(-S_U);
+    D2(1,1) = 1;
+    D2(1,2) = -2;
+    D2(1,3) = 1;
+    D2(m,m-2) = 1;
+    D2(m,m-1) = -2;
+    D2(m,m)   = 1;
+    D2 = D2/h^2;
 
+    S_U = [-3/2, 2, -1/2]/h;
+    S_1 = sparse(1,m);
+    S_1(1:3) = S_U;
+    S_m = sparse(1,m);
+    S_m(m-2:m) = fliplr(-S_U);
 
-    M=-H*D2-e_1*S_1+e_m*S_m;
+    M = -H*D2-e_1*S_1+e_m*S_m;
     S_1 = S_1';
     S_m = S_m';
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d2_4.m
--- a/+sbp/+implementations/d2_4.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/+implementations/d2_4.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,5 +1,5 @@
 function [H, HI, D1, D2, e_1, e_m, M, Q, S_1, S_m] = d2_4(m,h)
-    
+
     BP = 4;
     if(m<2*BP)
         error(['Operator requires at least ' num2str(2*BP) ' grid points']);
@@ -20,7 +20,12 @@
 
     Q=spdiags([e -8*e 0*e 8*e -e], -2:2, m, m)/12;
     %Q=(-1/12*diag(ones(m-2,1),2)+8/12*diag(ones(m-1,1),1)-8/12*diag(ones(m-1,1),-1)+1/12*diag(ones(m-2,1),-2));
-    Q_U = [0 0.59e2 / 0.96e2 -0.1e1 / 0.12e2 -0.1e1 / 0.32e2; -0.59e2 / 0.96e2 0 0.59e2 / 0.96e2 0; 0.1e1 / 0.12e2 -0.59e2 / 0.96e2 0 0.59e2 / 0.96e2; 0.1e1 / 0.32e2 0 -0.59e2 / 0.96e2 0;];
+    Q_U = [
+        0              0.59e2/0.96e2  -0.1e1/0.12e2  -0.1e1/0.32e2;
+        -0.59e2/0.96e2 0              0.59e2/0.96e2  0;
+        0.1e1/0.12e2   -0.59e2/0.96e2 0              0.59e2/0.96e2;
+        0.1e1/0.32e2   0              -0.59e2/0.96e2 0;
+    ];
     Q(1:4,1:4)=Q_U;
     Q(m-3:m,m-3:m)=rot90( -Q_U(1:4,1:4) ,2 );
 
@@ -30,13 +35,18 @@
 
     %M=-(-1/12*diag(ones(m-2,1),2)+16/12*diag(ones(m-1,1),1)+16/12*diag(ones(m-1,1),-1)-1/12*diag(ones(m-2,1),-2)-30/12*diag(ones(m,1),0));
 
-    M_U=[0.9e1 / 0.8e1 -0.59e2 / 0.48e2 0.1e1 / 0.12e2 0.1e1 / 0.48e2; -0.59e2 / 0.48e2 0.59e2 / 0.24e2 -0.59e2 / 0.48e2 0; 0.1e1 / 0.12e2 -0.59e2 / 0.48e2 0.55e2 / 0.24e2 -0.59e2 / 0.48e2; 0.1e1 / 0.48e2 0 -0.59e2 / 0.48e2 0.59e2 / 0.24e2;];
+    M_U=[
+        0.9e1/0.8e1 -0.59e2/0.48e2 0.1e1/0.12e2 0.1e1/0.48e2;
+        -0.59e2/0.48e2 0.59e2/0.24e2 -0.59e2/0.48e2 0;
+        0.1e1/0.12e2 -0.59e2/0.48e2 0.55e2/0.24e2 -0.59e2/0.48e2;
+        0.1e1/0.48e2 0 -0.59e2/0.48e2 0.59e2/0.24e2;
+    ];
     M(1:4,1:4)=M_U;
 
     M(m-3:m,m-3:m)=rot90(  M_U ,2 );
     M=M/h;
 
-    S_U=[-0.11e2 / 0.6e1 3 -0.3e1 / 0.2e1 0.1e1 / 0.3e1;]/h;
+    S_U=[-0.11e2/0.6e1 3 -0.3e1/0.2e1 0.1e1/0.3e1;]/h;
     S_1=sparse(sparse(1,m));
     S_1(1:4)=S_U;
     S_m=sparse(sparse(1,m));
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d2_variable_4.m
--- a/+sbp/+implementations/d2_variable_4.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/+implementations/d2_variable_4.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,6 +1,6 @@
 function [H, HI, D1, D2, e_l, e_r, d1_l, d1_r] = d2_variable_4(m,h)
 
-    BP = 4;
+    BP = 6;
     if(m<2*BP)
         error(['Operator requires at least ' num2str(2*BP) ' grid points']);
     end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d2_variable_periodic_2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d2_variable_periodic_2.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,50 @@
+function [H, HI, D1, D2, e_l, e_r, d1_l, d1_r] = d2_variable_periodic_2(m,h)
+    % m = number of unique grid points, i.e. h = L/m;
+
+    if(m<3)
+        error(['Operator requires at least ' num2str(3) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Dummy boundary operators
+    e_l = sparse(m,1);
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_r = -rot90(d1_l, 2);
+
+    % D1 operator
+    diags   = -1:1;
+    stencil = [-1/2 0 1/2];
+    D1 = stripeMatrixPeriodic(stencil, diags, m);
+    D1 = D1/h;
+
+    scheme_width = 3;
+    scheme_radius = (scheme_width-1)/2;
+
+    r = 1:m;
+    offset = scheme_width;
+    r = r + offset;
+
+    function D2 = D2_fun(c)
+        c = [c(end-scheme_width+1:end); c; c(1:scheme_width) ];
+
+        Mm1 = -c(r-1)/2 - c(r)/2;
+        M0  =  c(r-1)/2 + c(r)   + c(r+1)/2;
+        Mp1 =            -c(r)/2 - c(r+1)/2;
+
+        vals = [Mm1,M0,Mp1];
+        diags = -scheme_radius : scheme_radius;
+        M = spdiagsPeriodic(vals,diags);
+
+        M=M/h;
+        D2=HI*(-M );
+    end
+    D2 = @D2_fun;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d2_variable_periodic_4.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d2_variable_periodic_4.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,57 @@
+function [H, HI, D1, D2, e_l, e_r, d1_l, d1_r] = d2_variable_periodic_4(m,h)
+    % m = number of unique grid points, i.e. h = L/m;
+
+    if(m<5)
+        error(['Operator requires at least ' num2str(5) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Dummy boundary operators
+    e_l = sparse(m,1);
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_r = -rot90(d1_l, 2);
+
+    S = d1_l*d1_l' + d1_r*d1_r';
+
+    % D1 operator
+    stencil = [1/12 -2/3 0 2/3 -1/12];
+    diags = -2:2;
+    Q = stripeMatrixPeriodic(stencil, diags, m);
+    D1 = HI*(Q - 1/2*e_l*e_l' + 1/2*e_r*e_r');
+
+
+    scheme_width = 5;
+    scheme_radius = (scheme_width-1)/2;
+
+    r = 1:m;
+    offset = scheme_width;
+    r = r + offset;
+
+    function D2 = D2_fun(c)
+        c = [c(end-scheme_width+1:end); c; c(1:scheme_width) ];
+
+        % Note: these coefficients are for -M.
+        Mm2 = -1/8*c(r-2) + 1/6*c(r-1) - 1/8*c(r);
+        Mm1 = 1/6 *c(r-2) + 1/2*c(r-1) + 1/2*c(r) + 1/6*c(r+1);
+        M0  = -1/24*c(r-2)- 5/6*c(r-1) - 3/4*c(r) - 5/6*c(r+1) - 1/24*c(r+2);
+        Mp1  = 0 * c(r-2) + 1/6*c(r-1) + 1/2*c(r) + 1/2*c(r+1) + 1/6 *c(r+2);
+        Mp2  = 0 * c(r-2) + 0 * c(r-1) - 1/8*c(r) + 1/6*c(r+1) - 1/8 *c(r+2);
+
+        vals = -[Mm2,Mm1,M0,Mp1,Mp2];
+        diags = -scheme_radius : scheme_radius;
+        M = spdiagsPeriodic(vals,diags);
+
+        M=M/h;
+        D2=HI*(-M );
+
+    end
+    D2 = @D2_fun;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d2_variable_periodic_6.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d2_variable_periodic_6.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,58 @@
+function [H, HI, D1, D2, e_l, e_r, d1_l, d1_r] = d2_variable_periodic_6(m,h)
+    % m = number of unique grid points, i.e. h = L/m;
+
+    if(m<7)
+        error(['Operator requires at least ' num2str(7) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Dummy boundary operators
+    e_l = sparse(m,1);
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_r = -rot90(d1_l, 2);
+
+
+    % D1 operator
+    diags   = -3:3;
+    stencil = [-1/60 9/60 -45/60 0 45/60 -9/60 1/60];
+    D1 = stripeMatrixPeriodic(stencil, diags, m);
+    D1 = D1/h;
+
+    % D2 operator
+    scheme_width = 7;
+    scheme_radius = (scheme_width-1)/2;
+
+    r = 1:m;
+    offset = scheme_width;
+    r = r + offset;
+
+    function D2 = D2_fun(c)
+        c = [c(end-scheme_width+1:end); c; c(1:scheme_width) ];
+
+        Mm3 =  c(r-2)/0.40e2 + c(r-1)/0.40e2 - 0.11e2/0.360e3 * c(r-3) - 0.11e2/0.360e3 * c(r);
+        Mm2 =  c(r-3)/0.20e2 - 0.3e1/0.10e2 * c(r-1) + c(r+1)/0.20e2 + 0.7e1/0.40e2 * c(r) + 0.7e1/0.40e2 * c(r-2);
+        Mm1 = -c(r-3)/0.40e2 - 0.3e1/0.10e2 * c(r-2) - 0.3e1/0.10e2 * c(r+1) - c(r+2)/0.40e2 - 0.17e2/0.40e2 * c(r) - 0.17e2/0.40e2 * c(r-1);
+        M0 =  c(r-3)/0.180e3 + c(r-2)/0.8e1 + 0.19e2/0.20e2 * c(r-1) + 0.19e2/0.20e2 * c(r+1) + c(r+2)/0.8e1 + c(r+3)/0.180e3 + 0.101e3/0.180e3 * c(r);
+        Mp1 = -c(r-2)/0.40e2 - 0.3e1/0.10e2 * c(r-1) - 0.3e1/0.10e2 * c(r+2) - c(r+3)/0.40e2 - 0.17e2/0.40e2 * c(r) - 0.17e2/0.40e2 * c(r+1);
+        Mp2 =  c(r-1)/0.20e2 - 0.3e1/0.10e2 * c(r+1) + c(r+3)/0.20e2 + 0.7e1/0.40e2 * c(r) + 0.7e1/0.40e2 * c(r+2);
+        Mp3 =  c(r+1)/0.40e2 + c(r+2)/0.40e2 - 0.11e2/0.360e3 * c(r) - 0.11e2/0.360e3 * c(r+3);
+
+        vals = [Mm3,Mm2,Mm1,M0,Mp1,Mp2,Mp3];
+        diags = -scheme_radius : scheme_radius;
+        M = spdiagsPeriodic(vals,diags);
+
+        M=M/h;
+        D2=HI*(-M );
+    end
+    D2 = @D2_fun;
+
+
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_compatible_6.m
--- a/+sbp/+implementations/d4_compatible_6.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/+implementations/d4_compatible_6.m	Fri Sep 07 14:40:58 2018 +0200
@@ -25,7 +25,7 @@
 
     % Vi b?rjar med normen. Notera att alla SBP operatorer delar samma norm,
     % vilket ?r n?dv?ndigt f?r stabilitet
-    
+
     BP = 8;
     if(m<2*BP)
         error(['Operator requires at least ' num2str(2*BP) ' grid points']);
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_compatible_halfvariable_2.m
--- a/+sbp/+implementations/d4_compatible_halfvariable_2.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,179 +0,0 @@
-% Returns D2 as a function handle
-function [H, HI, D1, D2, D3, D4, e_1, e_m, M4, Q, S2_1,...
-    S2_m, S3_1, S3_m, S_1, S_m] = d4_compatible_halfvariable_2(m,h)
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    %%% 4:de ordn. SBP Finita differens         %%%
-    %%% operatorer framtagna av Ken Mattsson    %%%
-    %%%                                         %%%
-    %%% 6 randpunkter, diagonal norm            %%%
-    %%%                                         %%%
-    %%% Datum: 2013-11-11                       %%%
-    %%%                                         %%%
-    %%%                                         %%%
-    %%% H           (Normen)                    %%%
-    %%% D1          (approx f?rsta derivatan)   %%%
-    %%% D2          (approx andra derivatan)    %%%
-    %%% D3          (approx tredje derivatan)   %%%
-    %%% D2          (approx fj?rde derivatan)   %%%
-    %%%                                         %%%
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-    % M?ste ange antal punkter (m) och stegl?ngd (h)
-    % Notera att dessa opetratorer ?r framtagna f?r att anv?ndas n?r
-    % vi har 3de och 4de derivator i v?r PDE
-    % I annat fall anv?nd de "traditionella" som har noggrannare
-    % randsplutningar f?r D1 och D2
-
-    % Vi b?rjar med normen. Notera att alla SBP operatorer delar samma norm,
-    % vilket ?r n?dv?ndigt f?r stabilitet
-    
-    BP = 4;
-    if(m<2*BP)
-        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
-    end
-
-    H=speye(m,m);H(1,1)=1/2;H(m,m)=1/2;
-
-
-    H=H*h;
-    HI=inv(H);
-
-
-    % First derivative SBP operator, 1st order accurate at first 6 boundary points
-
-    q1=1/2;
-%     Q=q1*(diag(ones(m-1,1),1)-diag(ones(m-1,1),-1));
-    stencil = [-q1,0,q1];
-    d = (length(stencil)-1)/2;
-    diags = -d:d;
-    Q = stripeMatrix(stencil, diags, m);
-
-    %Q=(-1/12*diag(ones(m-2,1),2)+8/12*diag(ones(m-1,1),1)-8/12*diag(ones(m-1,1),-1)+1/12*diag(ones(m-2,1),-2));
-
-
-    e_1=sparse(m,1);e_1(1)=1;
-    e_m=sparse(m,1);e_m(m)=1;
-
-
-    D1=HI*(Q-1/2*(e_1*e_1')+1/2*(e_m*e_m')) ;
-
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-
-    % Second derivative, 1st order accurate at first boundary points
-
-    % below for constant coefficients
-    % m1=-1;m0=2;
-    % M=m1*(diag(ones(m-1,1),1)+diag(ones(m-1,1),-1))+m0*diag(ones(m,1),0);M(1,1)=1;M(m,m)=1;
-    % M=M/h;
-    %D2=HI*(-M-e_1*S_1+e_m*S_m);
-
-    % Below for variable coefficients
-    % Require a vector c with the koeffients
-
-    S_U=[-3/2 2 -1/2]/h;
-    S_1=sparse(1,m);
-    S_1(1:3)=S_U;
-    S_m=sparse(1,m);
-    S_m(m-2:m)=fliplr(-S_U);
-
-    S_1 = S_1';
-    S_m = S_m';
-
-    M=sparse(m,m);
-    e_1 = sparse(e_1);
-    e_m = sparse(e_m);
-    S_1 = sparse(S_1);
-    S_m = sparse(S_m);
-
-    scheme_width = 3;
-    scheme_radius = (scheme_width-1)/2;
-    r = (1+scheme_radius):(m-scheme_radius);
-
-    function D2 = D2_fun(c)
-
-        Mm1 = -c(r-1)/2 - c(r)/2;
-        M0  =  c(r-1)/2 + c(r)   + c(r+1)/2;
-        Mp1 =            -c(r)/2 - c(r+1)/2;
-
-        M(r,:) = spdiags([Mm1 M0 Mp1],0:2*scheme_radius,length(r),m);
-
-
-        M(1:2,1:2)=[c(1)/2 + c(2)/2 -c(1)/2 - c(2)/2; -c(1)/2 - c(2)/2 c(1)/2 + c(2) + c(3)/2;];
-        M(m-1:m,m-1:m)=[c(m-2)/2 + c(m-1) + c(m)/2 -c(m-1)/2 - c(m)/2; -c(m-1)/2 - c(m)/2 c(m-1)/2 + c(m)/2;];
-        M=M/h;
-
-        D2=HI*(-M-c(1)*e_1*S_1'+c(m)*e_m*S_m');
-    end
-    D2 = @D2_fun;
-
-
-
-
-
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-
-    % Third derivative, 1st order accurate at first 6 boundary points
-
-    q2=1/2;q1=-1;
-%     Q3=q2*(diag(ones(m-2,1),2)-diag(ones(m-2,1),-2))+q1*(diag(ones(m-1,1),1)-diag(ones(m-1,1),-1));
-    stencil = [-q2,-q1,0,q1,q2];
-    d = (length(stencil)-1)/2;
-    diags = -d:d;
-    Q3 = stripeMatrix(stencil, diags, m);
-
-    %QQ3=(-1/8*diag(ones(m-3,1),3) + 1*diag(ones(m-2,1),2) - 13/8*diag(ones(m-1,1),1) +13/8*diag(ones(m-1,1),-1) -1*diag(ones(m-2,1),-2) + 1/8*diag(ones(m-3,1),-3));
-
-
-    Q3_U = [0 -0.13e2 / 0.16e2 0.7e1 / 0.8e1 -0.1e1 / 0.16e2; 0.13e2 / 0.16e2 0 -0.23e2 / 0.16e2 0.5e1 / 0.8e1; -0.7e1 / 0.8e1 0.23e2 / 0.16e2 0 -0.17e2 / 0.16e2; 0.1e1 / 0.16e2 -0.5e1 / 0.8e1 0.17e2 / 0.16e2 0;];
-    Q3(1:4,1:4)=Q3_U;
-    Q3(m-3:m,m-3:m)=rot90(  -Q3_U ,2 );
-    Q3=Q3/h^2;
-
-
-
-    S2_U=[1 -2 1;]/h^2;
-    S2_1=sparse(1,m);
-    S2_1(1:3)=S2_U;
-    S2_m=sparse(1,m);
-    S2_m(m-2:m)=fliplr(S2_U);
-    S2_1 = S2_1';
-    S2_m = S2_m';
-
-
-
-    D3=HI*(Q3 - e_1*S2_1' + e_m*S2_m' +1/2*(S_1*S_1') -1/2*(S_m*S_m') ) ;
-
-    % Fourth derivative, 0th order accurate at first 6 boundary points (still
-    % yield 4th order convergence if stable: for example u_tt=-u_xxxx
-
-    m2=1;m1=-4;m0=6;
-%     M4=m2*(diag(ones(m-2,1),2)+diag(ones(m-2,1),-2))+m1*(diag(ones(m-1,1),1)+diag(ones(m-1,1),-1))+m0*diag(ones(m,1),0);
-    stencil = [m2,m1,m0,m1,m2];
-    d = (length(stencil)-1)/2;
-    diags = -d:d;
-    M4 = stripeMatrix(stencil, diags, m);
-
-    %M4=(-1/6*(diag(ones(m-3,1),3)+diag(ones(m-3,1),-3) ) + 2*(diag(ones(m-2,1),2)+diag(ones(m-2,1),-2)) -13/2*(diag(ones(m-1,1),1)+diag(ones(m-1,1),-1)) + 28/3*diag(ones(m,1),0));
-
-    M4_U=[0.13e2 / 0.10e2 -0.12e2 / 0.5e1 0.9e1 / 0.10e2 0.1e1 / 0.5e1; -0.12e2 / 0.5e1 0.26e2 / 0.5e1 -0.16e2 / 0.5e1 0.2e1 / 0.5e1; 0.9e1 / 0.10e2 -0.16e2 / 0.5e1 0.47e2 / 0.10e2 -0.17e2 / 0.5e1; 0.1e1 / 0.5e1 0.2e1 / 0.5e1 -0.17e2 / 0.5e1 0.29e2 / 0.5e1;];
-
-
-    M4(1:4,1:4)=M4_U;
-
-    M4(m-3:m,m-3:m)=rot90(  M4_U ,2 );
-    M4=M4/h^3;
-
-    S3_U=[-1 3 -3 1;]/h^3;
-    S3_1=sparse(1,m);
-    S3_1(1:4)=S3_U;
-    S3_m=sparse(1,m);
-    S3_m(m-3:m)=fliplr(-S3_U);
-    S3_1 = S3_1';
-    S3_m = S3_m';
-
-    D4=HI*(M4-e_1*S3_1'+e_m*S3_m'  + S_1*S2_1'-S_m*S2_m');
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_compatible_halfvariable_4.m
--- a/+sbp/+implementations/d4_compatible_halfvariable_4.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,167 +0,0 @@
-function [H, HI, D2, D4, e_1, e_m, M4, S2_1, S2_m, S3_1,...
-    S3_m, S_1, S_m] = d4_compatible_halfvariable_4(m,h)
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    %%% 4:de ordn. SBP Finita differens         %%%
-    %%%                                         %%%
-    %%% H           (Normen)                    %%%
-    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
-    %%% D2          (approx andra derivatan)    %%%
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-    %m=20; %problemstorlek
-    %h=1/(m-1);
-    %h=1;
-    
-    BP = 6;
-    if(m<2*BP)
-        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
-    end
-
-%     c=ones(m,1);
-
-
-    H=speye(m,m);
-    H(1:4,1:4)=diag([17/48 59/48 43/48 49/48]);
-    H(m-3:m,m-3:m)=rot90(diag([17/48 59/48 43/48 49/48]),2);
-    H=H*h;
-    HI=inv(H);
-    HI = sparse(HI);
-
-
-
-%     Q=(-1/12*diag(ones(m-2,1),2)+8/12*diag(ones(m-1,1),1)-8/12*diag(ones(m-1,1),-1)+1/12*diag(ones(m-2,1),-2));
-      e=ones(m,1);
-%       Q=spdiags([e -8*e 0*e 8*e -e], -2:2, m, m)/12;
-%     Q_U = [0 0.59e2 / 0.96e2 -0.1e1 / 0.12e2 -0.1e1 / 0.32e2; -0.59e2 / 0.96e2 0 0.59e2 / 0.96e2 0; 0.1e1 / 0.12e2 -0.59e2 / 0.96e2 0 0.59e2 / 0.96e2; 0.1e1 / 0.32e2 0 -0.59e2 / 0.96e2 0;];
-%     Q(1:4,1:4)=Q_U;
-%     Q(m-3:m,m-3:m)=rot90( -Q_U(1:4,1:4) ,2 );
-
-    e_1=sparse(m,1);e_1(1)=1;
-    e_m=sparse(m,1);e_m(m)=1;
-
-%     D1=HI*(Q-1/2*(e_1*e_1')+1/2*(e_m*e_m')) ;
-
-    M_U=[0.9e1 / 0.8e1 -0.59e2 / 0.48e2 0.1e1 / 0.12e2 0.1e1 / 0.48e2; -0.59e2 / 0.48e2 0.59e2 / 0.24e2 -0.59e2 / 0.48e2 0; 0.1e1 / 0.12e2 -0.59e2 / 0.48e2 0.55e2 / 0.24e2 -0.59e2 / 0.48e2; 0.1e1 / 0.48e2 0 -0.59e2 / 0.48e2 0.59e2 / 0.24e2;];
-%     M=-(-1/12*diag(ones(m-2,1),2)+16/12*diag(ones(m-1,1),1)+16/12*diag(ones(m-1,1),-1)-1/12*diag(ones(m-2,1),-2)-30/12*diag(ones(m,1),0));
-    M=-spdiags([-e 16*e -30*e 16*e -e], -2:2, m, m)/12;
-
-    M(1:4,1:4)=M_U;
-
-    M(m-3:m,m-3:m)=rot90(  M_U ,2 );
-    M=M/h;
-
-    S_U=[-0.11e2 / 0.6e1 3 -0.3e1 / 0.2e1 0.1e1 / 0.3e1;]/h;
-    S_1=sparse(1,m);
-    S_1(1:4)=S_U;
-    S_m=sparse(1,m);
-    S_m(m-3:m)=fliplr(-S_U);
-    S_1 = S_1';
-    S_m = S_m';
-
-
-    M=sparse(m,m);
-    e_1 = sparse(e_1);
-    e_m = sparse(e_m);
-    S_1 = sparse(S_1);
-    S_m = sparse(S_m);
-
-
-    scheme_width = 5;
-    scheme_radius = (scheme_width-1)/2;
-    r = (1+scheme_radius):(m-scheme_radius);
-
-    function D2 = D2_fun(c)
-
-        % ALTERNATIVES %%%%%%%%%%%%%
-        % for i=4:m-3
-        %     M(i,i-2:i+2)=[-c(i-1) / 0.6e1 + c(i-2) / 0.8e1 + c(i) / 0.8e1 -c(i-2) / 0.6e1 - c(i+1) / 0.6e1 - c(i-1) / 0.2e1 - c(i) / 0.2e1 c(i-2) / 0.24e2 + 0.5e1 / 0.6e1 * c(i-1) + 0.5e1 / 0.6e1 * c(i+1) + c(i+2) / 0.24e2 + 0.3e1 / 0.4e1 * c(i) -c(i-1) / 0.6e1 - c(i+2) / 0.6e1 - c(i) / 0.2e1 - c(i+1) / 0.2e1 -c(i+1) / 0.6e1 + c(i) / 0.8e1 + c(i+2) / 0.8e1;];
-        % end
-        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-        % for i=4:m-3
-        %     M(i,i-2:i+2)= [
-        %      c(i-2) / 0.8e1 - c(i-1) / 0.6e1 + c(i)   / 0.8e1                                   ,
-        %     -c(i-2) / 0.6e1 - c(i-1) / 0.2e1 - c(i)   / 0.2e1 - c(i+1) / 0.6e1                  ,
-        %      c(i-2) / 2.4e1 + c(i-1) / 1.2e0 + c(i) * 0.3/0.4 + c(i+1) / 1.2e0 + c(i+2) / 2.4e1 ,
-        %                      -c(i-1) / 0.6e1 - c(i)   / 0.2e1 - c(i+1) / 0.2e1 - c(i+2) / 0.6e1 ,
-        %                                        c(i)   / 0.8e1 - c(i+1) / 0.6e1 + c(i+2) / 0.8e1 ,
-        %     ];
-        % end
-        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-        Mm2 =  c(r-2) / 0.8e1 - c(r-1) / 0.6e1 + c(r)   / 0.8e1                                  ;
-        Mm1 = -c(r-2) / 0.6e1 - c(r-1) / 0.2e1 - c(r)   / 0.2e1 - c(r+1) / 0.6e1                 ;
-        M0  =  c(r-2) / 2.4e1 + c(r-1) / 1.2e0 + c(r) * 0.3/0.4 + c(r+1) / 1.2e0 + c(r+2) / 2.4e1;
-        Mp1 =                  -c(r-1) / 0.6e1 - c(r)   / 0.2e1 - c(r+1) / 0.2e1 - c(r+2) / 0.6e1;
-        Mp2 =                                    c(r)   / 0.8e1 - c(r+1) / 0.6e1 + c(r+2) / 0.8e1;
-        % printSize(Mm2);
-        % scheme_radius
-        % m
-        M(r,:) = spdiags([Mm2 Mm1 M0 Mp1 Mp2],0:2*scheme_radius,length(r),m);
-        % M(r,:) = spdiags([Mm2 Mm1 M0 Mp1 Mp2],(-2:2)+scheme_radius,M(r,:)); % This is slower
-        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-        % %% Somthing is wrong here!!
-        % Mm2 =  c(r-2) / 0.8e1 - c(r-1) / 0.6e1 + c(r)   / 0.8e1                                  ;
-        % Mm1 = -c(r-2) / 0.6e1 - c(r-1) / 0.2e1 - c(r)   / 0.2e1 - c(r+1) / 0.6e1                 ;
-        % M0  =  c(r-2) / 2.4e1 + c(r-1) / 1.2e0 + c(r) * 0.3/0.4 + c(r+1) / 1.2e0 + c(r+2) / 2.4e1;
-        % Mp1 =                  -c(r-1) / 0.6e1 - c(r)   / 0.2e1 - c(r+1) / 0.2e1 - c(r+2) / 0.6e1;
-        % Mp2 =                                    c(r)   / 0.8e1 - c(r+1) / 0.6e1 + c(r+2) / 0.8e1;
-        % % printSize(M_diag_ind);
-        % % Mdiags = [Mm2 Mm1 M0  Mp1 Mp2];
-        % % printSize(Mdiags);
-        % M(M_diag_ind) = [Mm2 Mm1 M0  Mp1 Mp2]; % This is slightly faster
-        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-        % Kan man skriva det som en multiplikation av en 3-dim matris?
-        %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-
-
-        M(1:6,1:6)=[0.12e2 / 0.17e2 * c(1) + 0.59e2 / 0.192e3 * c(2) + 0.27010400129e11 / 0.345067064608e12 * c(3) + 0.69462376031e11 / 0.2070402387648e13 * c(4) -0.59e2 / 0.68e2 * c(1) - 0.6025413881e10 / 0.21126554976e11 * c(3) - 0.537416663e9 / 0.7042184992e10 * c(4) 0.2e1 / 0.17e2 * c(1) - 0.59e2 / 0.192e3 * c(2) + 0.213318005e9 / 0.16049630912e11 * c(4) + 0.2083938599e10 / 0.8024815456e10 * c(3) 0.3e1 / 0.68e2 * c(1) - 0.1244724001e10 / 0.21126554976e11 * c(3) + 0.752806667e9 / 0.21126554976e11 * c(4) 0.49579087e8 / 0.10149031312e11 * c(3) - 0.49579087e8 / 0.10149031312e11 * c(4) -c(4) / 0.784e3 + c(3) / 0.784e3; -0.59e2 / 0.68e2 * c(1) - 0.6025413881e10 / 0.21126554976e11 * c(3) - 0.537416663e9 / 0.7042184992e10 * c(4) 0.3481e4 / 0.3264e4 * c(1) + 0.9258282831623875e16 / 0.7669235228057664e16 * c(3) + 0.236024329996203e15 / 0.1278205871342944e16 * c(4) -0.59e2 / 0.408e3 * c(1) - 0.29294615794607e14 / 0.29725717938208e14 * c(3) - 0.2944673881023e13 / 0.29725717938208e14 * c(4) -0.59e2 / 0.1088e4 * c(1) + 0.260297319232891e15 / 0.2556411742685888e16 * c(3) - 0.60834186813841e14 / 0.1278205871342944e16 * c(4) -0.1328188692663e13 / 0.37594290333616e14 * c(3) + 0.1328188692663e13 / 0.37594290333616e14 * c(4) -0.8673e4 / 0.2904112e7 * c(3) + 0.8673e4 / 0.2904112e7 * c(4); 0.2e1 / 0.17e2 * c(1) - 0.59e2 / 0.192e3 * c(2) + 0.213318005e9 / 0.16049630912e11 * c(4) + 0.2083938599e10 / 0.8024815456e10 * c(3) -0.59e2 / 0.408e3 * c(1) - 0.29294615794607e14 / 0.29725717938208e14 * c(3) - 0.2944673881023e13 / 0.29725717938208e14 * c(4) c(1) / 0.51e2 + 0.59e2 / 0.192e3 * c(2) + 0.13777050223300597e17 / 0.26218083221499456e17 * c(4) + 0.564461e6 / 0.13384296e8 * c(5) + 0.378288882302546512209e21 / 0.270764341349677687456e21 * c(3) c(1) / 0.136e3 - 0.125059e6 / 0.743572e6 * c(5) - 0.4836340090442187227e19 / 0.5525802884687299744e19 * c(3) - 0.17220493277981e14 / 0.89177153814624e14 * c(4) -0.10532412077335e14 / 0.42840005263888e14 * c(4) + 0.1613976761032884305e19 / 0.7963657098519931984e19 * c(3) + 0.564461e6 / 0.4461432e7 * c(5) -0.960119e6 / 0.1280713392e10 * c(4) - 0.3391e4 / 0.6692148e7 * c(5) + 0.33235054191e11 / 0.26452850508784e14 * c(3); 0.3e1 / 0.68e2 * c(1) - 0.1244724001e10 / 0.21126554976e11 * c(3) + 0.752806667e9 / 0.21126554976e11 * c(4) -0.59e2 / 0.1088e4 * c(1) + 0.260297319232891e15 / 0.2556411742685888e16 * c(3) - 0.60834186813841e14 / 0.1278205871342944e16 * c(4) c(1) / 0.136e3 - 0.125059e6 / 0.743572e6 * c(5) - 0.4836340090442187227e19 / 0.5525802884687299744e19 * c(3) - 0.17220493277981e14 / 0.89177153814624e14 * c(4) 0.3e1 / 0.1088e4 * c(1) + 0.507284006600757858213e21 / 0.475219048083107777984e21 * c(3) + 0.1869103e7 / 0.2230716e7 * c(5) + c(6) / 0.24e2 + 0.1950062198436997e16 / 0.3834617614028832e16 * c(4) -0.4959271814984644613e19 / 0.20965546238960637264e20 * c(3) - c(6) / 0.6e1 - 0.15998714909649e14 / 0.37594290333616e14 * c(4) - 0.375177e6 / 0.743572e6 * c(5) -0.368395e6 / 0.2230716e7 * c(5) + 0.752806667e9 / 0.539854092016e12 * c(3) + 0.1063649e7 / 0.8712336e7 * c(4) + c(6) / 0.8e1; 0.49579087e8 / 0.10149031312e11 * c(3) - 0.49579087e8 / 0.10149031312e11 * c(4) -0.1328188692663e13 / 0.37594290333616e14 * c(3) + 0.1328188692663e13 / 0.37594290333616e14 * c(4) -0.10532412077335e14 / 0.42840005263888e14 * c(4) + 0.1613976761032884305e19 / 0.7963657098519931984e19 * c(3) + 0.564461e6 / 0.4461432e7 * c(5) -0.4959271814984644613e19 / 0.20965546238960637264e20 * c(3) - c(6) / 0.6e1 - 0.15998714909649e14 / 0.37594290333616e14 * c(4) - 0.375177e6 / 0.743572e6 * c(5) 0.8386761355510099813e19 / 0.128413970713633903242e21 * c(3) + 0.2224717261773437e16 / 0.2763180339520776e16 * c(4) + 0.5e1 / 0.6e1 * c(6) + c(7) / 0.24e2 + 0.280535e6 / 0.371786e6 * c(5) -0.35039615e8 / 0.213452232e9 * c(4) - c(7) / 0.6e1 - 0.13091810925e11 / 0.13226425254392e14 * c(3) - 0.1118749e7 / 0.2230716e7 * c(5) - c(6) / 0.2e1; -c(4) / 0.784e3 + c(3) / 0.784e3 -0.8673e4 / 0.2904112e7 * c(3) + 0.8673e4 / 0.2904112e7 * c(4) -0.960119e6 / 0.1280713392e10 * c(4) - 0.3391e4 / 0.6692148e7 * c(5) + 0.33235054191e11 / 0.26452850508784e14 * c(3) -0.368395e6 / 0.2230716e7 * c(5) + 0.752806667e9 / 0.539854092016e12 * c(3) + 0.1063649e7 / 0.8712336e7 * c(4) + c(6) / 0.8e1 -0.35039615e8 / 0.213452232e9 * c(4) - c(7) / 0.6e1 - 0.13091810925e11 / 0.13226425254392e14 * c(3) - 0.1118749e7 / 0.2230716e7 * c(5) - c(6) / 0.2e1 0.3290636e7 / 0.80044587e8 * c(4) + 0.5580181e7 / 0.6692148e7 * c(5) + 0.5e1 / 0.6e1 * c(7) + c(8) / 0.24e2 + 0.660204843e9 / 0.13226425254392e14 * c(3) + 0.3e1 / 0.4e1 * c(6);];
-
-        M(m-5:m,m-5:m)=[c(m-7) / 0.24e2 + 0.5e1 / 0.6e1 * c(m-6) + 0.5580181e7 / 0.6692148e7 * c(m-4) + 0.4887707739997e13 / 0.119037827289528e15 * c(m-3) + 0.3e1 / 0.4e1 * c(m-5) + 0.660204843e9 / 0.13226425254392e14 * c(m-2) + 0.660204843e9 / 0.13226425254392e14 * c(m-1) -c(m-6) / 0.6e1 - 0.1618585929605e13 / 0.9919818940794e13 * c(m-3) - c(m-5) / 0.2e1 - 0.1118749e7 / 0.2230716e7 * c(m-4) - 0.13091810925e11 / 0.13226425254392e14 * c(m-2) - 0.13091810925e11 / 0.13226425254392e14 * c(m-1) -0.368395e6 / 0.2230716e7 * c(m-4) + c(m-5) / 0.8e1 + 0.48866620889e11 / 0.404890569012e12 * c(m-3) + 0.752806667e9 / 0.539854092016e12 * c(m-2) + 0.752806667e9 / 0.539854092016e12 * c(m-1) -0.3391e4 / 0.6692148e7 * c(m-4) - 0.238797444493e12 / 0.119037827289528e15 * c(m-3) + 0.33235054191e11 / 0.26452850508784e14 * c(m-2) + 0.33235054191e11 / 0.26452850508784e14 * c(m-1) -0.8673e4 / 0.2904112e7 * c(m-2) - 0.8673e4 / 0.2904112e7 * c(m-1) + 0.8673e4 / 0.1452056e7 * c(m-3) -c(m-3) / 0.392e3 + c(m-2) / 0.784e3 + c(m-1) / 0.784e3; -c(m-6) / 0.6e1 - 0.1618585929605e13 / 0.9919818940794e13 * c(m-3) - c(m-5) / 0.2e1 - 0.1118749e7 / 0.2230716e7 * c(m-4) - 0.13091810925e11 / 0.13226425254392e14 * c(m-2) - 0.13091810925e11 / 0.13226425254392e14 * c(m-1) c(m-6) / 0.24e2 + 0.5e1 / 0.6e1 * c(m-5) + 0.3896014498639e13 / 0.4959909470397e13 * c(m-3) + 0.8386761355510099813e19 / 0.128413970713633903242e21 * c(m-2) + 0.280535e6 / 0.371786e6 * c(m-4) + 0.3360696339136261875e19 / 0.171218627618178537656e21 * c(m-1) -c(m-5) / 0.6e1 - 0.4959271814984644613e19 / 0.20965546238960637264e20 * c(m-2) - 0.375177e6 / 0.743572e6 * c(m-4) - 0.13425842714e11 / 0.33740880751e11 * c(m-3) - 0.193247108773400725e18 / 0.6988515412986879088e19 * c(m-1) -0.365281640980e12 / 0.1653303156799e13 * c(m-3) + 0.564461e6 / 0.4461432e7 * c(m-4) + 0.1613976761032884305e19 / 0.7963657098519931984e19 * c(m-2) - 0.198407225513315475e18 / 0.7963657098519931984e19 * c(m-1) -0.1328188692663e13 / 0.37594290333616e14 * c(m-2) + 0.2226377963775e13 / 0.37594290333616e14 * c(m-1) - 0.8673e4 / 0.363014e6 * c(m-3) c(m-3) / 0.49e2 + 0.49579087e8 / 0.10149031312e11 * c(m-2) - 0.256702175e9 / 0.10149031312e11 * c(m-1); -0.368395e6 / 0.2230716e7 * c(m-4) + c(m-5) / 0.8e1 + 0.48866620889e11 / 0.404890569012e12 * c(m-3) + 0.752806667e9 / 0.539854092016e12 * c(m-2) + 0.752806667e9 / 0.539854092016e12 * c(m-1) -c(m-5) / 0.6e1 - 0.4959271814984644613e19 / 0.20965546238960637264e20 * c(m-2) - 0.375177e6 / 0.743572e6 * c(m-4) - 0.13425842714e11 / 0.33740880751e11 * c(m-3) - 0.193247108773400725e18 / 0.6988515412986879088e19 * c(m-1) c(m-5) / 0.24e2 + 0.1869103e7 / 0.2230716e7 * c(m-4) + 0.507284006600757858213e21 / 0.475219048083107777984e21 * c(m-2) + 0.3e1 / 0.1088e4 * c(m) + 0.31688435395e11 / 0.67481761502e11 * c(m-3) + 0.27769176016102795561e20 / 0.712828572124661666976e21 * c(m-1) -0.125059e6 / 0.743572e6 * c(m-4) + c(m) / 0.136e3 - 0.23099342648e11 / 0.101222642253e12 * c(m-3) - 0.4836340090442187227e19 / 0.5525802884687299744e19 * c(m-2) + 0.193950157930938693e18 / 0.5525802884687299744e19 * c(m-1) 0.260297319232891e15 / 0.2556411742685888e16 * c(m-2) - 0.59e2 / 0.1088e4 * c(m) - 0.106641839640553e15 / 0.1278205871342944e16 * c(m-1) + 0.26019e5 / 0.726028e6 * c(m-3) -0.1244724001e10 / 0.21126554976e11 * c(m-2) + 0.3e1 / 0.68e2 * c(m) + 0.752806667e9 / 0.21126554976e11 * c(m-1); -0.3391e4 / 0.6692148e7 * c(m-4) - 0.238797444493e12 / 0.119037827289528e15 * c(m-3) + 0.33235054191e11 / 0.26452850508784e14 * c(m-2) + 0.33235054191e11 / 0.26452850508784e14 * c(m-1) -0.365281640980e12 / 0.1653303156799e13 * c(m-3) + 0.564461e6 / 0.4461432e7 * c(m-4) + 0.1613976761032884305e19 / 0.7963657098519931984e19 * c(m-2) - 0.198407225513315475e18 / 0.7963657098519931984e19 * c(m-1) -0.125059e6 / 0.743572e6 * c(m-4) + c(m) / 0.136e3 - 0.23099342648e11 / 0.101222642253e12 * c(m-3) - 0.4836340090442187227e19 / 0.5525802884687299744e19 * c(m-2) + 0.193950157930938693e18 / 0.5525802884687299744e19 * c(m-1) 0.564461e6 / 0.13384296e8 * c(m-4) + 0.470299699916357e15 / 0.952302618316224e15 * c(m-3) + 0.550597048646198778781e21 / 0.1624586048098066124736e22 * c(m-1) + c(m) / 0.51e2 + 0.378288882302546512209e21 / 0.270764341349677687456e21 * c(m-2) -0.59e2 / 0.408e3 * c(m) - 0.29294615794607e14 / 0.29725717938208e14 * c(m-2) - 0.2234477713167e13 / 0.29725717938208e14 * c(m-1) - 0.8673e4 / 0.363014e6 * c(m-3) -0.59e2 / 0.3136e4 * c(m-3) - 0.13249937023e11 / 0.48148892736e11 * c(m-1) + 0.2e1 / 0.17e2 * c(m) + 0.2083938599e10 / 0.8024815456e10 * c(m-2); -0.8673e4 / 0.2904112e7 * c(m-2) - 0.8673e4 / 0.2904112e7 * c(m-1) + 0.8673e4 / 0.1452056e7 * c(m-3) -0.1328188692663e13 / 0.37594290333616e14 * c(m-2) + 0.2226377963775e13 / 0.37594290333616e14 * c(m-1) - 0.8673e4 / 0.363014e6 * c(m-3) 0.260297319232891e15 / 0.2556411742685888e16 * c(m-2) - 0.59e2 / 0.1088e4 * c(m) - 0.106641839640553e15 / 0.1278205871342944e16 * c(m-1) + 0.26019e5 / 0.726028e6 * c(m-3) -0.59e2 / 0.408e3 * c(m) - 0.29294615794607e14 / 0.29725717938208e14 * c(m-2) - 0.2234477713167e13 / 0.29725717938208e14 * c(m-1) - 0.8673e4 / 0.363014e6 * c(m-3) 0.9258282831623875e16 / 0.7669235228057664e16 * c(m-2) + 0.3481e4 / 0.3264e4 * c(m) + 0.228389721191751e15 / 0.1278205871342944e16 * c(m-1) + 0.8673e4 / 0.1452056e7 * c(m-3) -0.6025413881e10 / 0.21126554976e11 * c(m-2) - 0.59e2 / 0.68e2 * c(m) - 0.537416663e9 / 0.7042184992e10 * c(m-1); -c(m-3) / 0.392e3 + c(m-2) / 0.784e3 + c(m-1) / 0.784e3 c(m-3) / 0.49e2 + 0.49579087e8 / 0.10149031312e11 * c(m-2) - 0.256702175e9 / 0.10149031312e11 * c(m-1) -0.1244724001e10 / 0.21126554976e11 * c(m-2) + 0.3e1 / 0.68e2 * c(m) + 0.752806667e9 / 0.21126554976e11 * c(m-1) -0.59e2 / 0.3136e4 * c(m-3) - 0.13249937023e11 / 0.48148892736e11 * c(m-1) + 0.2e1 / 0.17e2 * c(m) + 0.2083938599e10 / 0.8024815456e10 * c(m-2) -0.6025413881e10 / 0.21126554976e11 * c(m-2) - 0.59e2 / 0.68e2 * c(m) - 0.537416663e9 / 0.7042184992e10 * c(m-1) 0.3e1 / 0.3136e4 * c(m-3) + 0.27010400129e11 / 0.345067064608e12 * c(m-2) + 0.234566387291e12 / 0.690134129216e12 * c(m-1) + 0.12e2 / 0.17e2 * c(m);];
-
-        M=M/h;
-        D2=HI*(-M-c(1)*e_1*S_1'+c(m)*e_m*S_m');
-    end
-    D2 = @D2_fun;
-
-
-    S2_U=[2 -5 4 -1;]/h^2;
-    S2_1=sparse(1,m);
-    S2_1(1:4)=S2_U;
-    S2_m=sparse(1,m);
-    S2_m(m-3:m)=fliplr(S2_U);
-    S2_1 = S2_1';
-    S2_m = S2_m';
-
-    m3=-1/6;m2=2;m1=-13/2;m0=28/3;
-%     M4=m3*(diag(ones(m-3,1),3)+diag(ones(m-3,1),-3))+m2*(diag(ones(m-2,1),2)+diag(ones(m-2,1),-2))+m1*(diag(ones(m-1,1),1)+diag(ones(m-1,1),-1))+m0*diag(ones(m,1),0);
-    stencil = [m3,m2,m1,m0,m1,m2,m3];
-    d = (length(stencil)-1)/2;
-    diags = -d:d;
-    M4 = stripeMatrix(stencil, diags, m);
-
-    %M4=(-1/6*(diag(ones(m-3,1),3)+diag(ones(m-3,1),-3) ) + 2*(diag(ones(m-2,1),2)+diag(ones(m-2,1),-2)) -13/2*(diag(ones(m-1,1),1)+diag(ones(m-1,1),-1)) + 28/3*diag(ones(m,1),0));
-
-    M4_U=[0.5762947e7 / 0.2316384e7 -0.6374287e7 / 0.1158192e7 0.573947e6 / 0.165456e6 -0.124637e6 / 0.289548e6 0.67979e5 / 0.2316384e7 -0.60257e5 / 0.1158192e7; -0.6374287e7 / 0.1158192e7 0.30392389e8 / 0.2316384e7 -0.2735053e7 / 0.289548e6 0.273109e6 / 0.165456e6 0.83767e5 / 0.1158192e7 0.245549e6 / 0.2316384e7; 0.573947e6 / 0.165456e6 -0.2735053e7 / 0.289548e6 0.5266855e7 / 0.579096e6 -0.1099715e7 / 0.289548e6 0.869293e6 / 0.1158192e7 -0.10195e5 / 0.144774e6; -0.124637e6 / 0.289548e6 0.273109e6 / 0.165456e6 -0.1099715e7 / 0.289548e6 0.3259225e7 / 0.579096e6 -0.324229e6 / 0.72387e5 0.1847891e7 / 0.1158192e7; 0.67979e5 / 0.2316384e7 0.83767e5 / 0.1158192e7 0.869293e6 / 0.1158192e7 -0.324229e6 / 0.72387e5 0.2626501e7 / 0.330912e6 -0.7115491e7 / 0.1158192e7; -0.60257e5 / 0.1158192e7 0.245549e6 / 0.2316384e7 -0.10195e5 / 0.144774e6 0.1847891e7 / 0.1158192e7 -0.7115491e7 / 0.1158192e7 0.21383077e8 / 0.2316384e7;];
-
-    M4(1:6,1:6)=M4_U;
-
-    M4(m-5:m,m-5:m)=rot90(  M4_U ,2 );
-    M4=M4/h^3;
-
-    S3_U=[-1 3 -3 1;]/h^3;
-    S3_1=sparse(1,m);
-    S3_1(1:4)=S3_U;
-    S3_m=sparse(1,m);
-    S3_m(m-3:m)=fliplr(-S3_U);
-    S3_1 = S3_1';
-    S3_m = S3_m';
-
-    D4=HI*(M4-e_1*S3_1'+e_m*S3_m'  + S_1*S2_1'-S_m*S2_m');
-
-
-
-
-
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_compatible_halfvariable_6.m
--- a/+sbp/+implementations/d4_compatible_halfvariable_6.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-function [H, HI, D2, D4, e_1, e_m, M4, S2_1, S2_m, S3_1,...
-    S3_m, S_1, S_m] = d4_compatible_halfvariable_6(m,h)
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-    %%% 6:te ordn. SBP Finita differens         %%%
-    %%% operatorer med diagonal norm            %%%
-    %%% Extension to variable koeff             %%%
-    %%%                                         %%%
-    %%% H           (Normen)                    %%%
-    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
-    %%% D2          (approx andra derivatan)    %%%
-    %%% D2=HI*(R+C*D*S                          %%%
-    %%%                                         %%%
-    %%% R=-D1'*H*C*D1-RR                        %%%
-    %%%                                         %%%
-    %%% RR ?r dissipation)                      %%%
-    %%% Dissipationen uppbyggd av D4:           %%%
-    %%% DI=D4*B*H*D4                            %%%
-    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-    %m=10;          %problemstorlek
-    %h=1/(m-1);
-
-    % Variable koefficicients are stored in vector: c, size m,
-    % with the unknown stored as c(1), c(2), ..., c_m
-    % x=1:h:m*h;x=x';
-    % c=x.^0;
-    
-    BP = 8;
-    if(m<2*BP)
-        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
-    end
-
-
-    H=speye(m,m);
-    H(1:6,1:6)=diag([13649/43200,12013/8640,2711/4320,5359/4320,7877/8640, ...
-    		 43801/43200]);
-    H(m-5:m,m-5:m)=rot90(diag([13649/43200,12013/8640, ...
-    		    2711/4320,5359/4320,7877/8640,43801/43200]),2);
-
-
-%     x1=0.70127127127127;
-
-
-%     D1=(1/60*diag(ones(m-3,1),3)-9/60*diag(ones(m-2,1),2)+45/60*diag(ones(m-1,1),1)-45/60*diag(ones(m-1,1),-1)+9/60*diag(ones(m-2,1),-2)-1/60*diag(ones(m-3,1),-3));
-% 
-% 
-% 
-%     D1(1:6,1:9)=[-21600/13649, 43200/13649*x1-7624/40947, -172800/13649*x1+ ...
-%     	     715489/81894, 259200/13649*x1-187917/13649, -172800/13649* ...
-%     	     x1+735635/81894, 43200/13649*x1-89387/40947, 0, 0, 0; ...
-%     	     -8640/12013*x1+7624/180195, 0, 86400/12013*x1-57139/12013, ...
-%     	     -172800/12013*x1+745733/72078, 129600/12013*x1-91715/12013, ...
-%     	     -34560/12013*x1+240569/120130, 0, 0, 0; ...
-%              17280/2711*x1-715489/162660, -43200/2711*x1+57139/5422, 0, ...
-%              86400/2711*x1-176839/8133, -86400/2711*x1+242111/10844, ...
-%              25920/2711*x1-182261/27110, 0, 0, 0; ...
-%              -25920/5359*x1+187917/53590, 86400/5359*x1-745733/64308, ...
-%              -86400/5359*x1+176839/16077, 0, 43200/5359*x1-165041/32154, ...
-%              -17280/5359*x1+710473/321540, 72/5359, 0, 0; ...
-%              34560/7877*x1-147127/47262, -129600/7877*x1+91715/7877, ...
-%              172800/7877*x1-242111/15754, -86400/7877*x1+165041/23631, ...
-%              0, 8640/7877*x1, -1296/7877, 144/7877, 0; ...
-%              -43200/43801*x1+89387/131403, 172800/43801*x1-240569/87602,...
-%              -259200/43801*x1+182261/43801, 172800/43801*x1-710473/262806, ...
-%              -43200/43801*x1, 0, 32400/43801, -6480/43801, 720/43801];
-%     D1(m-5:m,m-8:m)=rot90( -D1(1:6,1:9),2);
-%     D1=D1/h;
-
-    e_1=sparse(m,1);e_1(1)=1;
-    e_m=sparse(m,1);e_m(m)=1;
-
-    S_U=[-25/12, 4, -3, 4/3, -1/4]/h;
-    S_1=sparse(1,m);
-    S_1(1:5)=S_U;
-    S_m=sparse(1,m);
-    S_m(m-4:m)=fliplr(-S_U);
-    S_1 = S_1';
-    S_m = S_m';
-
-
-
-    %DS=sparse(m,m);
-    %DS(1,1:5)=-[-25/12, 4, -3, 4/3, -1/4];
-    %DS(m,m-4:m)=fliplr(-[-25/12, 4, -3, 4/3, -1/4]);
-    %DS=diag(c)*DS/h;
-
-
-    H=h*H;
-    HI=inv(H);
-
-
-    M=sparse(m,m);
-    e_1 = sparse(e_1);
-    e_m = sparse(e_m);
-    S_1 = sparse(S_1);
-    S_m = sparse(S_m);
-
-    scheme_width = 7;
-    scheme_radius = (scheme_width-1)/2;
-    r = (1+scheme_radius):(m-scheme_radius);
-
-    function D2 = D2_fun(c)
-
-        Mm3 =  c(r-2) / 0.40e2 + c(r-1) / 0.40e2 - 0.11e2 / 0.360e3 * c(r-3) - 0.11e2 / 0.360e3 * c(r);
-        Mm2 =  c(r-3) / 0.20e2 - 0.3e1 / 0.10e2 * c(r-1) + c(r+1) / 0.20e2 + 0.7e1 / 0.40e2 * c(r) + 0.7e1 / 0.40e2 * c(r-2);
-        Mm1 = -c(r-3) / 0.40e2 - 0.3e1 / 0.10e2 * c(r-2) - 0.3e1 / 0.10e2 * c(r+1) - c(r+2) / 0.40e2 - 0.17e2 / 0.40e2 * c(r) - 0.17e2 / 0.40e2 * c(r-1);
-        M0 =  c(r-3) / 0.180e3 + c(r-2) / 0.8e1 + 0.19e2 / 0.20e2 * c(r-1) + 0.19e2 / 0.20e2 * c(r+1) + c(r+2) / 0.8e1 + c(r+3) / 0.180e3 + 0.101e3 / 0.180e3 * c(r);
-        Mp1 = -c(r-2) / 0.40e2 - 0.3e1 / 0.10e2 * c(r-1) - 0.3e1 / 0.10e2 * c(r+2) - c(r+3) / 0.40e2 - 0.17e2 / 0.40e2 * c(r) - 0.17e2 / 0.40e2 * c(r+1);
-        Mp2 =  c(r-1) / 0.20e2 - 0.3e1 / 0.10e2 * c(r+1) + c(r+3) / 0.20e2 + 0.7e1 / 0.40e2 * c(r) + 0.7e1 / 0.40e2 * c(r+2);
-        Mp3 =  c(r+1) / 0.40e2 + c(r+2) / 0.40e2 - 0.11e2 / 0.360e3 * c(r) - 0.11e2 / 0.360e3 * c(r+3);
-
-        M(r,:) = spdiags([Mm3 Mm2 Mm1 M0 Mp1 Mp2 Mp3],0:2*scheme_radius,length(r),m);
-
-
-        M(1:9,1:9)=[0.7912667594695582093926295e0 * c(1) + 0.2968472090638000742888467e0 * c(2) + 0.3185519088796429015220016e-2 * c(3) + 0.1632404042590951953384672e-1 * c(4) + 0.3160302244094415087693968e-1 * c(5) + 0.3167964748016105299646518e-1 * c(6) + 0.3148577733947253920469418e-1 * c(7) -0.1016689339350338144430605e1 * c(1) - 0.2845627370491611369031341e-1 * c(3) - 0.4128029838349298819825156e-1 * c(4) - 0.1392281451620140507549866e0 * c(5) - 0.1195777325611201766551392e0 * c(6) - 0.1194267756529333410855186e0 * c(7) 0.7075642937243715046279337e-1 * c(1) - 0.1845476106024151050283847e0 * c(2) - 0.4364163147111892346990101e-1 * c(4) + 0.2432367907207732460874765e0 * c(5) + 0.1582127073537215443965653e0 * c(6) + 0.1602348578364786307613271e0 * c(7) 0.2251991532891353212689574e0 * c(1) - 0.1662748711097054895317080e0 * c(2) + 0.2710530961648671297733465e-1 * c(3) - 0.1916646185968439909125616e0 * c(5) - 0.7684117160199014594442072e-1 * c(6) - 0.8219586949831697575883635e-1 * c(7) -0.5224403464202056316702078e-1 * c(1) + 0.4440063948509876221050939e-1 * c(2) - 0.1023976547309387874453988e-2 * c(3) + 0.7403484645316174090533193e-1 * c(4) + 0.1241625568998496895352046e-1 * c(6) + 0.7188652847892601282652228e-1 * c(5) + 0.1379362997104735503447960e-1 * c(7) -0.1828896813877197352675410e-1 * c(1) + 0.9574633163221758060736592e-2 * c(2) - 0.8105784530576404277872603e-3 * c(3) - 0.7348845587775519698437916e-2 * c(4) + 0.1063601949723906997026904e-1 * c(5) - 0.1315967038382618382356495e-1 * c(6) - 0.2117936478838753524581943e-1 * c(7) 0.1911888563316170927411831e-2 * c(4) - 0.4068130355529149936100229e-1 * c(5) + 0.1319674981073749167009902e-1 * c(6) + 0.2557266518123783676349144e-1 * c(7) 0.1559652871136785763960685e-1 * c(5) - 0.6486184157331537899459796e-2 * c(6) - 0.9110344554036319740147054e-2 * c(7) 0.5593983696629863059347067e-3 * c(6) - 0.1384822535100796372263822e-2 * c(5) + 0.8254241654378100663291154e-3 * c(7); -0.1016689339350338144430605e1 * c(1) - 0.2845627370491611369031341e-1 * c(3) - 0.4128029838349298819825156e-1 * c(4) - 0.1392281451620140507549866e0 * c(5) - 0.1195777325611201766551392e0 * c(6) - 0.1194267756529333410855186e0 * c(7) 0.1306332157111667628555907e1 * c(1) + 0.2542001760457345743492403e0 * c(3) + 0.1043897828092562609502636e0 * c(4) + 0.6672328021032112950919876e0 * c(5) + 0.4681819359722749441073885e0 * c(6) + 0.4676415410195836920069412e0 * c(7) -0.9091410269992464604926176e-1 * c(1) + 0.1103611313171476425250639e0 * c(4) - 0.1290397544997518887000350e1 * c(5) - 0.6639605248735044787146222e0 * c(6) - 0.6615974464005206184151509e0 * c(7) -0.2893557395653431666593814e0 * c(1) - 0.2421320004064592721552708e0 * c(3) + 0.1187670255028031027693374e1 * c(5) + 0.3956598149904136332753521e0 * c(6) + 0.3860048921755800000681479e0 * c(7) 0.6712774475803763988977355e-1 * c(1) + 0.9147192682075630179962131e-2 * c(3) - 0.1872196143003808021730728e0 * c(4) - 0.1319358558853174530078498e0 * c(6) - 0.4871575736811911887376923e0 * c(5) - 0.1047516312275448138054418e0 * c(7) 0.2349927974590068869356781e-1 * c(1) + 0.7240905383565181316381731e-2 * c(3) + 0.1858378996391679448655070e-1 * c(4) - 0.9289616133938676174345208e-1 * c(5) + 0.1223513270418807666970488e0 * c(6) + 0.1113520320436295033894092e0 * c(7) -0.4834791406446907590553793e-2 * c(4) + 0.2310683832687820403062715e0 * c(5) - 0.1080774142196007991746827e0 * c(6) - 0.1181561776427343335410349e0 * c(7) -0.8368141434403455353724691e-1 * c(5) + 0.4093499466767054661591066e-1 * c(6) + 0.4274641967636400692133626e-1 * c(7) -0.3576545132696983143406173e-2 * c(6) + 0.7389399124121078682094445e-2 * c(5) - 0.3812853991424095538688273e-2 * c(7); 0.7075642937243715046279337e-1 * c(1) - 0.1845476106024151050283847e0 * c(2) - 0.4364163147111892346990101e-1 * c(4) + 0.2432367907207732460874765e0 * c(5) + 0.1582127073537215443965653e0 * c(6) + 0.1602348578364786307613271e0 * c(7) -0.9091410269992464604926176e-1 * c(1) + 0.1103611313171476425250639e0 * c(4) - 0.1290397544997518887000350e1 * c(5) - 0.6639605248735044787146222e0 * c(6) - 0.6615974464005206184151509e0 * c(7) 0.6327161147136873807796515e-2 * c(1) + 0.1147318200715868527529827e0 * c(2) + 0.1166740554279680007487795e0 * c(4) + 0.2766610808285444037240703e1 * c(5) + 0.1070920689960817104203947e1 * c(6) + 0.1013161391032973057171717e1 * c(7) 0.2013769413884797246646959e-1 * c(1) + 0.1033717994630886401730470e0 * c(2) - 0.2913221621151742724258117e1 * c(5) - 0.8755807343482262259774782e0 * c(6) - 0.6909957183488812426508351e0 * c(7) -0.4671751091575462868310238e-2 * c(1) - 0.2760353365637712827793337e-1 * c(2) - 0.1979290298620869974478871e0 * c(4) + 0.5402985338373433052255418e0 * c(6) + 0.1239177593031911077924537e1 * c(5) + 0.2628038050247358227280031e0 * c(7) -0.1635430866921887819487473e-2 * c(1) - 0.5952475275883259619711594e-2 * c(2) + 0.1964682777744275219350831e-1 * c(4) + 0.3236640012639046600590714e0 * c(5) - 0.4659516693228870973898560e0 * c(6) - 0.2217272720941736859420432e0 * c(7) -0.5111353189352474549563559e-2 * c(4) - 0.5355878163774754346032096e0 * c(5) + 0.3328335104489738933610597e0 * c(6) + 0.2078656591178540157917135e0 * c(7) 0.1824328174134289562208038e0 * c(5) - 0.1059816030196818445908057e0 * c(6) - 0.7645121439374711162999809e-1 * c(7) 0.9209089963443799485648361e-2 * c(6) - 0.1591502818872493167091475e-1 * c(5) + 0.6705938225281132185266388e-2 * c(7); 0.2251991532891353212689574e0 * c(1) - 0.1662748711097054895317080e0 * c(2) + 0.2710530961648671297733465e-1 * c(3) - 0.1916646185968439909125616e0 * c(5) - 0.7684117160199014594442072e-1 * c(6) - 0.8219586949831697575883635e-1 * c(7) -0.2893557395653431666593814e0 * c(1) - 0.2421320004064592721552708e0 * c(3) + 0.1187670255028031027693374e1 * c(5) + 0.3956598149904136332753521e0 * c(6) + 0.3860048921755800000681479e0 * c(7) 0.2013769413884797246646959e-1 * c(1) + 0.1033717994630886401730470e0 * c(2) - 0.2913221621151742724258117e1 * c(5) - 0.8755807343482262259774782e0 * c(6) - 0.6909957183488812426508351e0 * c(7) 0.6409299775987186986730499e-1 * c(1) + 0.9313657638804699948929701e-1 * c(2) + 0.2306367624634749229113646e0 * c(3) + 0.3689440308283716620260816e1 * c(5) + 0.1190550338687608873798462e1 * c(6) + 0.5912479546888856519443605e0 * c(7) -0.1486895819265604128572498e-1 * c(1) - 0.2487040599390160764166412e-1 * c(2) - 0.8712928907711754187084757e-2 * c(3) - 0.1263507837371824205693950e1 * c(6) - 0.3058317397843997326920898e0 * c(7) - 0.1470691926045802954795783e1 * c(5) -0.5205147429855955657625694e-2 * c(1) - 0.5363098747528542488971874e-2 * c(2) - 0.6897142765790609546343709e-2 * c(3) - 0.7857524521667450101721993e0 * c(5) + 0.2291148005423734600066709e0 * c(7) + 0.9977064356292750529201981e0 * c(6) 0.6697297488067662265210608e0 * c(5) - 0.5013247356072127938999311e0 * c(6) - 0.1795161243106645437322408e0 * c(7) -0.2022909060111751565150958e0 * c(5) + 0.1453421858063658498587377e0 * c(6) + 0.5694872020480930665635812e-1 * c(7) -0.1200429618441003833696998e-1 * c(6) - 0.4776915669385923841535432e-2 * c(7) + 0.1678121185379596217850541e-1 * c(5); -0.5224403464202056316702078e-1 * c(1) + 0.4440063948509876221050939e-1 * c(2) - 0.1023976547309387874453988e-2 * c(3) + 0.7403484645316174090533193e-1 * c(4) + 0.1241625568998496895352046e-1 * c(6) + 0.7188652847892601282652228e-1 * c(5) + 0.1379362997104735503447960e-1 * c(7) 0.6712774475803763988977355e-1 * c(1) + 0.9147192682075630179962131e-2 * c(3) - 0.1872196143003808021730728e0 * c(4) - 0.1319358558853174530078498e0 * c(6) - 0.4871575736811911887376923e0 * c(5) - 0.1047516312275448138054418e0 * c(7) -0.4671751091575462868310238e-2 * c(1) - 0.2760353365637712827793337e-1 * c(2) - 0.1979290298620869974478871e0 * c(4) + 0.5402985338373433052255418e0 * c(6) + 0.1239177593031911077924537e1 * c(5) + 0.2628038050247358227280031e0 * c(7) -0.1486895819265604128572498e-1 * c(1) - 0.2487040599390160764166412e-1 * c(2) - 0.8712928907711754187084757e-2 * c(3) - 0.1263507837371824205693950e1 * c(6) - 0.3058317397843997326920898e0 * c(7) - 0.1470691926045802954795783e1 * c(5) 0.3449455095910233625229891e-2 * c(1) + 0.6641183499427826101618457e-2 * c(2) + 0.3291545083271862858501887e-3 * c(3) + 0.3357721707576477199985656e0 * c(4) + 0.2096413329579026439044119e1 * c(6) + 0.2317323204183126854954203e0 * c(7) + 0.6107825764368264576481962e-2 * c(8) + 0.7109125850683376695640722e0 * c(5) 0.1207544072304193806052558e-2 * c(1) + 0.1432116665752147607469646e-2 * c(2) + 0.2605582646183255957264249e-3 * c(3) - 0.3332941113251635390801278e-1 * c(4) - 0.2808241697385532683612407e0 * c(7) - 0.2720908083525083608370563e-1 * c(8) + 0.1045865435682921987447929e0 * c(5) - 0.1348436986667115543203552e1 * c(6) 0.8671038084174692625075159e-2 * c(4) + 0.1736073411355428563685818e0 * c(6) + 0.5331362125287625412555844e-1 * c(8) - 0.2424935262404526301801157e0 * c(5) + 0.1569015257678588270609004e0 * c(7) -0.8631683980217122275970376e-1 * c(6) + 0.2698842360470999243492629e-1 * c(7) + 0.8098194147715651085292754e-1 * c(5) - 0.3276463639080639163926118e-1 * c(8) 0.7462059484530855073291365e-2 * c(6) - 0.8121640361668678949573496e-3 * c(7) + 0.5522702088127090209264064e-3 * c(8) - 0.7202165657176696199260422e-2 * c(5); -0.1828896813877197352675410e-1 * c(1) + 0.9574633163221758060736592e-2 * c(2) - 0.8105784530576404277872603e-3 * c(3) - 0.7348845587775519698437916e-2 * c(4) + 0.1063601949723906997026904e-1 * c(5) - 0.1315967038382618382356495e-1 * c(6) - 0.2117936478838753524581943e-1 * c(7) 0.2349927974590068869356781e-1 * c(1) + 0.7240905383565181316381731e-2 * c(3) + 0.1858378996391679448655070e-1 * c(4) - 0.9289616133938676174345208e-1 * c(5) + 0.1223513270418807666970488e0 * c(6) + 0.1113520320436295033894092e0 * c(7) -0.1635430866921887819487473e-2 * c(1) - 0.5952475275883259619711594e-2 * c(2) + 0.1964682777744275219350831e-1 * c(4) + 0.3236640012639046600590714e0 * c(5) - 0.4659516693228870973898560e0 * c(6) - 0.2217272720941736859420432e0 * c(7) -0.5205147429855955657625694e-2 * c(1) - 0.5363098747528542488971874e-2 * c(2) - 0.6897142765790609546343709e-2 * c(3) - 0.7857524521667450101721993e0 * c(5) + 0.2291148005423734600066709e0 * c(7) + 0.9977064356292750529201981e0 * c(6) 0.1207544072304193806052558e-2 * c(1) + 0.1432116665752147607469646e-2 * c(2) + 0.2605582646183255957264249e-3 * c(3) - 0.3332941113251635390801278e-1 * c(4) - 0.2808241697385532683612407e0 * c(7) - 0.2720908083525083608370563e-1 * c(8) + 0.1045865435682921987447929e0 * c(5) - 0.1348436986667115543203552e1 * c(6) 0.4227226173449345042468960e-3 * c(1) + 0.3088241944378964404772302e-3 * c(2) + 0.2062575706647430620228133e-3 * c(3) + 0.3308343404200968256656458e-2 * c(4) + 0.5828047016405001815804837e0 * c(5) + 0.8054174220366215473556835e0 * c(7) + 0.1338363233410033443348225e0 * c(8) + 0.5555555555555555555555556e-2 * c(9) + 0.1190362071861893051132274e1 * c(6) -0.8607044252686413302647675e-3 * c(4) - 0.1748074708673904989293256e0 * c(5) - 0.3132544850115050165022338e0 * c(8) - 0.2500000000000000000000000e-1 * c(9) - 0.3169166305310429271303167e0 * c(7) - 0.6691607091647929161078591e0 * c(6) 0.3354661791693352108660900e-1 * c(5) - 0.3343620022386971405018586e0 * c(7) + 0.5000000000000000000000000e-1 * c(9) + 0.2169790609807602750804271e0 * c(6) + 0.1838363233410033443348225e0 * c(8) 0.2912518476823004642951502e-1 * c(7) + 0.2279091916474916391629437e-1 * c(8) - 0.3068985997518740530511593e-1 * c(6) - 0.1781799513347360596249022e-2 * c(5) - 0.3055555555555555555555556e-1 * c(9); 0.1911888563316170927411831e-2 * c(4) - 0.4068130355529149936100229e-1 * c(5) + 0.1319674981073749167009902e-1 * c(6) + 0.2557266518123783676349144e-1 * c(7) -0.4834791406446907590553793e-2 * c(4) + 0.2310683832687820403062715e0 * c(5) - 0.1080774142196007991746827e0 * c(6) - 0.1181561776427343335410349e0 * c(7) -0.5111353189352474549563559e-2 * c(4) - 0.5355878163774754346032096e0 * c(5) + 0.3328335104489738933610597e0 * c(6) + 0.2078656591178540157917135e0 * c(7) 0.6697297488067662265210608e0 * c(5) - 0.5013247356072127938999311e0 * c(6) - 0.1795161243106645437322408e0 * c(7) 0.8671038084174692625075159e-2 * c(4) + 0.1736073411355428563685818e0 * c(6) + 0.5331362125287625412555844e-1 * c(8) - 0.2424935262404526301801157e0 * c(5) + 0.1569015257678588270609004e0 * c(7) -0.8607044252686413302647675e-3 * c(4) - 0.1748074708673904989293256e0 * c(5) - 0.3132544850115050165022338e0 * c(8) - 0.2500000000000000000000000e-1 * c(9) - 0.3169166305310429271303167e0 * c(7) - 0.6691607091647929161078591e0 * c(6) 0.2239223735771599178951297e-3 * c(4) + 0.1275437785430956673825710e0 * c(5) + 0.1011699483929608164601067e1 * c(6) + 0.9698817275172575247533506e0 * c(8) + 0.1250000000000000000000000e0 * c(9) + 0.5555555555555555555555556e-2 * c(10) + 0.4823177543031281500117826e0 * c(7) -0.3784113973033012949863031e-1 * c(5) - 0.2997556885134827361576001e0 * c(6) - 0.3000000000000000000000000e0 * c(9) - 0.2500000000000000000000000e-1 * c(10) - 0.3991486867446821178415359e0 * c(7) - 0.4382544850115050165022338e0 * c(8) 0.4698146218022683933926520e-1 * c(6) - 0.2966863787471237458744416e0 * c(8) + 0.5000000000000000000000000e-1 * c(10) + 0.1716355704146006481727960e0 * c(7) + 0.3069346152296258362380356e-2 * c(5) + 0.1750000000000000000000000e0 * c(9); 0.1559652871136785763960685e-1 * c(5) - 0.6486184157331537899459796e-2 * c(6) - 0.9110344554036319740147054e-2 * c(7) -0.8368141434403455353724691e-1 * c(5) + 0.4093499466767054661591066e-1 * c(6) + 0.4274641967636400692133626e-1 * c(7) 0.1824328174134289562208038e0 * c(5) - 0.1059816030196818445908057e0 * c(6) - 0.7645121439374711162999809e-1 * c(7) -0.2022909060111751565150958e0 * c(5) + 0.1453421858063658498587377e0 * c(6) + 0.5694872020480930665635812e-1 * c(7) -0.8631683980217122275970376e-1 * c(6) + 0.2698842360470999243492629e-1 * c(7) + 0.8098194147715651085292754e-1 * c(5) - 0.3276463639080639163926118e-1 * c(8) 0.3354661791693352108660900e-1 * c(5) - 0.3343620022386971405018586e0 * c(7) + 0.5000000000000000000000000e-1 * c(9) + 0.2169790609807602750804271e0 * c(6) + 0.1838363233410033443348225e0 * c(8) -0.3784113973033012949863031e-1 * c(5) - 0.2997556885134827361576001e0 * c(6) - 0.3000000000000000000000000e0 * c(9) - 0.2500000000000000000000000e-1 * c(10) - 0.3991486867446821178415359e0 * c(7) - 0.4382544850115050165022338e0 * c(8) 0.1230328942716804455358698e-1 * c(5) + 0.1183647529645898332481833e0 * c(6) + 0.9410511898227943334189628e0 * c(7) + 0.9500000000000000000000000e0 * c(9) + 0.1250000000000000000000000e0 * c(10) + 0.5555555555555555555555556e-2 * c(11) + 0.5699474344521144554459336e0 * c(8) -0.2308067892671916339568942e-1 * c(6) - 0.2986625053775149497180439e0 * c(7) - 0.3000000000000000000000000e0 * c(10) - 0.2500000000000000000000000e-1 * c(11) - 0.1047734860515050802561078e-2 * c(5) - 0.4272090808352508360837056e0 * c(8) - 0.4250000000000000000000000e0 * c(9); 0.5593983696629863059347067e-3 * c(6) - 0.1384822535100796372263822e-2 * c(5) + 0.8254241654378100663291154e-3 * c(7) -0.3576545132696983143406173e-2 * c(6) + 0.7389399124121078682094445e-2 * c(5) - 0.3812853991424095538688273e-2 * c(7) 0.9209089963443799485648361e-2 * c(6) - 0.1591502818872493167091475e-1 * c(5) + 0.6705938225281132185266388e-2 * c(7) -0.1200429618441003833696998e-1 * c(6) - 0.4776915669385923841535432e-2 * c(7) + 0.1678121185379596217850541e-1 * c(5) 0.7462059484530855073291365e-2 * c(6) - 0.8121640361668678949573496e-3 * c(7) + 0.5522702088127090209264064e-3 * c(8) - 0.7202165657176696199260422e-2 * c(5) 0.2912518476823004642951502e-1 * c(7) + 0.2279091916474916391629437e-1 * c(8) - 0.3068985997518740530511593e-1 * c(6) - 0.1781799513347360596249022e-2 * c(5) - 0.3055555555555555555555556e-1 * c(9) 0.4698146218022683933926520e-1 * c(6) - 0.2966863787471237458744416e0 * c(8) + 0.5000000000000000000000000e-1 * c(10) + 0.1716355704146006481727960e0 * c(7) + 0.3069346152296258362380356e-2 * c(5) + 0.1750000000000000000000000e0 * c(9) -0.2308067892671916339568942e-1 * c(6) - 0.2986625053775149497180439e0 * c(7) - 0.3000000000000000000000000e0 * c(10) - 0.2500000000000000000000000e-1 * c(11) - 0.1047734860515050802561078e-2 * c(5) - 0.4272090808352508360837056e0 * c(8) - 0.4250000000000000000000000e0 * c(9) 0.5139370221149109977041877e-2 * c(6) + 0.1247723215009422001393184e0 * c(7) + 0.9505522702088127090209264e0 * c(8) + 0.9500000000000000000000000e0 * c(10) + 0.1250000000000000000000000e0 * c(11) + 0.5555555555555555555555556e-2 * c(12) + 0.9159362465153641826887659e-4 * c(5) + 0.5611111111111111111111111e0 * c(9);];
-
-        M(m-8:m,m-8:m)=[0.5555555555555555555555556e-2 * c(m-11) + 0.1250000000000000000000000e0 * c(m-10) + 0.9500000000000000000000000e0 * c(m-9) + 0.9505522702088127090209264e0 * c(m-7) + 0.1247205076844361998744053e0 * c(m-6) + 0.5139370221149109977041877e-2 * c(m-5) + 0.5611111111111111111111111e0 * c(m-8) + 0.1434074411575366831819799e-3 * c(m-4) -0.2500000000000000000000000e-1 * c(m-10) - 0.3000000000000000000000000e0 * c(m-9) - 0.2980649679116425253322056e0 * c(m-6) - 0.2308067892671916339568942e-1 * c(m-5) - 0.4250000000000000000000000e0 * c(m-8) - 0.4272090808352508360837056e0 * c(m-7) - 0.1645272326387475188399322e-2 * c(m-4) 0.5000000000000000000000000e-1 * c(m-9) - 0.2966863787471237458744416e0 * c(m-7) + 0.4698146218022683933926520e-1 * c(m-5) + 0.1750000000000000000000000e0 * c(m-8) + 0.1700291833903489463825077e0 * c(m-6) + 0.4675733176547960152668626e-2 * c(m-4) 0.2279091916474916391629437e-1 * c(m-7) + 0.3097763128598982561225538e-1 * c(m-6) - 0.3055555555555555555555556e-1 * c(m-8) - 0.3068985997518740530511593e-1 * c(m-5) - 0.3634246031107139778989373e-2 * c(m-4) 0.5522702088127090209264064e-3 * c(m-7) - 0.3265435411305071914756373e-2 * c(m-6) + 0.7462059484530855073291365e-2 * c(m-5) - 0.4748894282038492179461399e-2 * c(m-4) 0.6272075574042975468177820e-3 * c(m-6) - 0.1200429618441003833696998e-1 * c(m-5) + 0.1137708862700574079015220e-1 * c(m-4) 0.9209089963443799485648361e-2 * c(m-5) - 0.3129629392354775191148163e-3 * c(m-6) - 0.8896127024208321966533544e-2 * c(m-4) -0.3576545132696983143406173e-2 * c(m-5) + 0.4335019854436220306755673e-3 * c(m-6) + 0.3143043147253361112730605e-2 * c(m-4) 0.5593983696629863059347067e-3 * c(m-5) - 0.1446656414398166805849327e-3 * c(m-6) - 0.4147327282231696253497740e-3 * c(m-4); -0.2500000000000000000000000e-1 * c(m-10) - 0.3000000000000000000000000e0 * c(m-9) - 0.2980649679116425253322056e0 * c(m-6) - 0.2308067892671916339568942e-1 * c(m-5) - 0.4250000000000000000000000e0 * c(m-8) - 0.4272090808352508360837056e0 * c(m-7) - 0.1645272326387475188399322e-2 * c(m-4) 0.5555555555555555555555556e-2 * c(m-10) + 0.1250000000000000000000000e0 * c(m-9) + 0.9500000000000000000000000e0 * c(m-8) + 0.9341601509609901526962449e0 * c(m-6) + 0.1183647529645898332481833e0 * c(m-5) + 0.1919432828897222527630486e-1 * c(m-4) + 0.5699474344521144554459336e0 * c(m-7) -0.2500000000000000000000000e-1 * c(m-9) - 0.3000000000000000000000000e0 * c(m-8) - 0.2997556885134827361576001e0 * c(m-5) - 0.5636663150858098975790317e-1 * c(m-4) - 0.4382544850115050165022338e0 * c(m-7) - 0.3806231949664312575822630e0 * c(m-6) 0.5000000000000000000000000e-1 * c(m-8) - 0.3557251496099816106154206e0 * c(m-6) + 0.5490976528821799120017102e-1 * c(m-4) + 0.1838363233410033443348225e0 * c(m-7) + 0.2169790609807602750804271e0 * c(m-5) 0.5528052133944605740009217e-1 * c(m-6) - 0.8631683980217122275970376e-1 * c(m-5) - 0.3276463639080639163926118e-1 * c(m-7) + 0.5268984374242044588776166e-1 * c(m-4) -0.5373770512016897565958305e-2 * c(m-6) + 0.1453421858063658498587377e0 * c(m-5) - 0.1399684152943489522927794e0 * c(m-4) -0.1059816030196818445908057e0 * c(m-5) + 0.1014880675788250237247178e0 * c(m-4) + 0.4493535440856820866087846e-2 * c(m-6) 0.4093499466767054661591066e-1 * c(m-5) - 0.3471075437892810033585296e-1 * c(m-4) - 0.6224240288742446280057699e-2 * c(m-6) -0.6486184157331537899459796e-2 * c(m-5) + 0.4409068609809831485979484e-2 * c(m-4) + 0.2077115547521706413480312e-2 * c(m-6); 0.5000000000000000000000000e-1 * c(m-9) - 0.2966863787471237458744416e0 * c(m-7) + 0.4698146218022683933926520e-1 * c(m-5) + 0.1750000000000000000000000e0 * c(m-8) + 0.1700291833903489463825077e0 * c(m-6) + 0.4675733176547960152668626e-2 * c(m-4) -0.2500000000000000000000000e-1 * c(m-9) - 0.3000000000000000000000000e0 * c(m-8) - 0.2997556885134827361576001e0 * c(m-5) - 0.5636663150858098975790317e-1 * c(m-4) - 0.4382544850115050165022338e0 * c(m-7) - 0.3806231949664312575822630e0 * c(m-6) 0.5555555555555555555555556e-2 * c(m-9) + 0.1250000000000000000000000e0 * c(m-8) + 0.9698817275172575247533506e0 * c(m-7) + 0.1011699483929608164601067e1 * c(m-5) + 0.1773466968705924819112984e0 * c(m-4) + 0.2239223735771599178951297e-3 * c(m-3) + 0.4325148359756313354830552e0 * c(m-6) -0.2500000000000000000000000e-1 * c(m-8) - 0.3132544850115050165022338e0 * c(m-7) - 0.2322389872063761557916742e0 * c(m-4) - 0.8607044252686413302647675e-3 * c(m-3) - 0.2594851141920572702679681e0 * c(m-6) - 0.6691607091647929161078591e0 * c(m-5) 0.5331362125287625412555844e-1 * c(m-7) + 0.1736073411355428563685818e0 * c(m-5) + 0.8671038084174692625075159e-2 * c(m-3) + 0.8084259844422177692569663e-1 * c(m-6) - 0.1664345989168155800449120e0 * c(m-4) -0.5013247356072127938999311e0 * c(m-5) + 0.5021853752328231128475915e0 * c(m-4) - 0.1197175073672143005877150e-1 * c(m-6) 0.3328335104489738933610597e0 * c(m-5) - 0.3179803804558436283847901e0 * c(m-4) - 0.5111353189352474549563559e-2 * c(m-3) - 0.9741776803777790426705996e-2 * c(m-6) -0.1080774142196007991746827e0 * c(m-5) + 0.9941834083648937298100811e-1 * c(m-4) - 0.4834791406446907590553793e-2 * c(m-3) + 0.1349386478955833378422842e-1 * c(m-6) 0.1319674981073749167009902e-1 * c(m-5) - 0.1060554802883657391328704e-1 * c(m-4) + 0.1911888563316170927411831e-2 * c(m-3) - 0.4503090345217088684223814e-2 * c(m-6); 0.2279091916474916391629437e-1 * c(m-7) + 0.3097763128598982561225538e-1 * c(m-6) - 0.3055555555555555555555556e-1 * c(m-8) - 0.3068985997518740530511593e-1 * c(m-5) - 0.3634246031107139778989373e-2 * c(m-4) 0.5000000000000000000000000e-1 * c(m-8) - 0.3557251496099816106154206e0 * c(m-6) + 0.5490976528821799120017102e-1 * c(m-4) + 0.1838363233410033443348225e0 * c(m-7) + 0.2169790609807602750804271e0 * c(m-5) -0.2500000000000000000000000e-1 * c(m-8) - 0.3132544850115050165022338e0 * c(m-7) - 0.2322389872063761557916742e0 * c(m-4) - 0.8607044252686413302647675e-3 * c(m-3) - 0.2594851141920572702679681e0 * c(m-6) - 0.6691607091647929161078591e0 * c(m-5) 0.5555555555555555555555556e-2 * c(m-8) + 0.1338363233410033443348225e0 * c(m-7) + 0.7391887916719206077121040e0 * c(m-6) + 0.6490333320052011212240632e0 * c(m-4) + 0.3308343404200968256656458e-2 * c(m-3) + 0.2062575706647430620228133e-3 * c(m-2) + 0.3088241944378964404772302e-3 * c(m-1) + 0.4227226173449345042468960e-3 * c(m) + 0.1190362071861893051132274e1 * c(m-5) -0.2720908083525083608370563e-1 * c(m-7) - 0.1931148612480615118957263e0 * c(m-6) - 0.3332941113251635390801278e-1 * c(m-3) + 0.2605582646183255957264249e-3 * c(m-2) + 0.1432116665752147607469646e-2 * c(m-1) + 0.1207544072304193806052558e-2 * c(m) - 0.1348436986667115543203552e1 * c(m-5) + 0.1687723507780044227927853e-1 * c(m-4) 0.3590669644811151307464697e-1 * c(m-6) - 0.5925443480724830632401754e0 * c(m-4) - 0.6897142765790609546343709e-2 * c(m-2) - 0.5363098747528542488971874e-2 * c(m-1) - 0.5205147429855955657625694e-2 * c(m) + 0.9977064356292750529201981e0 * c(m-5) 0.7272438906214475928744770e-1 * c(m-4) + 0.1964682777744275219350831e-1 * c(m-3) - 0.5952475275883259619711594e-2 * c(m-1) - 0.1635430866921887819487473e-2 * c(m) + 0.2921234010758621482958052e-1 * c(m-6) - 0.4659516693228870973898560e0 * c(m-5) 0.5891947149681041048896399e-1 * c(m-4) + 0.1858378996391679448655070e-1 * c(m-3) + 0.7240905383565181316381731e-2 * c(m-2) + 0.2349927974590068869356781e-1 * c(m) - 0.4046360079256766884300687e-1 * c(m-6) + 0.1223513270418807666970488e0 * c(m-5) -0.2404661162020836566908542e-1 * c(m-4) - 0.7348845587775519698437916e-2 * c(m-3) - 0.8105784530576404277872603e-3 * c(m-2) + 0.9574633163221758060736592e-2 * c(m-1) - 0.1828896813877197352675410e-1 * c(m) + 0.1350326632905990039353503e-1 * c(m-6) - 0.1315967038382618382356495e-1 * c(m-5); 0.5522702088127090209264064e-3 * c(m-7) - 0.3265435411305071914756373e-2 * c(m-6) + 0.7462059484530855073291365e-2 * c(m-5) - 0.4748894282038492179461399e-2 * c(m-4) 0.5528052133944605740009217e-1 * c(m-6) - 0.8631683980217122275970376e-1 * c(m-5) - 0.3276463639080639163926118e-1 * c(m-7) + 0.5268984374242044588776166e-1 * c(m-4) 0.5331362125287625412555844e-1 * c(m-7) + 0.1736073411355428563685818e0 * c(m-5) + 0.8671038084174692625075159e-2 * c(m-3) + 0.8084259844422177692569663e-1 * c(m-6) - 0.1664345989168155800449120e0 * c(m-4) -0.2720908083525083608370563e-1 * c(m-7) - 0.1931148612480615118957263e0 * c(m-6) - 0.3332941113251635390801278e-1 * c(m-3) + 0.2605582646183255957264249e-3 * c(m-2) + 0.1432116665752147607469646e-2 * c(m-1) + 0.1207544072304193806052558e-2 * c(m) - 0.1348436986667115543203552e1 * c(m-5) + 0.1687723507780044227927853e-1 * c(m-4) 0.6107825764368264576481962e-2 * c(m-7) + 0.1155752633643216628010304e0 * c(m-6) + 0.2096413329579026439044119e1 * c(m-5) + 0.3357721707576477199985656e0 * c(m-3) + 0.3291545083271862858501887e-3 * c(m-2) + 0.6641183499427826101618457e-2 * c(m-1) + 0.3449455095910233625229891e-2 * c(m) + 0.8270696421223286922584620e0 * c(m-4) -0.4995827370863505253765970e-1 * c(m-6) - 0.1263507837371824205693950e1 * c(m-5) - 0.8712928907711754187084757e-2 * c(m-2) - 0.2487040599390160764166412e-1 * c(m-1) - 0.1486895819265604128572498e-1 * c(m) - 0.1726565392121567634950213e1 * c(m-4) 0.5402985338373433052255418e0 * c(m-5) - 0.1979290298620869974478871e0 * c(m-3) - 0.2760353365637712827793337e-1 * c(m-1) - 0.4671751091575462868310238e-2 * c(m) - 0.6952587985456154591014641e-1 * c(m-6) + 0.1571507277911208446562686e1 * c(m-4) -0.1319358558853174530078498e0 * c(m-5) - 0.1872196143003808021730728e0 * c(m-3) + 0.9147192682075630179962131e-2 * c(m-2) + 0.6712774475803763988977355e-1 * c(m) + 0.9630407686703666967100804e-1 * c(m-6) - 0.6882132817757726722141421e0 * c(m-4) 0.1241625568998496895352046e-1 * c(m-5) + 0.7403484645316174090533193e-1 * c(m-3) - 0.1023976547309387874453988e-2 * c(m-2) + 0.4440063948509876221050939e-1 * c(m-1) - 0.5224403464202056316702078e-1 * c(m) - 0.3213800979246298453953842e-1 * c(m-6) + 0.1178181682424363524005403e0 * c(m-4); 0.6272075574042975468177820e-3 * c(m-6) - 0.1200429618441003833696998e-1 * c(m-5) + 0.1137708862700574079015220e-1 * c(m-4) -0.5373770512016897565958305e-2 * c(m-6) + 0.1453421858063658498587377e0 * c(m-5) - 0.1399684152943489522927794e0 * c(m-4) -0.5013247356072127938999311e0 * c(m-5) + 0.5021853752328231128475915e0 * c(m-4) - 0.1197175073672143005877150e-1 * c(m-6) 0.3590669644811151307464697e-1 * c(m-6) - 0.5925443480724830632401754e0 * c(m-4) - 0.6897142765790609546343709e-2 * c(m-2) - 0.5363098747528542488971874e-2 * c(m-1) - 0.5205147429855955657625694e-2 * c(m) + 0.9977064356292750529201981e0 * c(m-5) -0.4995827370863505253765970e-1 * c(m-6) - 0.1263507837371824205693950e1 * c(m-5) - 0.8712928907711754187084757e-2 * c(m-2) - 0.2487040599390160764166412e-1 * c(m-1) - 0.1486895819265604128572498e-1 * c(m) - 0.1726565392121567634950213e1 * c(m-4) 0.2760393423824887721078848e-1 * c(m-6) + 0.1190550338687608873798462e1 * c(m-5) + 0.4253084328734353394994388e1 * c(m-4) + 0.2306367624634749229113646e0 * c(m-2) + 0.9313657638804699948929701e-1 * c(m-1) + 0.6409299775987186986730499e-1 * c(m) -0.8755807343482262259774782e0 * c(m-5) - 0.3645285178085761821545207e1 * c(m-4) + 0.1033717994630886401730470e0 * c(m-1) + 0.2013769413884797246646959e-1 * c(m) + 0.4106783858513785463625543e-1 * c(m-6) 0.3956598149904136332753521e0 * c(m-5) + 0.1630560443616104907615866e1 * c(m-4) - 0.2421320004064592721552708e0 * c(m-2) - 0.2893557395653431666593814e0 * c(m) - 0.5688529641249387985434413e-1 * c(m-6) -0.7684117160199014594442072e-1 * c(m-5) - 0.2928439026361256842196229e0 * c(m-4) + 0.2710530961648671297733465e-1 * c(m-2) - 0.1662748711097054895317080e0 * c(m-1) + 0.2251991532891353212689574e0 * c(m) + 0.1898341454096471754822498e-1 * c(m-6); 0.9209089963443799485648361e-2 * c(m-5) - 0.3129629392354775191148163e-3 * c(m-6) - 0.8896127024208321966533544e-2 * c(m-4) -0.1059816030196818445908057e0 * c(m-5) + 0.1014880675788250237247178e0 * c(m-4) + 0.4493535440856820866087846e-2 * c(m-6) 0.3328335104489738933610597e0 * c(m-5) - 0.3179803804558436283847901e0 * c(m-4) - 0.5111353189352474549563559e-2 * c(m-3) - 0.9741776803777790426705996e-2 * c(m-6) 0.7272438906214475928744770e-1 * c(m-4) + 0.1964682777744275219350831e-1 * c(m-3) - 0.5952475275883259619711594e-2 * c(m-1) - 0.1635430866921887819487473e-2 * c(m) + 0.2921234010758621482958052e-1 * c(m-6) - 0.4659516693228870973898560e0 * c(m-5) 0.5402985338373433052255418e0 * c(m-5) - 0.1979290298620869974478871e0 * c(m-3) - 0.2760353365637712827793337e-1 * c(m-1) - 0.4671751091575462868310238e-2 * c(m) - 0.6952587985456154591014641e-1 * c(m-6) + 0.1571507277911208446562686e1 * c(m-4) -0.8755807343482262259774782e0 * c(m-5) - 0.3645285178085761821545207e1 * c(m-4) + 0.1033717994630886401730470e0 * c(m-1) + 0.2013769413884797246646959e-1 * c(m) + 0.4106783858513785463625543e-1 * c(m-6) 0.1070920689960817104203947e1 * c(m-5) + 0.3717418466925056542408153e1 * c(m-4) + 0.1166740554279680007487795e0 * c(m-3) + 0.1147318200715868527529827e0 * c(m-1) + 0.6327161147136873807796515e-2 * c(m) + 0.6235373239336055200426697e-1 * c(m-6) -0.6639605248735044787146222e0 * c(m-5) - 0.1865625445986772763641423e1 * c(m-4) + 0.1103611313171476425250639e0 * c(m-3) - 0.9091410269992464604926176e-1 * c(m) - 0.8636954541126674177407762e-1 * c(m-6) 0.1582127073537215443965653e0 * c(m-5) + 0.3746489300753517635549495e0 * c(m-4) - 0.4364163147111892346990101e-1 * c(m-3) - 0.1845476106024151050283847e0 * c(m-1) + 0.7075642937243715046279337e-1 * c(m) + 0.2882271848190011329385407e-1 * c(m-6); -0.3576545132696983143406173e-2 * c(m-5) + 0.4335019854436220306755673e-3 * c(m-6) + 0.3143043147253361112730605e-2 * c(m-4) 0.4093499466767054661591066e-1 * c(m-5) - 0.3471075437892810033585296e-1 * c(m-4) - 0.6224240288742446280057699e-2 * c(m-6) -0.1080774142196007991746827e0 * c(m-5) + 0.9941834083648937298100811e-1 * c(m-4) - 0.4834791406446907590553793e-2 * c(m-3) + 0.1349386478955833378422842e-1 * c(m-6) 0.5891947149681041048896399e-1 * c(m-4) + 0.1858378996391679448655070e-1 * c(m-3) + 0.7240905383565181316381731e-2 * c(m-2) + 0.2349927974590068869356781e-1 * c(m) - 0.4046360079256766884300687e-1 * c(m-6) + 0.1223513270418807666970488e0 * c(m-5) -0.1319358558853174530078498e0 * c(m-5) - 0.1872196143003808021730728e0 * c(m-3) + 0.9147192682075630179962131e-2 * c(m-2) + 0.6712774475803763988977355e-1 * c(m) + 0.9630407686703666967100804e-1 * c(m-6) - 0.6882132817757726722141421e0 * c(m-4) 0.3956598149904136332753521e0 * c(m-5) + 0.1630560443616104907615866e1 * c(m-4) - 0.2421320004064592721552708e0 * c(m-2) - 0.2893557395653431666593814e0 * c(m) - 0.5688529641249387985434413e-1 * c(m-6) -0.6639605248735044787146222e0 * c(m-5) - 0.1865625445986772763641423e1 * c(m-4) + 0.1103611313171476425250639e0 * c(m-3) - 0.9091410269992464604926176e-1 * c(m) - 0.8636954541126674177407762e-1 * c(m-6) 0.4681819359722749441073885e0 * c(m-5) + 0.1015239189167790053447110e1 * c(m-4) + 0.1043897828092562609502636e0 * c(m-3) + 0.2542001760457345743492403e0 * c(m-2) + 0.1306332157111667628555907e1 * c(m) + 0.1196351539550049336518187e0 * c(m-6) -0.1195777325611201766551392e0 * c(m-5) - 0.2187310061229745694542609e0 * c(m-4) - 0.4128029838349298819825156e-1 * c(m-3) - 0.2845627370491611369031341e-1 * c(m-2) - 0.1016689339350338144430605e1 * c(m) - 0.3992391469197282238624438e-1 * c(m-6); 0.5593983696629863059347067e-3 * c(m-5) - 0.1446656414398166805849327e-3 * c(m-6) - 0.4147327282231696253497740e-3 * c(m-4) -0.6486184157331537899459796e-2 * c(m-5) + 0.4409068609809831485979484e-2 * c(m-4) + 0.2077115547521706413480312e-2 * c(m-6) 0.1319674981073749167009902e-1 * c(m-5) - 0.1060554802883657391328704e-1 * c(m-4) + 0.1911888563316170927411831e-2 * c(m-3) - 0.4503090345217088684223814e-2 * c(m-6) -0.2404661162020836566908542e-1 * c(m-4) - 0.7348845587775519698437916e-2 * c(m-3) - 0.8105784530576404277872603e-3 * c(m-2) + 0.9574633163221758060736592e-2 * c(m-1) - 0.1828896813877197352675410e-1 * c(m) + 0.1350326632905990039353503e-1 * c(m-6) - 0.1315967038382618382356495e-1 * c(m-5) 0.1241625568998496895352046e-1 * c(m-5) + 0.7403484645316174090533193e-1 * c(m-3) - 0.1023976547309387874453988e-2 * c(m-2) + 0.4440063948509876221050939e-1 * c(m-1) - 0.5224403464202056316702078e-1 * c(m) - 0.3213800979246298453953842e-1 * c(m-6) + 0.1178181682424363524005403e0 * c(m-4) -0.7684117160199014594442072e-1 * c(m-5) - 0.2928439026361256842196229e0 * c(m-4) + 0.2710530961648671297733465e-1 * c(m-2) - 0.1662748711097054895317080e0 * c(m-1) + 0.2251991532891353212689574e0 * c(m) + 0.1898341454096471754822498e-1 * c(m-6) 0.1582127073537215443965653e0 * c(m-5) + 0.3746489300753517635549495e0 * c(m-4) - 0.4364163147111892346990101e-1 * c(m-3) - 0.1845476106024151050283847e0 * c(m-1) + 0.7075642937243715046279337e-1 * c(m) + 0.2882271848190011329385407e-1 * c(m-6) -0.1195777325611201766551392e0 * c(m-5) - 0.2187310061229745694542609e0 * c(m-4) - 0.4128029838349298819825156e-1 * c(m-3) - 0.2845627370491611369031341e-1 * c(m-2) - 0.1016689339350338144430605e1 * c(m) - 0.3992391469197282238624438e-1 * c(m-6) 0.3167964748016105299646518e-1 * c(m-5) + 0.4976563420877041544013670e-1 * c(m-4) + 0.1632404042590951953384672e-1 * c(m-3) + 0.3185519088796429015220016e-2 * c(m-2) + 0.2968472090638000742888467e0 * c(m-1) + 0.7912667594695582093926295e0 * c(m) + 0.1332316557164627464149716e-1 * c(m-6);];
-
-        M(5,10)=M(10,5);
-        M(m-4,m-9)=M(m-9,m-4);
-
-        M=M/h;
-
-        D2=HI*(-M-diag(c)*e_1*S_1'+diag(c)*e_m*S_m');
-    end
-    D2 = @D2_fun;
-
-    S2_U=[0.35e2 / 0.12e2 -0.26e2 / 0.3e1 0.19e2 / 0.2e1 -0.14e2 / 0.3e1 0.11e2 / 0.12e2;]/h^2;
-    S2_1=sparse(1,m);
-    S2_1(1:5)=S2_U;
-    S2_m=sparse(1,m);
-    S2_m(m-4:m)=fliplr(S2_U);
-    S2_1 = S2_1';
-    S2_m = S2_m';
-
-
-
-
-
-    % Fourth derivative, 1th order accurate at first 8 boundary points (still
-    % yield 5th order convergence if stable: for example u_tt=-u_xxxx
-
-    m4=7/240;m3=-2/5;m2=169/60;m1=-122/15;m0=91/8;
-%     M4=m4*(diag(ones(m-4,1),4)+diag(ones(m-4,1),-4))+m3*(diag(ones(m-3,1),3)+diag(ones(m-3,1),-3))+m2*(diag(ones(m-2,1),2)+diag(ones(m-2,1),-2))+m1*(diag(ones(m-1,1),1)+diag(ones(m-1,1),-1))+m0*diag(ones(m,1),0);
-    stencil = [m4,m3,m2,m1,m0,m1,m2,m3,m4];
-    d = (length(stencil)-1)/2;
-    diags = -d:d;
-    M4 = stripeMatrix(stencil, diags, m);
-
-    %M4=(-1/6*(diag(ones(m-3,1),3)+diag(ones(m-3,1),-3) ) + 2*(diag(ones(m-2,1),2)+diag(ones(m-2,1),-2)) -13/2*(diag(ones(m-1,1),1)+diag(ones(m-1,1),-1)) + 28/3*diag(ones(m,1),0));
-
-    M4_U=[0.1394226315049e13 / 0.367201486080e12 -0.1137054563243e13 / 0.114750464400e12 0.16614189027367e14 / 0.1836007430400e13 -0.1104821700277e13 / 0.306001238400e12 0.1355771086763e13 / 0.1836007430400e13 -0.27818686453e11 / 0.459001857600e12 -0.40671054239e11 / 0.1836007430400e13 0.5442887371e10 / 0.306001238400e12; -0.1137054563243e13 / 0.114750464400e12 0.70616795535409e14 / 0.2570410402560e13 -0.173266854731041e15 / 0.6426026006400e13 0.28938615291031e14 / 0.2570410402560e13 -0.146167361863e12 / 0.71400288960e11 0.2793470836571e13 / 0.12852052012800e14 0.6219558097e10 / 0.428401733760e12 -0.7313844559e10 / 0.166909766400e12; 0.16614189027367e14 / 0.1836007430400e13 -0.173266854731041e15 / 0.6426026006400e13 0.378613061504779e15 / 0.12852052012800e14 -0.9117069604217e13 / 0.642602600640e12 0.632177582849e12 / 0.233673672960e12 -0.1057776382577e13 / 0.6426026006400e13 0.443019868399e12 / 0.4284017337600e13 -0.3707981e7 / 0.2318191200e10; -0.1104821700277e13 / 0.306001238400e12 0.28938615291031e14 / 0.2570410402560e13 -0.9117069604217e13 / 0.642602600640e12 0.5029150721885e13 / 0.514082080512e12 -0.5209119714341e13 / 0.1285205201280e13 0.12235427457469e14 / 0.12852052012800e14 -0.13731270505e11 / 0.64260260064e11 0.2933596129e10 / 0.40800165120e11; 0.1355771086763e13 / 0.1836007430400e13 -0.146167361863e12 / 0.71400288960e11 0.632177582849e12 / 0.233673672960e12 -0.5209119714341e13 / 0.1285205201280e13 0.14871726798559e14 / 0.2570410402560e13 -0.7504337615347e13 / 0.1606506501600e13 0.310830296467e12 / 0.171360693504e12 -0.55284274391e11 / 0.183600743040e12; -0.27818686453e11 / 0.459001857600e12 0.2793470836571e13 / 0.12852052012800e14 -0.1057776382577e13 / 0.6426026006400e13 0.12235427457469e14 / 0.12852052012800e14 -0.7504337615347e13 / 0.1606506501600e13 0.106318657014853e15 / 0.12852052012800e14 -0.14432772918527e14 / 0.2142008668800e13 0.58102695589e11 / 0.22666758400e11; -0.40671054239e11 / 0.1836007430400e13 0.6219558097e10 / 0.428401733760e12 0.443019868399e12 / 0.4284017337600e13 -0.13731270505e11 / 0.64260260064e11 0.310830296467e12 / 0.171360693504e12 -0.14432772918527e14 / 0.2142008668800e13 0.27102479467823e14 / 0.2570410402560e13 -0.1216032192203e13 / 0.153000619200e12; 0.5442887371e10 / 0.306001238400e12 -0.7313844559e10 / 0.166909766400e12 -0.3707981e7 / 0.2318191200e10 0.2933596129e10 / 0.40800165120e11 -0.55284274391e11 / 0.183600743040e12 0.58102695589e11 / 0.22666758400e11 -0.1216032192203e13 / 0.153000619200e12 0.20799922829107e14 / 0.1836007430400e13;];
-
-    M4(1:8,1:8)=M4_U;
-
-    M4(m-7:m,m-7:m)=rot90(  M4_U ,2 );
-    M4=M4/h^3;
-
-    S3_U=[-0.5e1 / 0.2e1 9 -12 7 -0.3e1 / 0.2e1;]/h^3;
-    S3_1=sparse(1,m);
-    S3_1(1:5)=S3_U;
-    S3_m=sparse(1,m);
-    S3_m(m-4:m)=fliplr(-S3_U);
-    S3_1 = S3_1';
-    S3_m = S3_m';
-
-    D4=HI*(M4-e_1*S3_1'+e_m*S3_m'  + S_1*S2_1'-S_m*S2_m');
-
-end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_lonely_4_min_boundary_points.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_lonely_4_min_boundary_points.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,81 @@
+function [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_4_min_boundary_points(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 4:de ordn. SBP Finita differens         %%%
+    %%% operatorer framtagna av Mark Carpenter  %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %H?r med endast 4 randpunkter
+
+
+    BP = 4;
+    if(m<2*BP)
+        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
+    end
+
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:4) = [17/48 59/48 43/48 49/48];
+    Hv(m-3:m) = rot90(Hv(1:4),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:4) = 1/h*[-11/6 3 -3/2 1/3];
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:4) = 1/h^2*[2 -5 4 -1];
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:4) = 1/h^3*[-1 3 -3 1];
+    d3_r = -rot90(d3_l, 2);
+
+
+    % First derivative
+    stencil = [1/12 -2/3 0 2/3 -1/12];
+    diags = [-1 0 1];
+
+    Q_U = [
+        0 0.59e2/0.96e2 -0.1e1/0.12e2 -0.1e1/0.32e2;
+         -0.59e2/0.96e2 0 0.59e2/0.96e2 0;
+         0.1e1/0.12e2 -0.59e2/0.96e2 0 0.59e2/0.96e2;
+         0.1e1/0.32e2 0 -0.59e2/0.96e2 0;
+    ];
+
+    Q = stripeMatrix(stencil, diags, m);
+    Q(1:4,1:4)=Q_U;
+    Q(m-3:m,m-3:m) = -rot90(Q_U, 2);
+
+    D1 = HI*(Q - 1/2*e_l*e_l' + 1/2*e_r*e_r');
+
+    % Fourth derivative
+    stencil = [-1/6, 2, -13/2, 28/3, -13/2, 2, -1/6];
+    diags = -3:3;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U=[
+        0.8e1/0.3e1 -0.37e2/0.6e1 0.13e2/0.3e1 -0.5e1/0.6e1;
+        -0.37e2/0.6e1 0.47e2/0.3e1 -13 0.11e2/0.3e1;
+        0.13e2/0.3e1 -13 0.44e2/0.3e1 -0.47e2/0.6e1;
+        -0.5e1/0.6e1 0.11e2/0.3e1 -0.47e2/0.6e1 0.29e2/0.3e1;
+    ];
+
+
+    M4(1:4,1:4) = M4_U;
+    M4(m-3:m,m-3:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_lonely_6_2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_lonely_6_2.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,76 @@
+function [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_6_2(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 6:te ordn. SBP Finita differens         %%%
+    %%% operatorer med diagonal norm            %%%
+    %%% Extension to variable koeff             %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%% D2=HI*(R+C*D*S                          %%%
+    %%%                                         %%%
+    %%% R=-D1'*H*C*D1-RR                        %%%
+    %%%                                         %%%
+    %%% RR ?r dissipation)                      %%%
+    %%% Dissipationen uppbyggd av D4:           %%%
+    %%% DI=D4*B*H*D4                            %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    % H?r med 6 RP ist?llet f?r 8 f?r D4 operatorn, dock samma randderivator
+    % Denna ?r noggrannare, och har 2a ordningens randdslutning och b?r ge 6te
+    % ordningens konvergens. Hade dock ingen fri parameter att optimera
+
+    BP = 6;
+    if(m<2*BP)
+        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:6) = [0.181e3/0.576e3, 0.1343e4/0.960e3, 0.293e3/0.480e3, 0.1811e4/0.1440e4, 0.289e3/0.320e3, 0.65e2/0.64e2];
+    Hv(m-5:m) = rot90(Hv(1:6),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:6) = [-0.137e3/0.60e2 5 -5 0.10e2/0.3e1 -0.5e1/0.4e1 0.1e1/0.5e1;]/h;
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:6) = [0.15e2/0.4e1 -0.77e2/0.6e1 0.107e3/0.6e1 -13 0.61e2/0.12e2 -0.5e1/0.6e1;]/h^2;
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:6) = [-0.17e2/0.4e1 0.71e2/0.4e1 -0.59e2/0.2e1 0.49e2/0.2e1 -0.41e2/0.4e1 0.7e1/0.4e1;]/h^3;
+    d3_r = -rot90(d3_l, 2);
+
+
+    % Fourth derivative, 1th order accurate at first 8 boundary points (still
+    % yield 5th order convergence if stable: for example u_tt = -u_xxxx
+    stencil = [7/240, -2/5, 169/60, -122/15, 91/8, -122/15, 169/60, -2/5, 7/240];
+    diags = -4:4;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U = [
+        0.1009e4/0.192e3 -0.7657e4/0.480e3 0.9307e4/0.480e3 -0.509e3/0.40e2 0.4621e4/0.960e3 -0.25e2/0.32e2;
+        -0.7657e4/0.480e3 0.49513e5/0.960e3 -0.4007e4/0.60e2 0.21799e5/0.480e3 -0.8171e4/0.480e3 0.2657e4/0.960e3;
+        0.9307e4/0.480e3 -0.4007e4/0.60e2 0.1399e4/0.15e2 -0.2721e4/0.40e2 0.12703e5/0.480e3 -0.521e3/0.120e3;
+        -0.509e3/0.40e2 0.21799e5/0.480e3 -0.2721e4/0.40e2 0.3349e4/0.60e2 -0.389e3/0.15e2 0.559e3/0.96e2;
+        0.4621e4/0.960e3 -0.8171e4/0.480e3 0.12703e5/0.480e3 -0.389e3/0.15e2 0.17857e5/0.960e3 -0.1499e4/0.160e3;
+        -0.25e2/0.32e2 0.2657e4/0.960e3 -0.521e3/0.120e3 0.559e3/0.96e2 -0.1499e4/0.160e3 0.2225e4/0.192e3;
+    ];
+
+
+    M4(1:6,1:6) = M4_U;
+    M4(m-5:m,m-5:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_lonely_6_3.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_lonely_6_3.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,70 @@
+function [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_6_3(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 6:te ordn. SBP Finita differens         %%%
+    %%% operatorer med diagonal norm            %%%
+    %%% Extension to variable koeff             %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%% D2=HI*(R+C*D*S                          %%%
+    %%%                                         %%%
+    %%% R=-D1'*H*C*D1-RR                        %%%
+    %%%                                         %%%
+    %%% RR ?r dissipation)                      %%%
+    %%% Dissipationen uppbyggd av D4:           %%%
+    %%% DI=D4*B*H*D4                            %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    % H?r med 7 RP ist?llet f?r 8 f?r D4 operatorn, dock samma randderivator
+    % Denna ?r noggrannare, och har 2a ordningens randdslutning och b?r ge 6te
+    % ordningens konvergens. Hade 2 fria parametrar att optimera
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:7) = [0.414837907e9/0.1191965760e10, 0.475278367e9/0.397321920e9, 0.13872751e8/0.12416310e8, 0.346739027e9/0.595982880e9, 0.560227469e9/0.397321920e9, 0.322971631e9/0.397321920e9, 0.616122491e9/0.595982880e9];
+    Hv(m-6:m) = rot90(Hv(1:7),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:6) = [-0.137e3/0.60e2 5 -5 0.10e2/0.3e1 -0.5e1/0.4e1 0.1e1/0.5e1;]/h;
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:6) = [0.15e2/0.4e1 -0.77e2/0.6e1 0.107e3/0.6e1 -13 0.61e2/0.12e2 -0.5e1/0.6e1;]/h^2;
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:6) = [-0.17e2/0.4e1 0.71e2/0.4e1 -0.59e2/0.2e1 0.49e2/0.2e1 -0.41e2/0.4e1 0.7e1/0.4e1;]/h^3;
+    d3_r = -rot90(d3_l, 2);
+
+
+    % Fourth derivative, 1th order accurate at first 8 boundary points
+    stencil = [7/240, -2/5, 169/60, -122/15, 91/8, -122/15, 169/60, -2/5, 7/240];
+    diags = -4:4;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U = [
+        0.1399708478939e13/0.263487168000e12 -0.13482796013041e14/0.834376032000e12 0.344344095859e12/0.17565811200e11 -0.3166261424681e13/0.250312809600e12 0.1508605165681e13/0.333750412800e12 -0.486270829441e12/0.834376032000e12 -0.221976356359e12/0.5006256192000e13;
+        -0.13482796013041e14/0.834376032000e12 0.7260475818391e13/0.139062672000e12 -0.27224036353e11/0.406022400e9 0.1847477458951e13/0.41718801600e11 -0.848984558161e12/0.55625068800e11 0.247494925991e12/0.139062672000e12 0.165585445559e12/0.834376032000e12;
+        0.344344095859e12/0.17565811200e11 -0.27224036353e11/0.406022400e9 0.2044938640393e13/0.22250027520e11 -0.1071086785417e13/0.16687520640e11 0.502199537033e12/0.22250027520e11 -0.143589154441e12/0.55625068800e11 -0.88181965559e11/0.333750412800e12;
+        -0.3166261424681e13/0.250312809600e12 0.1847477458951e13/0.41718801600e11 -0.1071086785417e13/0.16687520640e11 0.628860435593e12/0.12515640480e11 -0.73736245829e11/0.3337504128e10 0.195760572271e12/0.41718801600e11 -0.81156046361e11/0.250312809600e12;
+        0.1508605165681e13/0.333750412800e12 -0.848984558161e12/0.55625068800e11 0.502199537033e12/0.22250027520e11 -0.73736245829e11/0.3337504128e10 0.76725285869e11/0.4450005504e10 -0.3912429433e10/0.406022400e9 0.53227370659e11/0.17565811200e11;
+        -0.486270829441e12/0.834376032000e12 0.247494925991e12/0.139062672000e12 -0.143589154441e12/0.55625068800e11 0.195760572271e12/0.41718801600e11 -0.3912429433e10/0.406022400e9 0.1699707221791e13/0.139062672000e12 -0.6959018412841e13/0.834376032000e12;
+        -0.221976356359e12/0.5006256192000e13 0.165585445559e12/0.834376032000e12 -0.88181965559e11/0.333750412800e12 -0.81156046361e11/0.250312809600e12 0.53227370659e11/0.17565811200e11 -0.6959018412841e13/0.834376032000e12 0.3012195053939e13/0.263487168000e12;
+    ];
+
+    M4(1:7,1:7) = M4_U;
+    M4(m-6:m,m-6:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_lonely_6_min_boundary_points.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_lonely_6_min_boundary_points.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,74 @@
+function [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_6_min_boundary_points(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 6:te ordn. SBP Finita differens         %%%
+    %%% operatorer med diagonal norm            %%%
+    %%% Extension to variable koeff             %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%% D2=HI*(R+C*D*S                          %%%
+    %%%                                         %%%
+    %%% R=-D1'*H*C*D1-RR                        %%%
+    %%%                                         %%%
+    %%% RR ?r dissipation)                      %%%
+    %%% Dissipationen uppbyggd av D4:           %%%
+    %%% DI=D4*B*H*D4                            %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    % H?r med 6 RP ist?llet f?r 8 f?r D4 operatorn, dock samma randderivator
+
+    BP = 6;
+    if(m<2*BP)
+        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:6) = [13649/43200,12013/8640,2711/4320,5359/4320,7877/8640, 43801/43200];
+    Hv(m-5:m) = rot90(Hv(1:6),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:5) = [-25/12, 4, -3, 4/3, -1/4]/h;
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:5) = [0.35e2/0.12e2 -0.26e2/0.3e1 0.19e2/0.2e1 -0.14e2/0.3e1 0.11e2/0.12e2;]/h^2;
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:5) = [-0.5e1/0.2e1 9 -12 7 -0.3e1/0.2e1;]/h^3;
+    d3_r = -rot90(d3_l, 2);
+
+
+    % Fourth derivative, 1th order accurate at first 8 boundary points (still
+    % yield 5th order convergence if stable: for example u_tt=-u_xxxx
+
+    stencil = [7/240, -2/5, 169/60, -122/15, 91/8, -122/15, 169/60, -2/5, 7/240];
+    diags = -4:4;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U=[
+        0.3504379e7/0.907200e6 -0.4613983e7/0.453600e6 0.4260437e7/0.453600e6 -0.418577e6/0.113400e6 0.524579e6/0.907200e6 0.535e3/0.18144e5;
+        -0.4613983e7/0.453600e6 0.5186159e7/0.181440e6 -0.81121e5/0.2835e4 0.218845e6/0.18144e5 -0.159169e6/0.90720e5 -0.94669e5/0.907200e6;
+        0.4260437e7/0.453600e6 -0.81121e5/0.2835e4 0.147695e6/0.4536e4 -0.384457e6/0.22680e5 0.339653e6/0.90720e5 -0.18233e5/0.113400e6;
+        -0.418577e6/0.113400e6 0.218845e6/0.18144e5 -0.384457e6/0.22680e5 0.65207e5/0.4536e4 -0.22762e5/0.2835e4 0.1181753e7/0.453600e6;
+        0.524579e6/0.907200e6 -0.159169e6/0.90720e5 0.339653e6/0.90720e5 -0.22762e5/0.2835e4 0.2006171e7/0.181440e6 -0.3647647e7/0.453600e6;
+        0.535e3/0.18144e5 -0.94669e5/0.907200e6 -0.18233e5/0.113400e6 0.1181753e7/0.453600e6 -0.3647647e7/0.453600e6 0.10305271e8/0.907200e6;
+    ];
+
+    M4(1:6,1:6) = M4_U;
+    M4(m-5:m,m-5:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_lonely_8_higher_boundary_order.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_lonely_8_higher_boundary_order.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,76 @@
+function [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_8_higher_boundary_order(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 8:te ordn. SBP Finita differens         %%%
+    %%% operatorer med diagonal norm            %%%
+    %%%                                         %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%% D2=HI*(R+C*D*S                          %%%
+    %%%                                         %%%
+    %%% R=-D1'*H*C*D1-RR                        %%%
+    %%%                                         %%%
+    %%% RR ?r dissipation)                      %%%
+    %%% Dissipationen uppbyggd av D4:           %%%
+    %%% DI=D4*B*H*D4                            %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %This is 3rd order accurate at the boundary. Not same norm as D1 operator
+
+    BP = 8;
+    if(m<2*BP)
+        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:8) = [0.7488203e7/0.25401600e8, 0.5539027e7/0.3628800e7, 0.308923e6/0.1209600e7, 0.1307491e7/0.725760e6, 0.59407e5/0.145152e6, 0.1548947e7/0.1209600e7, 0.3347963e7/0.3628800e7, 0.25641187e8/0.25401600e8];
+    Hv(m-7:m) = rot90(Hv(1:8),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:7) = [-0.49e2/0.20e2 6 -0.15e2/0.2e1 0.20e2/0.3e1 -0.15e2/0.4e1 0.6e1/0.5e1 -0.1e1/0.6e1]/h;
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:7) = [0.203e3/0.45e2 -0.87e2/0.5e1 0.117e3/0.4e1 -0.254e3/0.9e1 0.33e2/0.2e1 -0.27e2/0.5e1 0.137e3/0.180e3]/h^2;
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:7) = [-0.49e2/0.8e1 29 -0.461e3/0.8e1 62 -0.307e3/0.8e1 13 -0.15e2/0.8e1]/h^3;
+    d3_r = -rot90(d3_l, 2);
+
+
+
+    % Fourth derivative, 1th order accurate at first 8 boundary points (still
+    % yield 5th order convergence if stable: for example u_tt = -u_xxxx
+
+    stencil = [-0.41e2/0.7560e4, 0.1261e4/0.15120e5, -0.541e3/0.840e3, 0.4369e4/0.1260e4, -0.1669e4/0.180e3, 0.1529e4/0.120e3, -0.1669e4/0.180e3, 0.4369e4/0.1260e4, -0.541e3/0.840e3, 0.1261e4/0.15120e5,-0.41e2/0.7560e4];
+    diags = -5:5;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U = [
+        0.1031569831e10/0.155675520e9 -0.32874237931e11/0.1452971520e10 0.3069551773e10/0.90810720e8 -0.658395212131e12/0.21794572800e11 0.31068454007e11/0.1816214400e10 -0.39244130657e11/0.7264857600e10 0.1857767503e10/0.2724321600e10 0.1009939e7/0.49420800e8;
+        -0.32874237931e11/0.1452971520e10 0.12799022387e11/0.155675520e9 -0.134456503627e12/0.1037836800e10 0.15366749479e11/0.129729600e9 -0.207640325549e12/0.3113510400e10 0.5396424073e10/0.259459200e9 -0.858079351e9/0.345945600e9 -0.19806607e8/0.170270100e9;
+        0.3069551773e10/0.90810720e8 -0.134456503627e12/0.1037836800e10 0.6202056779e10/0.28828800e8 -0.210970327081e12/0.1037836800e10 0.2127730129e10/0.18532800e8 -0.4048692749e10/0.115315200e9 0.1025943959e10/0.259459200e9 0.71054663e8/0.290594304e9;
+        -0.658395212131e12/0.21794572800e11 0.15366749479e11/0.129729600e9 -0.210970327081e12/0.1037836800e10 0.31025293213e11/0.155675520e9 -0.1147729001e10/0.9884160e7 0.1178067773e10/0.32432400e8 -0.13487255581e11/0.3113510400e10 -0.231082547e9/0.1816214400e10;
+        0.31068454007e11/0.1816214400e10 -0.207640325549e12/0.3113510400e10 0.2127730129e10/0.18532800e8 -0.1147729001e10/0.9884160e7 0.11524865123e11/0.155675520e9 -0.29754506009e11/0.1037836800e10 0.14231221e8/0.2316600e7 -0.15030629699e11/0.21794572800e11;
+        -0.39244130657e11/0.7264857600e10 0.5396424073e10/0.259459200e9 -0.4048692749e10/0.115315200e9 0.1178067773e10/0.32432400e8 -0.29754506009e11/0.1037836800e10 0.572247737e9/0.28828800e8 -0.11322059051e11/0.1037836800e10 0.3345834083e10/0.908107200e9;
+        0.1857767503e10/0.2724321600e10 -0.858079351e9/0.345945600e9 0.1025943959e10/0.259459200e9 -0.13487255581e11/0.3113510400e10 0.14231221e8/0.2316600e7 -0.11322059051e11/0.1037836800e10 0.10478882597e11/0.778377600e9 -0.68446325191e11/0.7264857600e10;
+        0.1009939e7/0.49420800e8 -0.19806607e8/0.170270100e9 0.71054663e8/0.290594304e9 -0.231082547e9/0.1816214400e10 -0.15030629699e11/0.21794572800e11 0.3345834083e10/0.908107200e9 -0.68446325191e11/0.7264857600e10 0.9944747557e10/0.778377600e9;
+    ];
+
+    M4(1:8,1:8) = M4_U;
+    M4(m-7:m,m-7:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_lonely_8_min_boundary_points.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_lonely_8_min_boundary_points.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,73 @@
+function [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_8_min_boundary_points(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 8:te ordn. SBP Finita differens         %%%
+    %%% operatorer med diagonal norm            %%%
+    %%%                                         %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%% D2=HI*(R+C*D*S                          %%%
+    %%%                                         %%%
+    %%% R=-D1'*H*C*D1-RR                        %%%
+    %%%                                         %%%
+    %%% RR ?r dissipation)                      %%%
+    %%% Dissipationen uppbyggd av D4:           %%%
+    %%% DI=D4*B*H*D4                            %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    BP = 8;
+    if(m<2*BP)
+        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:8) = [1498139/5080320, 1107307/725760, 20761/80640, 1304999/725760, 299527/725760, 103097/80640, 670091/725760, 5127739/5080320];
+    Hv(m-7:m) = rot90(Hv(1:8),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:6) = [-0.137e3/0.60e2 5 -5 0.10e2/0.3e1 -0.5e1/0.4e1 0.1e1/0.5e1;]/h;
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:6) = [0.15e2/0.4e1 -0.77e2/0.6e1 0.107e3/0.6e1 -13 0.61e2/0.12e2 -0.5e1/0.6e1;]/h^2;
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:6) = [-0.17e2/0.4e1 0.71e2/0.4e1 -0.59e2/0.2e1 0.49e2/0.2e1 -0.41e2/0.4e1 0.7e1/0.4e1;]/h^3;
+    d3_r = -rot90(d3_l, 2);
+
+
+    % Fourth derivative, 1th order accurate at first 8 boundary points
+
+    stencil = [-0.41e2/0.7560e4, 0.1261e4/0.15120e5,-0.541e3/0.840e3,0.4369e4/0.1260e4,-0.1669e4/0.180e3,0.1529e4/0.120e3,-0.1669e4/0.180e3,0.4369e4/0.1260e4,-0.541e3/0.840e3, 0.1261e4/0.15120e5,-0.41e2/0.7560e4];
+    diags = -5:5;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U = [
+        0.151705142321e12/0.29189160000e11 -0.25643455801727e14/0.1634592960000e13 0.286417898677e12/0.15135120000e11 -0.4038072020317e13/0.326918592000e12 0.96455968907e11/0.20432412000e11 -0.151076916769e12/0.181621440000e12 0.14511526363e11/0.408648240000e12 -0.196663079e9/0.33359040000e11;
+         -0.25643455801727e14/0.1634592960000e13 0.735383382473e12/0.14594580000e11 -0.5035391734409e13/0.77837760000e11 0.20392440917e11/0.467026560e9 -0.109540902413e12/0.6671808000e10 0.2488686539e10/0.884520000e9 -0.2798067539e10/0.33359040000e11 0.6433463591e10/0.408648240000e12;
+         0.286417898677e12/0.15135120000e11 -0.5035391734409e13/0.77837760000e11 0.145019791981e12/0.1621620000e10 -0.333577111061e12/0.5189184000e10 0.18928722391e11/0.778377600e9 -0.93081704557e11/0.25945920000e11 -0.372660319e9/0.3243240000e10 0.2861399869e10/0.544864320000e12;
+         -0.4038072020317e13/0.326918592000e12 0.20392440917e11/0.467026560e9 -0.333577111061e12/0.5189184000e10 0.59368471277e11/0.1167566400e10 -0.201168708569e12/0.9340531200e10 0.1492314487e10/0.432432000e9 0.1911896257e10/0.9340531200e10 0.24383341e8/0.2554051500e10;
+         0.96455968907e11/0.20432412000e11 -0.109540902413e12/0.6671808000e10 0.18928722391e11/0.778377600e9 -0.201168708569e12/0.9340531200e10 0.1451230301e10/0.106142400e9 -0.103548247007e12/0.15567552000e11 0.27808437809e11/0.11675664000e11 -0.36870830713e11/0.65383718400e11;
+         -0.151076916769e12/0.181621440000e12 0.2488686539e10/0.884520000e9 -0.93081704557e11/0.25945920000e11 0.1492314487e10/0.432432000e9 -0.103548247007e12/0.15567552000e11 0.1229498243e10/0.115830000e9 -0.32222519717e11/0.3706560000e10 0.470092704233e12/0.136216080000e12;
+         0.14511526363e11/0.408648240000e12 -0.2798067539e10/0.33359040000e11 -0.372660319e9/0.3243240000e10 0.1911896257e10/0.9340531200e10 0.27808437809e11/0.11675664000e11 -0.32222519717e11/0.3706560000e10 0.11547819313e11/0.912161250e9 -0.15187033999199e14/0.1634592960000e13;
+         -0.196663079e9/0.33359040000e11 0.6433463591e10/0.408648240000e12 0.2861399869e10/0.544864320000e12 0.24383341e8/0.2554051500e10 -0.36870830713e11/0.65383718400e11 0.470092704233e12/0.136216080000e12 -0.15187033999199e14/0.1634592960000e13 0.33832994693e11/0.2653560000e10;
+    ];
+
+    M4(1:8,1:8) = M4_U;
+    M4(m-7:m,m-7:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_variable_2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_variable_2.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,89 @@
+% Returns D2 as a function handle
+function [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_2(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 4:de ordn. SBP Finita differens         %%%
+    %%% operatorer framtagna av Ken Mattsson    %%%
+    %%%                                         %%%
+    %%% 6 randpunkter, diagonal norm            %%%
+    %%%                                         %%%
+    %%% Datum: 2013-11-11                       %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    BP = 2;
+    if(m < 2*BP)
+        error('Operator requires at least %d grid points', 2*BP);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1) = 1/2;
+    Hv(m) = 1/2;
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:3) = 1/h*[-3/2 2 -1/2];
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:3) = 1/h^2*[1 -2 1];
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:4) = 1/h^3*[-1 3 -3 1];
+    d3_r = -rot90(d3_l, 2);
+
+
+    % First derivative SBP operator, 1st order accurate at first 6 boundary points
+    stencil = [-1/2, 0, 1/2];
+    diags = [-1 0 1];
+    Q = stripeMatrix(stencil, diags, m);
+
+    D1 = HI*(Q - 1/2*e_l*e_l' + 1/2*e_r*e_r');
+
+    % Second derivative, 1st order accurate at first boundary points
+    M = sparse(m,m);
+
+    scheme_width = 3;
+    scheme_radius = (scheme_width-1)/2;
+    r = (1+scheme_radius):(m-scheme_radius);
+
+    function D2 = D2_fun(c)
+        Mm1 = -c(r-1)/2 - c(r)/2;
+        M0  =  c(r-1)/2 + c(r)   + c(r+1)/2;
+        Mp1 =            -c(r)/2 - c(r+1)/2;
+
+        M(r,:) = spdiags([Mm1 M0 Mp1],0:2*scheme_radius,length(r),m);
+
+        M(1:2,1:2) = [c(1)/2 + c(2)/2 -c(1)/2 - c(2)/2; -c(1)/2 - c(2)/2 c(1)/2 + c(2) + c(3)/2;];
+        M(m-1:m,m-1:m) = [c(m-2)/2 + c(m-1) + c(m)/2 -c(m-1)/2 - c(m)/2; -c(m-1)/2 - c(m)/2 c(m-1)/2 + c(m)/2;];
+        M = 1/h*M;
+
+        D2 = HI*(-M - c(1)*e_l*d1_l' + c(m)*e_r*d1_r');
+    end
+    D2 = @D2_fun;
+
+    % Fourth derivative, 0th order accurate at first 6 boundary points
+    stencil = [1, -4, 6, -4, 1];
+    diags = -2:2;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U = [
+         0.13e2/0.10e2 -0.12e2/0.5e1   0.9e1/0.10e2   0.1e1/0.5e1;
+        -0.12e2/0.5e1   0.26e2/0.5e1  -0.16e2/0.5e1   0.2e1/0.5e1;
+         0.9e1/0.10e2  -0.16e2/0.5e1   0.47e2/0.10e2 -0.17e2/0.5e1;
+         0.1e1/0.5e1    0.2e1/0.5e1   -0.17e2/0.5e1   0.29e2/0.5e1;
+    ];
+
+    M4(1:4,1:4) = M4_U;
+    M4(m-3:m,m-3:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_variable_4.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_variable_4.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,171 @@
+function [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_4(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 4:de ordn. SBP Finita differens         %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+    BP = 6;
+    if(m<2*BP)
+        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:4) = [17/48 59/48 43/48 49/48];
+    Hv(m-3:m) = rot90(Hv(1:4),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:4) = 1/h*[-11/6 3 -3/2 1/3];
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:4) = 1/h^2*[2 -5 4 -1];
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:4) = 1/h^3*[-1 3 -3 1];
+    d3_r = -rot90(d3_l, 2);
+
+
+    % First derivative SBP operator,
+    stencil = [1/12 -2/3 0 2/3 -1/12];
+    diags = -2:2;
+
+    Q_U = [
+        0 0.59e2/0.96e2 -0.1e1/0.12e2 -0.1e1/0.32e2;
+        -0.59e2/0.96e2 0 0.59e2/0.96e2 0;
+        0.1e1/0.12e2 -0.59e2/0.96e2 0 0.59e2/0.96e2;
+        0.1e1/0.32e2 0 -0.59e2/0.96e2 0;
+    ];
+
+    Q = stripeMatrix(stencil, diags, m);
+    Q(1:4,1:4)=Q_U;
+    Q(m-3:m,m-3:m) = -rot90(Q_U, 2);
+
+    D1 = HI*(Q - 1/2*e_l*e_l' + 1/2*e_r*e_r');
+
+
+    % Second derivative
+    M = sparse(m,m);
+
+    scheme_width = 5;
+    scheme_radius = (scheme_width-1)/2;
+    r = (1+scheme_radius):(m-scheme_radius);
+
+    function D2 = D2_fun(c)
+        Mm2 =  c(r-2)/0.8e1 - c(r-1)/0.6e1 + c(r)    /0.8e1                                  ;
+        Mm1 = -c(r-2)/0.6e1 - c(r-1)/0.2e1 - c(r)    /0.2e1 - c(r+1)/0.6e1                 ;
+        M0  =  c(r-2)/2.4e1 + c(r-1)/1.2e0 + c(r)*0.3/0.4   + c(r+1)/1.2e0 + c(r+2)/2.4e1;
+        Mp1 =                -c(r-1)/0.6e1 - c(r)    /0.2e1 - c(r+1)/0.2e1 - c(r+2)/0.6e1;
+        Mp2 =                                c(r)    /0.8e1 - c(r+1)/0.6e1 + c(r+2)/0.8e1;
+
+        M(r,:) = spdiags([Mm2 Mm1 M0 Mp1 Mp2],0:2*scheme_radius,length(r),m);
+
+        M(1:6,1:6) = [
+            0.12e2/0.17e2 * c(1) + 0.59e2/0.192e3 * c(2) + 0.27010400129e11/0.345067064608e12 * c(3) + 0.69462376031e11/0.2070402387648e13 * c(4) -0.59e2/0.68e2 * c(1) - 0.6025413881e10/0.21126554976e11 * c(3) - 0.537416663e9/0.7042184992e10 * c(4) 0.2e1/0.17e2 * c(1) - 0.59e2/0.192e3 * c(2) + 0.213318005e9/0.16049630912e11 * c(4) + 0.2083938599e10/0.8024815456e10 * c(3) 0.3e1/0.68e2 * c(1) - 0.1244724001e10/0.21126554976e11 * c(3) + 0.752806667e9/0.21126554976e11 * c(4) 0.49579087e8/0.10149031312e11 * c(3) - 0.49579087e8/0.10149031312e11 * c(4) -c(4)/0.784e3 + c(3)/0.784e3;
+            -0.59e2/0.68e2 * c(1) - 0.6025413881e10/0.21126554976e11 * c(3) - 0.537416663e9/0.7042184992e10 * c(4) 0.3481e4/0.3264e4 * c(1) + 0.9258282831623875e16/0.7669235228057664e16 * c(3) + 0.236024329996203e15/0.1278205871342944e16 * c(4) -0.59e2/0.408e3 * c(1) - 0.29294615794607e14/0.29725717938208e14 * c(3) - 0.2944673881023e13/0.29725717938208e14 * c(4) -0.59e2/0.1088e4 * c(1) + 0.260297319232891e15/0.2556411742685888e16 * c(3) - 0.60834186813841e14/0.1278205871342944e16 * c(4) -0.1328188692663e13/0.37594290333616e14 * c(3) + 0.1328188692663e13/0.37594290333616e14 * c(4) -0.8673e4/0.2904112e7 * c(3) + 0.8673e4/0.2904112e7 * c(4);
+            0.2e1/0.17e2 * c(1) - 0.59e2/0.192e3 * c(2) + 0.213318005e9/0.16049630912e11 * c(4) + 0.2083938599e10/0.8024815456e10 * c(3) -0.59e2/0.408e3 * c(1) - 0.29294615794607e14/0.29725717938208e14 * c(3) - 0.2944673881023e13/0.29725717938208e14 * c(4) c(1)/0.51e2 + 0.59e2/0.192e3 * c(2) + 0.13777050223300597e17/0.26218083221499456e17 * c(4) + 0.564461e6/0.13384296e8 * c(5) + 0.378288882302546512209e21/0.270764341349677687456e21 * c(3) c(1)/0.136e3 - 0.125059e6/0.743572e6 * c(5) - 0.4836340090442187227e19/0.5525802884687299744e19 * c(3) - 0.17220493277981e14/0.89177153814624e14 * c(4) -0.10532412077335e14/0.42840005263888e14 * c(4) + 0.1613976761032884305e19/0.7963657098519931984e19 * c(3) + 0.564461e6/0.4461432e7 * c(5) -0.960119e6/0.1280713392e10 * c(4) - 0.3391e4/0.6692148e7 * c(5) + 0.33235054191e11/0.26452850508784e14 * c(3);
+            0.3e1/0.68e2 * c(1) - 0.1244724001e10/0.21126554976e11 * c(3) + 0.752806667e9/0.21126554976e11 * c(4) -0.59e2/0.1088e4 * c(1) + 0.260297319232891e15/0.2556411742685888e16 * c(3) - 0.60834186813841e14/0.1278205871342944e16 * c(4) c(1)/0.136e3 - 0.125059e6/0.743572e6 * c(5) - 0.4836340090442187227e19/0.5525802884687299744e19 * c(3) - 0.17220493277981e14/0.89177153814624e14 * c(4) 0.3e1/0.1088e4 * c(1) + 0.507284006600757858213e21/0.475219048083107777984e21 * c(3) + 0.1869103e7/0.2230716e7 * c(5) + c(6)/0.24e2 + 0.1950062198436997e16/0.3834617614028832e16 * c(4) -0.4959271814984644613e19/0.20965546238960637264e20 * c(3) - c(6)/0.6e1 - 0.15998714909649e14/0.37594290333616e14 * c(4) - 0.375177e6/0.743572e6 * c(5) -0.368395e6/0.2230716e7 * c(5) + 0.752806667e9/0.539854092016e12 * c(3) + 0.1063649e7/0.8712336e7 * c(4) + c(6)/0.8e1;
+            0.49579087e8/0.10149031312e11 * c(3) - 0.49579087e8/0.10149031312e11 * c(4) -0.1328188692663e13/0.37594290333616e14 * c(3) + 0.1328188692663e13/0.37594290333616e14 * c(4) -0.10532412077335e14/0.42840005263888e14 * c(4) + 0.1613976761032884305e19/0.7963657098519931984e19 * c(3) + 0.564461e6/0.4461432e7 * c(5) -0.4959271814984644613e19/0.20965546238960637264e20 * c(3) - c(6)/0.6e1 - 0.15998714909649e14/0.37594290333616e14 * c(4) - 0.375177e6/0.743572e6 * c(5) 0.8386761355510099813e19/0.128413970713633903242e21 * c(3) + 0.2224717261773437e16/0.2763180339520776e16 * c(4) + 0.5e1/0.6e1 * c(6) + c(7)/0.24e2 + 0.280535e6/0.371786e6 * c(5) -0.35039615e8/0.213452232e9 * c(4) - c(7)/0.6e1 - 0.13091810925e11/0.13226425254392e14 * c(3) - 0.1118749e7/0.2230716e7 * c(5) - c(6)/0.2e1;
+            -c(4)/0.784e3 + c(3)/0.784e3 -0.8673e4/0.2904112e7 * c(3) + 0.8673e4/0.2904112e7 * c(4) -0.960119e6/0.1280713392e10 * c(4) - 0.3391e4/0.6692148e7 * c(5) + 0.33235054191e11/0.26452850508784e14 * c(3) -0.368395e6/0.2230716e7 * c(5) + 0.752806667e9/0.539854092016e12 * c(3) + 0.1063649e7/0.8712336e7 * c(4) + c(6)/0.8e1 -0.35039615e8/0.213452232e9 * c(4) - c(7)/0.6e1 - 0.13091810925e11/0.13226425254392e14 * c(3) - 0.1118749e7/0.2230716e7 * c(5) - c(6)/0.2e1 0.3290636e7/0.80044587e8 * c(4) + 0.5580181e7/0.6692148e7 * c(5) + 0.5e1/0.6e1 * c(7) + c(8)/0.24e2 + 0.660204843e9/0.13226425254392e14 * c(3) + 0.3e1/0.4e1 * c(6);
+        ];
+
+        M(m-5:m,m-5:m) = [
+            c(m-7)/0.24e2 + 0.5e1/0.6e1 * c(m-6) + 0.5580181e7/0.6692148e7 * c(m-4) + 0.4887707739997e13/0.119037827289528e15 * c(m-3) + 0.3e1/0.4e1 * c(m-5) + 0.660204843e9/0.13226425254392e14 * c(m-2) + 0.660204843e9/0.13226425254392e14 * c(m-1) -c(m-6)/0.6e1 - 0.1618585929605e13/0.9919818940794e13 * c(m-3) - c(m-5)/0.2e1 - 0.1118749e7/0.2230716e7 * c(m-4) - 0.13091810925e11/0.13226425254392e14 * c(m-2) - 0.13091810925e11/0.13226425254392e14 * c(m-1) -0.368395e6/0.2230716e7 * c(m-4) + c(m-5)/0.8e1 + 0.48866620889e11/0.404890569012e12 * c(m-3) + 0.752806667e9/0.539854092016e12 * c(m-2) + 0.752806667e9/0.539854092016e12 * c(m-1) -0.3391e4/0.6692148e7 * c(m-4) - 0.238797444493e12/0.119037827289528e15 * c(m-3) + 0.33235054191e11/0.26452850508784e14 * c(m-2) + 0.33235054191e11/0.26452850508784e14 * c(m-1) -0.8673e4/0.2904112e7 * c(m-2) - 0.8673e4/0.2904112e7 * c(m-1) + 0.8673e4/0.1452056e7 * c(m-3) -c(m-3)/0.392e3 + c(m-2)/0.784e3 + c(m-1)/0.784e3;
+             -c(m-6)/0.6e1 - 0.1618585929605e13/0.9919818940794e13 * c(m-3) - c(m-5)/0.2e1 - 0.1118749e7/0.2230716e7 * c(m-4) - 0.13091810925e11/0.13226425254392e14 * c(m-2) - 0.13091810925e11/0.13226425254392e14 * c(m-1) c(m-6)/0.24e2 + 0.5e1/0.6e1 * c(m-5) + 0.3896014498639e13/0.4959909470397e13 * c(m-3) + 0.8386761355510099813e19/0.128413970713633903242e21 * c(m-2) + 0.280535e6/0.371786e6 * c(m-4) + 0.3360696339136261875e19/0.171218627618178537656e21 * c(m-1) -c(m-5)/0.6e1 - 0.4959271814984644613e19/0.20965546238960637264e20 * c(m-2) - 0.375177e6/0.743572e6 * c(m-4) - 0.13425842714e11/0.33740880751e11 * c(m-3) - 0.193247108773400725e18/0.6988515412986879088e19 * c(m-1) -0.365281640980e12/0.1653303156799e13 * c(m-3) + 0.564461e6/0.4461432e7 * c(m-4) + 0.1613976761032884305e19/0.7963657098519931984e19 * c(m-2) - 0.198407225513315475e18/0.7963657098519931984e19 * c(m-1) -0.1328188692663e13/0.37594290333616e14 * c(m-2) + 0.2226377963775e13/0.37594290333616e14 * c(m-1) - 0.8673e4/0.363014e6 * c(m-3) c(m-3)/0.49e2 + 0.49579087e8/0.10149031312e11 * c(m-2) - 0.256702175e9/0.10149031312e11 * c(m-1);
+             -0.368395e6/0.2230716e7 * c(m-4) + c(m-5)/0.8e1 + 0.48866620889e11/0.404890569012e12 * c(m-3) + 0.752806667e9/0.539854092016e12 * c(m-2) + 0.752806667e9/0.539854092016e12 * c(m-1) -c(m-5)/0.6e1 - 0.4959271814984644613e19/0.20965546238960637264e20 * c(m-2) - 0.375177e6/0.743572e6 * c(m-4) - 0.13425842714e11/0.33740880751e11 * c(m-3) - 0.193247108773400725e18/0.6988515412986879088e19 * c(m-1) c(m-5)/0.24e2 + 0.1869103e7/0.2230716e7 * c(m-4) + 0.507284006600757858213e21/0.475219048083107777984e21 * c(m-2) + 0.3e1/0.1088e4 * c(m) + 0.31688435395e11/0.67481761502e11 * c(m-3) + 0.27769176016102795561e20/0.712828572124661666976e21 * c(m-1) -0.125059e6/0.743572e6 * c(m-4) + c(m)/0.136e3 - 0.23099342648e11/0.101222642253e12 * c(m-3) - 0.4836340090442187227e19/0.5525802884687299744e19 * c(m-2) + 0.193950157930938693e18/0.5525802884687299744e19 * c(m-1) 0.260297319232891e15/0.2556411742685888e16 * c(m-2) - 0.59e2/0.1088e4 * c(m) - 0.106641839640553e15/0.1278205871342944e16 * c(m-1) + 0.26019e5/0.726028e6 * c(m-3) -0.1244724001e10/0.21126554976e11 * c(m-2) + 0.3e1/0.68e2 * c(m) + 0.752806667e9/0.21126554976e11 * c(m-1);
+             -0.3391e4/0.6692148e7 * c(m-4) - 0.238797444493e12/0.119037827289528e15 * c(m-3) + 0.33235054191e11/0.26452850508784e14 * c(m-2) + 0.33235054191e11/0.26452850508784e14 * c(m-1) -0.365281640980e12/0.1653303156799e13 * c(m-3) + 0.564461e6/0.4461432e7 * c(m-4) + 0.1613976761032884305e19/0.7963657098519931984e19 * c(m-2) - 0.198407225513315475e18/0.7963657098519931984e19 * c(m-1) -0.125059e6/0.743572e6 * c(m-4) + c(m)/0.136e3 - 0.23099342648e11/0.101222642253e12 * c(m-3) - 0.4836340090442187227e19/0.5525802884687299744e19 * c(m-2) + 0.193950157930938693e18/0.5525802884687299744e19 * c(m-1) 0.564461e6/0.13384296e8 * c(m-4) + 0.470299699916357e15/0.952302618316224e15 * c(m-3) + 0.550597048646198778781e21/0.1624586048098066124736e22 * c(m-1) + c(m)/0.51e2 + 0.378288882302546512209e21/0.270764341349677687456e21 * c(m-2) -0.59e2/0.408e3 * c(m) - 0.29294615794607e14/0.29725717938208e14 * c(m-2) - 0.2234477713167e13/0.29725717938208e14 * c(m-1) - 0.8673e4/0.363014e6 * c(m-3) -0.59e2/0.3136e4 * c(m-3) - 0.13249937023e11/0.48148892736e11 * c(m-1) + 0.2e1/0.17e2 * c(m) + 0.2083938599e10/0.8024815456e10 * c(m-2);
+             -0.8673e4/0.2904112e7 * c(m-2) - 0.8673e4/0.2904112e7 * c(m-1) + 0.8673e4/0.1452056e7 * c(m-3) -0.1328188692663e13/0.37594290333616e14 * c(m-2) + 0.2226377963775e13/0.37594290333616e14 * c(m-1) - 0.8673e4/0.363014e6 * c(m-3) 0.260297319232891e15/0.2556411742685888e16 * c(m-2) - 0.59e2/0.1088e4 * c(m) - 0.106641839640553e15/0.1278205871342944e16 * c(m-1) + 0.26019e5/0.726028e6 * c(m-3) -0.59e2/0.408e3 * c(m) - 0.29294615794607e14/0.29725717938208e14 * c(m-2) - 0.2234477713167e13/0.29725717938208e14 * c(m-1) - 0.8673e4/0.363014e6 * c(m-3) 0.9258282831623875e16/0.7669235228057664e16 * c(m-2) + 0.3481e4/0.3264e4 * c(m) + 0.228389721191751e15/0.1278205871342944e16 * c(m-1) + 0.8673e4/0.1452056e7 * c(m-3) -0.6025413881e10/0.21126554976e11 * c(m-2) - 0.59e2/0.68e2 * c(m) - 0.537416663e9/0.7042184992e10 * c(m-1);
+             -c(m-3)/0.392e3 + c(m-2)/0.784e3 + c(m-1)/0.784e3 c(m-3)/0.49e2 + 0.49579087e8/0.10149031312e11 * c(m-2) - 0.256702175e9/0.10149031312e11 * c(m-1) -0.1244724001e10/0.21126554976e11 * c(m-2) + 0.3e1/0.68e2 * c(m) + 0.752806667e9/0.21126554976e11 * c(m-1) -0.59e2/0.3136e4 * c(m-3) - 0.13249937023e11/0.48148892736e11 * c(m-1) + 0.2e1/0.17e2 * c(m) + 0.2083938599e10/0.8024815456e10 * c(m-2) -0.6025413881e10/0.21126554976e11 * c(m-2) - 0.59e2/0.68e2 * c(m) - 0.537416663e9/0.7042184992e10 * c(m-1) 0.3e1/0.3136e4 * c(m-3) + 0.27010400129e11/0.345067064608e12 * c(m-2) + 0.234566387291e12/0.690134129216e12 * c(m-1) + 0.12e2/0.17e2 * c(m);
+        ];
+
+        M = M/h;
+        D2 = HI*(-M - c(1)*e_l*d1_l' + c(m)*e_r*d1_r');
+    end
+    D2 = @D2_fun;
+
+
+    % Fourth derivative
+    stencil = [-1/6,2,-13/2, 28/3,-13/2,2,-1/6];
+    diags = -3:3;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U = [
+        0.5762947e7/0.2316384e7 -0.6374287e7/0.1158192e7 0.573947e6/0.165456e6 -0.124637e6/0.289548e6 0.67979e5/0.2316384e7 -0.60257e5/0.1158192e7;
+        -0.6374287e7/0.1158192e7 0.30392389e8/0.2316384e7 -0.2735053e7/0.289548e6 0.273109e6/0.165456e6 0.83767e5/0.1158192e7 0.245549e6/0.2316384e7;
+        0.573947e6/0.165456e6 -0.2735053e7/0.289548e6 0.5266855e7/0.579096e6 -0.1099715e7/0.289548e6 0.869293e6/0.1158192e7 -0.10195e5/0.144774e6;
+        -0.124637e6/0.289548e6 0.273109e6/0.165456e6 -0.1099715e7/0.289548e6 0.3259225e7/0.579096e6 -0.324229e6/0.72387e5 0.1847891e7/0.1158192e7;
+        0.67979e5/0.2316384e7 0.83767e5/0.1158192e7 0.869293e6/0.1158192e7 -0.324229e6/0.72387e5 0.2626501e7/0.330912e6 -0.7115491e7/0.1158192e7;
+        -0.60257e5/0.1158192e7 0.245549e6/0.2316384e7 -0.10195e5/0.144774e6 0.1847891e7/0.1158192e7 -0.7115491e7/0.1158192e7 0.21383077e8/0.2316384e7;
+    ];
+
+    M4(1:6,1:6) = M4_U;
+    M4(m-5:m,m-5:m) = rot90(M4_U, 2);
+    M4 = 1/h^3*M4;
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
+
+
+% Alternatives for variable 2nd derivative
+        % % ALTERNATIVES %%%%%%%%%%%%%
+        % % for i=4:m-3
+        % %     M(i,i-2:i+2)=[-c(i-1)/0.6e1 + c(i-2)/0.8e1 + c(i)/0.8e1 -c(i-2)/0.6e1 - c(i+1)/0.6e1 - c(i-1)/0.2e1 - c(i)/0.2e1 c(i-2)/0.24e2 + 0.5e1/0.6e1 * c(i-1) + 0.5e1/0.6e1 * c(i+1) + c(i+2)/0.24e2 + 0.3e1/0.4e1 * c(i) -c(i-1)/0.6e1 - c(i+2)/0.6e1 - c(i)/0.2e1 - c(i+1)/0.2e1 -c(i+1)/0.6e1 + c(i)/0.8e1 + c(i+2)/0.8e1;];
+        % % end
+        % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % % for i=4:m-3
+        % %     M(i,i-2:i+2)= [
+        % %      c(i-2)/0.8e1 - c(i-1)/0.6e1 + c(i)  /0.8e1                                   ,
+        % %     -c(i-2)/0.6e1 - c(i-1)/0.2e1 - c(i)  /0.2e1 - c(i+1)/0.6e1                  ,
+        % %      c(i-2)/2.4e1 + c(i-1)/1.2e0 + c(i) * 0.3/0.4 + c(i+1)/1.2e0 + c(i+2)/2.4e1 ,
+        % %                      -c(i-1)/0.6e1 - c(i)  /0.2e1 - c(i+1)/0.2e1 - c(i+2)/0.6e1 ,
+        % %                                        c(i)  /0.8e1 - c(i+1)/0.6e1 + c(i+2)/0.8e1 ,
+        % %     ];
+        % % end
+        % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % Mm2 =  c(r-2)/0.8e1 - c(r-1)/0.6e1 + c(r)  /0.8e1                                  ;
+        % Mm1 = -c(r-2)/0.6e1 - c(r-1)/0.2e1 - c(r)  /0.2e1 - c(r+1)/0.6e1                 ;
+        % M0  =  c(r-2)/2.4e1 + c(r-1)/1.2e0 + c(r) * 0.3/0.4 + c(r+1)/1.2e0 + c(r+2)/2.4e1;
+        % Mp1 =                  -c(r-1)/0.6e1 - c(r)  /0.2e1 - c(r+1)/0.2e1 - c(r+2)/0.6e1;
+        % Mp2 =                                    c(r)  /0.8e1 - c(r+1)/0.6e1 + c(r+2)/0.8e1;
+
+        % M(r,:) = spdiags([Mm2 Mm1 M0 Mp1 Mp2],0:2*scheme_radius,length(r),m);
+        % % M(r,:) = spdiags([Mm2 Mm1 M0 Mp1 Mp2],(-2:2)+scheme_radius,M(r,:)); % This is slower
+        % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % % %% Somthing is wrong here!!
+        % % Mm2 =  c(r-2)/0.8e1 - c(r-1)/0.6e1 + c(r)  /0.8e1                                  ;
+        % % Mm1 = -c(r-2)/0.6e1 - c(r-1)/0.2e1 - c(r)  /0.2e1 - c(r+1)/0.6e1                 ;
+        % % M0  =  c(r-2)/2.4e1 + c(r-1)/1.2e0 + c(r) * 0.3/0.4 + c(r+1)/1.2e0 + c(r+2)/2.4e1;
+        % % Mp1 =                  -c(r-1)/0.6e1 - c(r)  /0.2e1 - c(r+1)/0.2e1 - c(r+2)/0.6e1;
+        % % Mp2 =                                    c(r)  /0.8e1 - c(r+1)/0.6e1 + c(r+2)/0.8e1;
+        % % % printSize(M_diag_ind);
+        % % % Mdiags = [Mm2 Mm1 M0  Mp1 Mp2];
+        % % % printSize(Mdiags);
+        % % M(M_diag_ind) = [Mm2 Mm1 M0  Mp1 Mp2]; % This is slightly faster
+        % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+        % % Kan man skriva det som en multiplikation av en 3-dim matris?
+        % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+
+
+
+
+
+
+
+
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/d4_variable_6.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/d4_variable_6.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,158 @@
+function [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = d4_variable_6(m,h)
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+    %%% 6:te ordn. SBP Finita differens         %%%
+    %%% operatorer med diagonal norm            %%%
+    %%% Extension to variable koeff             %%%
+    %%%                                         %%%
+    %%% H           (Normen)                    %%%
+    %%% D1=H^(-1)Q  (approx f?rsta derivatan)   %%%
+    %%% D2          (approx andra derivatan)    %%%
+    %%% D2=HI*(R+C*D*S                          %%%
+    %%%                                         %%%
+    %%% R=-D1'*H*C*D1-RR                        %%%
+    %%%                                         %%%
+    %%% RR ?r dissipation)                      %%%
+    %%% Dissipationen uppbyggd av D4:           %%%
+    %%% DI=D4*B*H*D4                            %%%
+    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+    BP = 9;
+    if(m<2*BP)
+        error(['Operator requires at least ' num2str(2*BP) ' grid points']);
+    end
+
+    % Norm
+    Hv = ones(m,1);
+    Hv(1:6) = [13649/43200,12013/8640,2711/4320,5359/4320,7877/8640, 43801/43200];
+    Hv(m-5:m) = rot90(Hv(1:6),2);
+    Hv = h*Hv;
+    H = spdiag(Hv, 0);
+    HI = spdiag(1./Hv, 0);
+
+
+    % Boundary operators
+    e_l = sparse(m,1);
+    e_l(1) = 1;
+    e_r = rot90(e_l, 2);
+
+    d1_l = sparse(m,1);
+    d1_l(1:5) = [-25/12, 4, -3, 4/3, -1/4]/h;
+    d1_r = -rot90(d1_l, 2);
+
+    d2_l = sparse(m,1);
+    d2_l(1:5) = [0.35e2/0.12e2 -0.26e2/0.3e1 0.19e2/0.2e1 -0.14e2/0.3e1 0.11e2/0.12e2;]/h^2;
+    d2_r = rot90(d2_l, 2);
+
+    d3_l = sparse(m,1);
+    d3_l(1:5) = [-5/2 9 -12 7 -3/2]/h^3;
+    d3_r = -rot90(d3_l, 2);
+
+
+    % First derivtive
+    x1=0.70127127127127;
+
+
+    D1=(1/60*diag(ones(m-3,1),3)-9/60*diag(ones(m-2,1),2)+45/60*diag(ones(m-1,1),1)-45/60*diag(ones(m-1,1),-1)+9/60*diag(ones(m-2,1),-2)-1/60*diag(ones(m-3,1),-3));
+
+
+
+    D1(1:6,1:9)=[-21600/13649, 43200/13649*x1-7624/40947, -172800/13649*x1+ ...
+    	     715489/81894, 259200/13649*x1-187917/13649, -172800/13649* ...
+    	     x1+735635/81894, 43200/13649*x1-89387/40947, 0, 0, 0; ...
+    	     -8640/12013*x1+7624/180195, 0, 86400/12013*x1-57139/12013, ...
+    	     -172800/12013*x1+745733/72078, 129600/12013*x1-91715/12013, ...
+    	     -34560/12013*x1+240569/120130, 0, 0, 0; ...
+             17280/2711*x1-715489/162660, -43200/2711*x1+57139/5422, 0, ...
+             86400/2711*x1-176839/8133, -86400/2711*x1+242111/10844, ...
+             25920/2711*x1-182261/27110, 0, 0, 0; ...
+             -25920/5359*x1+187917/53590, 86400/5359*x1-745733/64308, ...
+             -86400/5359*x1+176839/16077, 0, 43200/5359*x1-165041/32154, ...
+             -17280/5359*x1+710473/321540, 72/5359, 0, 0; ...
+             34560/7877*x1-147127/47262, -129600/7877*x1+91715/7877, ...
+             172800/7877*x1-242111/15754, -86400/7877*x1+165041/23631, ...
+             0, 8640/7877*x1, -1296/7877, 144/7877, 0; ...
+             -43200/43801*x1+89387/131403, 172800/43801*x1-240569/87602,...
+             -259200/43801*x1+182261/43801, 172800/43801*x1-710473/262806, ...
+             -43200/43801*x1, 0, 32400/43801, -6480/43801, 720/43801];
+    D1(m-5:m,m-8:m)=rot90( -D1(1:6,1:9),2);
+    D1=D1/h;
+
+
+    % Second derivative
+    M=sparse(m,m);
+
+    scheme_width = 7;
+    scheme_radius = (scheme_width-1)/2;
+    r = (1+scheme_radius):(m-scheme_radius);
+
+    function D2 = D2_fun(c)
+
+        Mm3 =  c(r-2)/0.40e2 + c(r-1)/0.40e2 - 0.11e2/0.360e3 * c(r-3) - 0.11e2/0.360e3 * c(r);
+        Mm2 =  c(r-3)/0.20e2 - 0.3e1/0.10e2 * c(r-1) + c(r+1)/0.20e2 + 0.7e1/0.40e2 * c(r) + 0.7e1/0.40e2 * c(r-2);
+        Mm1 = -c(r-3)/0.40e2 - 0.3e1/0.10e2 * c(r-2) - 0.3e1/0.10e2 * c(r+1) - c(r+2)/0.40e2 - 0.17e2/0.40e2 * c(r) - 0.17e2/0.40e2 * c(r-1);
+        M0 =  c(r-3)/0.180e3 + c(r-2)/0.8e1 + 0.19e2/0.20e2 * c(r-1) + 0.19e2/0.20e2 * c(r+1) + c(r+2)/0.8e1 + c(r+3)/0.180e3 + 0.101e3/0.180e3 * c(r);
+        Mp1 = -c(r-2)/0.40e2 - 0.3e1/0.10e2 * c(r-1) - 0.3e1/0.10e2 * c(r+2) - c(r+3)/0.40e2 - 0.17e2/0.40e2 * c(r) - 0.17e2/0.40e2 * c(r+1);
+        Mp2 =  c(r-1)/0.20e2 - 0.3e1/0.10e2 * c(r+1) + c(r+3)/0.20e2 + 0.7e1/0.40e2 * c(r) + 0.7e1/0.40e2 * c(r+2);
+        Mp3 =  c(r+1)/0.40e2 + c(r+2)/0.40e2 - 0.11e2/0.360e3 * c(r) - 0.11e2/0.360e3 * c(r+3);
+
+        M(r,:) = spdiags([Mm3 Mm2 Mm1 M0 Mp1 Mp2 Mp3],0:2*scheme_radius,length(r),m);
+
+
+        M(1:9,1:9)=[
+            0.7912667594695582093926295e0 * c(1) + 0.2968472090638000742888467e0 * c(2) + 0.3185519088796429015220016e-2 * c(3) + 0.1632404042590951953384672e-1 * c(4) + 0.3160302244094415087693968e-1 * c(5) + 0.3167964748016105299646518e-1 * c(6) + 0.3148577733947253920469418e-1 * c(7) -0.1016689339350338144430605e1 * c(1) - 0.2845627370491611369031341e-1 * c(3) - 0.4128029838349298819825156e-1 * c(4) - 0.1392281451620140507549866e0 * c(5) - 0.1195777325611201766551392e0 * c(6) - 0.1194267756529333410855186e0 * c(7) 0.7075642937243715046279337e-1 * c(1) - 0.1845476106024151050283847e0 * c(2) - 0.4364163147111892346990101e-1 * c(4) + 0.2432367907207732460874765e0 * c(5) + 0.1582127073537215443965653e0 * c(6) + 0.1602348578364786307613271e0 * c(7) 0.2251991532891353212689574e0 * c(1) - 0.1662748711097054895317080e0 * c(2) + 0.2710530961648671297733465e-1 * c(3) - 0.1916646185968439909125616e0 * c(5) - 0.7684117160199014594442072e-1 * c(6) - 0.8219586949831697575883635e-1 * c(7) -0.5224403464202056316702078e-1 * c(1) + 0.4440063948509876221050939e-1 * c(2) - 0.1023976547309387874453988e-2 * c(3) + 0.7403484645316174090533193e-1 * c(4) + 0.1241625568998496895352046e-1 * c(6) + 0.7188652847892601282652228e-1 * c(5) + 0.1379362997104735503447960e-1 * c(7) -0.1828896813877197352675410e-1 * c(1) + 0.9574633163221758060736592e-2 * c(2) - 0.8105784530576404277872603e-3 * c(3) - 0.7348845587775519698437916e-2 * c(4) + 0.1063601949723906997026904e-1 * c(5) - 0.1315967038382618382356495e-1 * c(6) - 0.2117936478838753524581943e-1 * c(7) 0.1911888563316170927411831e-2 * c(4) - 0.4068130355529149936100229e-1 * c(5) + 0.1319674981073749167009902e-1 * c(6) + 0.2557266518123783676349144e-1 * c(7) 0.1559652871136785763960685e-1 * c(5) - 0.6486184157331537899459796e-2 * c(6) - 0.9110344554036319740147054e-2 * c(7) 0.5593983696629863059347067e-3 * c(6) - 0.1384822535100796372263822e-2 * c(5) + 0.8254241654378100663291154e-3 * c(7);
+            -0.1016689339350338144430605e1 * c(1) - 0.2845627370491611369031341e-1 * c(3) - 0.4128029838349298819825156e-1 * c(4) - 0.1392281451620140507549866e0 * c(5) - 0.1195777325611201766551392e0 * c(6) - 0.1194267756529333410855186e0 * c(7) 0.1306332157111667628555907e1 * c(1) + 0.2542001760457345743492403e0 * c(3) + 0.1043897828092562609502636e0 * c(4) + 0.6672328021032112950919876e0 * c(5) + 0.4681819359722749441073885e0 * c(6) + 0.4676415410195836920069412e0 * c(7) -0.9091410269992464604926176e-1 * c(1) + 0.1103611313171476425250639e0 * c(4) - 0.1290397544997518887000350e1 * c(5) - 0.6639605248735044787146222e0 * c(6) - 0.6615974464005206184151509e0 * c(7) -0.2893557395653431666593814e0 * c(1) - 0.2421320004064592721552708e0 * c(3) + 0.1187670255028031027693374e1 * c(5) + 0.3956598149904136332753521e0 * c(6) + 0.3860048921755800000681479e0 * c(7) 0.6712774475803763988977355e-1 * c(1) + 0.9147192682075630179962131e-2 * c(3) - 0.1872196143003808021730728e0 * c(4) - 0.1319358558853174530078498e0 * c(6) - 0.4871575736811911887376923e0 * c(5) - 0.1047516312275448138054418e0 * c(7) 0.2349927974590068869356781e-1 * c(1) + 0.7240905383565181316381731e-2 * c(3) + 0.1858378996391679448655070e-1 * c(4) - 0.9289616133938676174345208e-1 * c(5) + 0.1223513270418807666970488e0 * c(6) + 0.1113520320436295033894092e0 * c(7) -0.4834791406446907590553793e-2 * c(4) + 0.2310683832687820403062715e0 * c(5) - 0.1080774142196007991746827e0 * c(6) - 0.1181561776427343335410349e0 * c(7) -0.8368141434403455353724691e-1 * c(5) + 0.4093499466767054661591066e-1 * c(6) + 0.4274641967636400692133626e-1 * c(7) -0.3576545132696983143406173e-2 * c(6) + 0.7389399124121078682094445e-2 * c(5) - 0.3812853991424095538688273e-2 * c(7);
+            0.7075642937243715046279337e-1 * c(1) - 0.1845476106024151050283847e0 * c(2) - 0.4364163147111892346990101e-1 * c(4) + 0.2432367907207732460874765e0 * c(5) + 0.1582127073537215443965653e0 * c(6) + 0.1602348578364786307613271e0 * c(7) -0.9091410269992464604926176e-1 * c(1) + 0.1103611313171476425250639e0 * c(4) - 0.1290397544997518887000350e1 * c(5) - 0.6639605248735044787146222e0 * c(6) - 0.6615974464005206184151509e0 * c(7) 0.6327161147136873807796515e-2 * c(1) + 0.1147318200715868527529827e0 * c(2) + 0.1166740554279680007487795e0 * c(4) + 0.2766610808285444037240703e1 * c(5) + 0.1070920689960817104203947e1 * c(6) + 0.1013161391032973057171717e1 * c(7) 0.2013769413884797246646959e-1 * c(1) + 0.1033717994630886401730470e0 * c(2) - 0.2913221621151742724258117e1 * c(5) - 0.8755807343482262259774782e0 * c(6) - 0.6909957183488812426508351e0 * c(7) -0.4671751091575462868310238e-2 * c(1) - 0.2760353365637712827793337e-1 * c(2) - 0.1979290298620869974478871e0 * c(4) + 0.5402985338373433052255418e0 * c(6) + 0.1239177593031911077924537e1 * c(5) + 0.2628038050247358227280031e0 * c(7) -0.1635430866921887819487473e-2 * c(1) - 0.5952475275883259619711594e-2 * c(2) + 0.1964682777744275219350831e-1 * c(4) + 0.3236640012639046600590714e0 * c(5) - 0.4659516693228870973898560e0 * c(6) - 0.2217272720941736859420432e0 * c(7) -0.5111353189352474549563559e-2 * c(4) - 0.5355878163774754346032096e0 * c(5) + 0.3328335104489738933610597e0 * c(6) + 0.2078656591178540157917135e0 * c(7) 0.1824328174134289562208038e0 * c(5) - 0.1059816030196818445908057e0 * c(6) - 0.7645121439374711162999809e-1 * c(7) 0.9209089963443799485648361e-2 * c(6) - 0.1591502818872493167091475e-1 * c(5) + 0.6705938225281132185266388e-2 * c(7);
+            0.2251991532891353212689574e0 * c(1) - 0.1662748711097054895317080e0 * c(2) + 0.2710530961648671297733465e-1 * c(3) - 0.1916646185968439909125616e0 * c(5) - 0.7684117160199014594442072e-1 * c(6) - 0.8219586949831697575883635e-1 * c(7) -0.2893557395653431666593814e0 * c(1) - 0.2421320004064592721552708e0 * c(3) + 0.1187670255028031027693374e1 * c(5) + 0.3956598149904136332753521e0 * c(6) + 0.3860048921755800000681479e0 * c(7) 0.2013769413884797246646959e-1 * c(1) + 0.1033717994630886401730470e0 * c(2) - 0.2913221621151742724258117e1 * c(5) - 0.8755807343482262259774782e0 * c(6) - 0.6909957183488812426508351e0 * c(7) 0.6409299775987186986730499e-1 * c(1) + 0.9313657638804699948929701e-1 * c(2) + 0.2306367624634749229113646e0 * c(3) + 0.3689440308283716620260816e1 * c(5) + 0.1190550338687608873798462e1 * c(6) + 0.5912479546888856519443605e0 * c(7) -0.1486895819265604128572498e-1 * c(1) - 0.2487040599390160764166412e-1 * c(2) - 0.8712928907711754187084757e-2 * c(3) - 0.1263507837371824205693950e1 * c(6) - 0.3058317397843997326920898e0 * c(7) - 0.1470691926045802954795783e1 * c(5) -0.5205147429855955657625694e-2 * c(1) - 0.5363098747528542488971874e-2 * c(2) - 0.6897142765790609546343709e-2 * c(3) - 0.7857524521667450101721993e0 * c(5) + 0.2291148005423734600066709e0 * c(7) + 0.9977064356292750529201981e0 * c(6) 0.6697297488067662265210608e0 * c(5) - 0.5013247356072127938999311e0 * c(6) - 0.1795161243106645437322408e0 * c(7) -0.2022909060111751565150958e0 * c(5) + 0.1453421858063658498587377e0 * c(6) + 0.5694872020480930665635812e-1 * c(7) -0.1200429618441003833696998e-1 * c(6) - 0.4776915669385923841535432e-2 * c(7) + 0.1678121185379596217850541e-1 * c(5);
+            -0.5224403464202056316702078e-1 * c(1) + 0.4440063948509876221050939e-1 * c(2) - 0.1023976547309387874453988e-2 * c(3) + 0.7403484645316174090533193e-1 * c(4) + 0.1241625568998496895352046e-1 * c(6) + 0.7188652847892601282652228e-1 * c(5) + 0.1379362997104735503447960e-1 * c(7) 0.6712774475803763988977355e-1 * c(1) + 0.9147192682075630179962131e-2 * c(3) - 0.1872196143003808021730728e0 * c(4) - 0.1319358558853174530078498e0 * c(6) - 0.4871575736811911887376923e0 * c(5) - 0.1047516312275448138054418e0 * c(7) -0.4671751091575462868310238e-2 * c(1) - 0.2760353365637712827793337e-1 * c(2) - 0.1979290298620869974478871e0 * c(4) + 0.5402985338373433052255418e0 * c(6) + 0.1239177593031911077924537e1 * c(5) + 0.2628038050247358227280031e0 * c(7) -0.1486895819265604128572498e-1 * c(1) - 0.2487040599390160764166412e-1 * c(2) - 0.8712928907711754187084757e-2 * c(3) - 0.1263507837371824205693950e1 * c(6) - 0.3058317397843997326920898e0 * c(7) - 0.1470691926045802954795783e1 * c(5) 0.3449455095910233625229891e-2 * c(1) + 0.6641183499427826101618457e-2 * c(2) + 0.3291545083271862858501887e-3 * c(3) + 0.3357721707576477199985656e0 * c(4) + 0.2096413329579026439044119e1 * c(6) + 0.2317323204183126854954203e0 * c(7) + 0.6107825764368264576481962e-2 * c(8) + 0.7109125850683376695640722e0 * c(5) 0.1207544072304193806052558e-2 * c(1) + 0.1432116665752147607469646e-2 * c(2) + 0.2605582646183255957264249e-3 * c(3) - 0.3332941113251635390801278e-1 * c(4) - 0.2808241697385532683612407e0 * c(7) - 0.2720908083525083608370563e-1 * c(8) + 0.1045865435682921987447929e0 * c(5) - 0.1348436986667115543203552e1 * c(6) 0.8671038084174692625075159e-2 * c(4) + 0.1736073411355428563685818e0 * c(6) + 0.5331362125287625412555844e-1 * c(8) - 0.2424935262404526301801157e0 * c(5) + 0.1569015257678588270609004e0 * c(7) -0.8631683980217122275970376e-1 * c(6) + 0.2698842360470999243492629e-1 * c(7) + 0.8098194147715651085292754e-1 * c(5) - 0.3276463639080639163926118e-1 * c(8) 0.7462059484530855073291365e-2 * c(6) - 0.8121640361668678949573496e-3 * c(7) + 0.5522702088127090209264064e-3 * c(8) - 0.7202165657176696199260422e-2 * c(5);
+            -0.1828896813877197352675410e-1 * c(1) + 0.9574633163221758060736592e-2 * c(2) - 0.8105784530576404277872603e-3 * c(3) - 0.7348845587775519698437916e-2 * c(4) + 0.1063601949723906997026904e-1 * c(5) - 0.1315967038382618382356495e-1 * c(6) - 0.2117936478838753524581943e-1 * c(7) 0.2349927974590068869356781e-1 * c(1) + 0.7240905383565181316381731e-2 * c(3) + 0.1858378996391679448655070e-1 * c(4) - 0.9289616133938676174345208e-1 * c(5) + 0.1223513270418807666970488e0 * c(6) + 0.1113520320436295033894092e0 * c(7) -0.1635430866921887819487473e-2 * c(1) - 0.5952475275883259619711594e-2 * c(2) + 0.1964682777744275219350831e-1 * c(4) + 0.3236640012639046600590714e0 * c(5) - 0.4659516693228870973898560e0 * c(6) - 0.2217272720941736859420432e0 * c(7) -0.5205147429855955657625694e-2 * c(1) - 0.5363098747528542488971874e-2 * c(2) - 0.6897142765790609546343709e-2 * c(3) - 0.7857524521667450101721993e0 * c(5) + 0.2291148005423734600066709e0 * c(7) + 0.9977064356292750529201981e0 * c(6) 0.1207544072304193806052558e-2 * c(1) + 0.1432116665752147607469646e-2 * c(2) + 0.2605582646183255957264249e-3 * c(3) - 0.3332941113251635390801278e-1 * c(4) - 0.2808241697385532683612407e0 * c(7) - 0.2720908083525083608370563e-1 * c(8) + 0.1045865435682921987447929e0 * c(5) - 0.1348436986667115543203552e1 * c(6) 0.4227226173449345042468960e-3 * c(1) + 0.3088241944378964404772302e-3 * c(2) + 0.2062575706647430620228133e-3 * c(3) + 0.3308343404200968256656458e-2 * c(4) + 0.5828047016405001815804837e0 * c(5) + 0.8054174220366215473556835e0 * c(7) + 0.1338363233410033443348225e0 * c(8) + 0.5555555555555555555555556e-2 * c(9) + 0.1190362071861893051132274e1 * c(6) -0.8607044252686413302647675e-3 * c(4) - 0.1748074708673904989293256e0 * c(5) - 0.3132544850115050165022338e0 * c(8) - 0.2500000000000000000000000e-1 * c(9) - 0.3169166305310429271303167e0 * c(7) - 0.6691607091647929161078591e0 * c(6) 0.3354661791693352108660900e-1 * c(5) - 0.3343620022386971405018586e0 * c(7) + 0.5000000000000000000000000e-1 * c(9) + 0.2169790609807602750804271e0 * c(6) + 0.1838363233410033443348225e0 * c(8) 0.2912518476823004642951502e-1 * c(7) + 0.2279091916474916391629437e-1 * c(8) - 0.3068985997518740530511593e-1 * c(6) - 0.1781799513347360596249022e-2 * c(5) - 0.3055555555555555555555556e-1 * c(9);
+            0.1911888563316170927411831e-2 * c(4) - 0.4068130355529149936100229e-1 * c(5) + 0.1319674981073749167009902e-1 * c(6) + 0.2557266518123783676349144e-1 * c(7) -0.4834791406446907590553793e-2 * c(4) + 0.2310683832687820403062715e0 * c(5) - 0.1080774142196007991746827e0 * c(6) - 0.1181561776427343335410349e0 * c(7) -0.5111353189352474549563559e-2 * c(4) - 0.5355878163774754346032096e0 * c(5) + 0.3328335104489738933610597e0 * c(6) + 0.2078656591178540157917135e0 * c(7) 0.6697297488067662265210608e0 * c(5) - 0.5013247356072127938999311e0 * c(6) - 0.1795161243106645437322408e0 * c(7) 0.8671038084174692625075159e-2 * c(4) + 0.1736073411355428563685818e0 * c(6) + 0.5331362125287625412555844e-1 * c(8) - 0.2424935262404526301801157e0 * c(5) + 0.1569015257678588270609004e0 * c(7) -0.8607044252686413302647675e-3 * c(4) - 0.1748074708673904989293256e0 * c(5) - 0.3132544850115050165022338e0 * c(8) - 0.2500000000000000000000000e-1 * c(9) - 0.3169166305310429271303167e0 * c(7) - 0.6691607091647929161078591e0 * c(6) 0.2239223735771599178951297e-3 * c(4) + 0.1275437785430956673825710e0 * c(5) + 0.1011699483929608164601067e1 * c(6) + 0.9698817275172575247533506e0 * c(8) + 0.1250000000000000000000000e0 * c(9) + 0.5555555555555555555555556e-2 * c(10) + 0.4823177543031281500117826e0 * c(7) -0.3784113973033012949863031e-1 * c(5) - 0.2997556885134827361576001e0 * c(6) - 0.3000000000000000000000000e0 * c(9) - 0.2500000000000000000000000e-1 * c(10) - 0.3991486867446821178415359e0 * c(7) - 0.4382544850115050165022338e0 * c(8) 0.4698146218022683933926520e-1 * c(6) - 0.2966863787471237458744416e0 * c(8) + 0.5000000000000000000000000e-1 * c(10) + 0.1716355704146006481727960e0 * c(7) + 0.3069346152296258362380356e-2 * c(5) + 0.1750000000000000000000000e0 * c(9);
+            0.1559652871136785763960685e-1 * c(5) - 0.6486184157331537899459796e-2 * c(6) - 0.9110344554036319740147054e-2 * c(7) -0.8368141434403455353724691e-1 * c(5) + 0.4093499466767054661591066e-1 * c(6) + 0.4274641967636400692133626e-1 * c(7) 0.1824328174134289562208038e0 * c(5) - 0.1059816030196818445908057e0 * c(6) - 0.7645121439374711162999809e-1 * c(7) -0.2022909060111751565150958e0 * c(5) + 0.1453421858063658498587377e0 * c(6) + 0.5694872020480930665635812e-1 * c(7) -0.8631683980217122275970376e-1 * c(6) + 0.2698842360470999243492629e-1 * c(7) + 0.8098194147715651085292754e-1 * c(5) - 0.3276463639080639163926118e-1 * c(8) 0.3354661791693352108660900e-1 * c(5) - 0.3343620022386971405018586e0 * c(7) + 0.5000000000000000000000000e-1 * c(9) + 0.2169790609807602750804271e0 * c(6) + 0.1838363233410033443348225e0 * c(8) -0.3784113973033012949863031e-1 * c(5) - 0.2997556885134827361576001e0 * c(6) - 0.3000000000000000000000000e0 * c(9) - 0.2500000000000000000000000e-1 * c(10) - 0.3991486867446821178415359e0 * c(7) - 0.4382544850115050165022338e0 * c(8) 0.1230328942716804455358698e-1 * c(5) + 0.1183647529645898332481833e0 * c(6) + 0.9410511898227943334189628e0 * c(7) + 0.9500000000000000000000000e0 * c(9) + 0.1250000000000000000000000e0 * c(10) + 0.5555555555555555555555556e-2 * c(11) + 0.5699474344521144554459336e0 * c(8) -0.2308067892671916339568942e-1 * c(6) - 0.2986625053775149497180439e0 * c(7) - 0.3000000000000000000000000e0 * c(10) - 0.2500000000000000000000000e-1 * c(11) - 0.1047734860515050802561078e-2 * c(5) - 0.4272090808352508360837056e0 * c(8) - 0.4250000000000000000000000e0 * c(9);
+            0.5593983696629863059347067e-3 * c(6) - 0.1384822535100796372263822e-2 * c(5) + 0.8254241654378100663291154e-3 * c(7) -0.3576545132696983143406173e-2 * c(6) + 0.7389399124121078682094445e-2 * c(5) - 0.3812853991424095538688273e-2 * c(7) 0.9209089963443799485648361e-2 * c(6) - 0.1591502818872493167091475e-1 * c(5) + 0.6705938225281132185266388e-2 * c(7) -0.1200429618441003833696998e-1 * c(6) - 0.4776915669385923841535432e-2 * c(7) + 0.1678121185379596217850541e-1 * c(5) 0.7462059484530855073291365e-2 * c(6) - 0.8121640361668678949573496e-3 * c(7) + 0.5522702088127090209264064e-3 * c(8) - 0.7202165657176696199260422e-2 * c(5) 0.2912518476823004642951502e-1 * c(7) + 0.2279091916474916391629437e-1 * c(8) - 0.3068985997518740530511593e-1 * c(6) - 0.1781799513347360596249022e-2 * c(5) - 0.3055555555555555555555556e-1 * c(9) 0.4698146218022683933926520e-1 * c(6) - 0.2966863787471237458744416e0 * c(8) + 0.5000000000000000000000000e-1 * c(10) + 0.1716355704146006481727960e0 * c(7) + 0.3069346152296258362380356e-2 * c(5) + 0.1750000000000000000000000e0 * c(9) -0.2308067892671916339568942e-1 * c(6) - 0.2986625053775149497180439e0 * c(7) - 0.3000000000000000000000000e0 * c(10) - 0.2500000000000000000000000e-1 * c(11) - 0.1047734860515050802561078e-2 * c(5) - 0.4272090808352508360837056e0 * c(8) - 0.4250000000000000000000000e0 * c(9) 0.5139370221149109977041877e-2 * c(6) + 0.1247723215009422001393184e0 * c(7) + 0.9505522702088127090209264e0 * c(8) + 0.9500000000000000000000000e0 * c(10) + 0.1250000000000000000000000e0 * c(11) + 0.5555555555555555555555556e-2 * c(12) + 0.9159362465153641826887659e-4 * c(5) + 0.5611111111111111111111111e0 * c(9);
+        ];
+
+        M(m-8:m,m-8:m)=[
+            0.5555555555555555555555556e-2 * c(m-11) + 0.1250000000000000000000000e0 * c(m-10) + 0.9500000000000000000000000e0 * c(m-9) + 0.9505522702088127090209264e0 * c(m-7) + 0.1247205076844361998744053e0 * c(m-6) + 0.5139370221149109977041877e-2 * c(m-5) + 0.5611111111111111111111111e0 * c(m-8) + 0.1434074411575366831819799e-3 * c(m-4) -0.2500000000000000000000000e-1 * c(m-10) - 0.3000000000000000000000000e0 * c(m-9) - 0.2980649679116425253322056e0 * c(m-6) - 0.2308067892671916339568942e-1 * c(m-5) - 0.4250000000000000000000000e0 * c(m-8) - 0.4272090808352508360837056e0 * c(m-7) - 0.1645272326387475188399322e-2 * c(m-4) 0.5000000000000000000000000e-1 * c(m-9) - 0.2966863787471237458744416e0 * c(m-7) + 0.4698146218022683933926520e-1 * c(m-5) + 0.1750000000000000000000000e0 * c(m-8) + 0.1700291833903489463825077e0 * c(m-6) + 0.4675733176547960152668626e-2 * c(m-4) 0.2279091916474916391629437e-1 * c(m-7) + 0.3097763128598982561225538e-1 * c(m-6) - 0.3055555555555555555555556e-1 * c(m-8) - 0.3068985997518740530511593e-1 * c(m-5) - 0.3634246031107139778989373e-2 * c(m-4) 0.5522702088127090209264064e-3 * c(m-7) - 0.3265435411305071914756373e-2 * c(m-6) + 0.7462059484530855073291365e-2 * c(m-5) - 0.4748894282038492179461399e-2 * c(m-4) 0.6272075574042975468177820e-3 * c(m-6) - 0.1200429618441003833696998e-1 * c(m-5) + 0.1137708862700574079015220e-1 * c(m-4) 0.9209089963443799485648361e-2 * c(m-5) - 0.3129629392354775191148163e-3 * c(m-6) - 0.8896127024208321966533544e-2 * c(m-4) -0.3576545132696983143406173e-2 * c(m-5) + 0.4335019854436220306755673e-3 * c(m-6) + 0.3143043147253361112730605e-2 * c(m-4) 0.5593983696629863059347067e-3 * c(m-5) - 0.1446656414398166805849327e-3 * c(m-6) - 0.4147327282231696253497740e-3 * c(m-4);
+            -0.2500000000000000000000000e-1 * c(m-10) - 0.3000000000000000000000000e0 * c(m-9) - 0.2980649679116425253322056e0 * c(m-6) - 0.2308067892671916339568942e-1 * c(m-5) - 0.4250000000000000000000000e0 * c(m-8) - 0.4272090808352508360837056e0 * c(m-7) - 0.1645272326387475188399322e-2 * c(m-4) 0.5555555555555555555555556e-2 * c(m-10) + 0.1250000000000000000000000e0 * c(m-9) + 0.9500000000000000000000000e0 * c(m-8) + 0.9341601509609901526962449e0 * c(m-6) + 0.1183647529645898332481833e0 * c(m-5) + 0.1919432828897222527630486e-1 * c(m-4) + 0.5699474344521144554459336e0 * c(m-7) -0.2500000000000000000000000e-1 * c(m-9) - 0.3000000000000000000000000e0 * c(m-8) - 0.2997556885134827361576001e0 * c(m-5) - 0.5636663150858098975790317e-1 * c(m-4) - 0.4382544850115050165022338e0 * c(m-7) - 0.3806231949664312575822630e0 * c(m-6) 0.5000000000000000000000000e-1 * c(m-8) - 0.3557251496099816106154206e0 * c(m-6) + 0.5490976528821799120017102e-1 * c(m-4) + 0.1838363233410033443348225e0 * c(m-7) + 0.2169790609807602750804271e0 * c(m-5) 0.5528052133944605740009217e-1 * c(m-6) - 0.8631683980217122275970376e-1 * c(m-5) - 0.3276463639080639163926118e-1 * c(m-7) + 0.5268984374242044588776166e-1 * c(m-4) -0.5373770512016897565958305e-2 * c(m-6) + 0.1453421858063658498587377e0 * c(m-5) - 0.1399684152943489522927794e0 * c(m-4) -0.1059816030196818445908057e0 * c(m-5) + 0.1014880675788250237247178e0 * c(m-4) + 0.4493535440856820866087846e-2 * c(m-6) 0.4093499466767054661591066e-1 * c(m-5) - 0.3471075437892810033585296e-1 * c(m-4) - 0.6224240288742446280057699e-2 * c(m-6) -0.6486184157331537899459796e-2 * c(m-5) + 0.4409068609809831485979484e-2 * c(m-4) + 0.2077115547521706413480312e-2 * c(m-6);
+            0.5000000000000000000000000e-1 * c(m-9) - 0.2966863787471237458744416e0 * c(m-7) + 0.4698146218022683933926520e-1 * c(m-5) + 0.1750000000000000000000000e0 * c(m-8) + 0.1700291833903489463825077e0 * c(m-6) + 0.4675733176547960152668626e-2 * c(m-4) -0.2500000000000000000000000e-1 * c(m-9) - 0.3000000000000000000000000e0 * c(m-8) - 0.2997556885134827361576001e0 * c(m-5) - 0.5636663150858098975790317e-1 * c(m-4) - 0.4382544850115050165022338e0 * c(m-7) - 0.3806231949664312575822630e0 * c(m-6) 0.5555555555555555555555556e-2 * c(m-9) + 0.1250000000000000000000000e0 * c(m-8) + 0.9698817275172575247533506e0 * c(m-7) + 0.1011699483929608164601067e1 * c(m-5) + 0.1773466968705924819112984e0 * c(m-4) + 0.2239223735771599178951297e-3 * c(m-3) + 0.4325148359756313354830552e0 * c(m-6) -0.2500000000000000000000000e-1 * c(m-8) - 0.3132544850115050165022338e0 * c(m-7) - 0.2322389872063761557916742e0 * c(m-4) - 0.8607044252686413302647675e-3 * c(m-3) - 0.2594851141920572702679681e0 * c(m-6) - 0.6691607091647929161078591e0 * c(m-5) 0.5331362125287625412555844e-1 * c(m-7) + 0.1736073411355428563685818e0 * c(m-5) + 0.8671038084174692625075159e-2 * c(m-3) + 0.8084259844422177692569663e-1 * c(m-6) - 0.1664345989168155800449120e0 * c(m-4) -0.5013247356072127938999311e0 * c(m-5) + 0.5021853752328231128475915e0 * c(m-4) - 0.1197175073672143005877150e-1 * c(m-6) 0.3328335104489738933610597e0 * c(m-5) - 0.3179803804558436283847901e0 * c(m-4) - 0.5111353189352474549563559e-2 * c(m-3) - 0.9741776803777790426705996e-2 * c(m-6) -0.1080774142196007991746827e0 * c(m-5) + 0.9941834083648937298100811e-1 * c(m-4) - 0.4834791406446907590553793e-2 * c(m-3) + 0.1349386478955833378422842e-1 * c(m-6) 0.1319674981073749167009902e-1 * c(m-5) - 0.1060554802883657391328704e-1 * c(m-4) + 0.1911888563316170927411831e-2 * c(m-3) - 0.4503090345217088684223814e-2 * c(m-6);
+            0.2279091916474916391629437e-1 * c(m-7) + 0.3097763128598982561225538e-1 * c(m-6) - 0.3055555555555555555555556e-1 * c(m-8) - 0.3068985997518740530511593e-1 * c(m-5) - 0.3634246031107139778989373e-2 * c(m-4) 0.5000000000000000000000000e-1 * c(m-8) - 0.3557251496099816106154206e0 * c(m-6) + 0.5490976528821799120017102e-1 * c(m-4) + 0.1838363233410033443348225e0 * c(m-7) + 0.2169790609807602750804271e0 * c(m-5) -0.2500000000000000000000000e-1 * c(m-8) - 0.3132544850115050165022338e0 * c(m-7) - 0.2322389872063761557916742e0 * c(m-4) - 0.8607044252686413302647675e-3 * c(m-3) - 0.2594851141920572702679681e0 * c(m-6) - 0.6691607091647929161078591e0 * c(m-5) 0.5555555555555555555555556e-2 * c(m-8) + 0.1338363233410033443348225e0 * c(m-7) + 0.7391887916719206077121040e0 * c(m-6) + 0.6490333320052011212240632e0 * c(m-4) + 0.3308343404200968256656458e-2 * c(m-3) + 0.2062575706647430620228133e-3 * c(m-2) + 0.3088241944378964404772302e-3 * c(m-1) + 0.4227226173449345042468960e-3 * c(m) + 0.1190362071861893051132274e1 * c(m-5) -0.2720908083525083608370563e-1 * c(m-7) - 0.1931148612480615118957263e0 * c(m-6) - 0.3332941113251635390801278e-1 * c(m-3) + 0.2605582646183255957264249e-3 * c(m-2) + 0.1432116665752147607469646e-2 * c(m-1) + 0.1207544072304193806052558e-2 * c(m) - 0.1348436986667115543203552e1 * c(m-5) + 0.1687723507780044227927853e-1 * c(m-4) 0.3590669644811151307464697e-1 * c(m-6) - 0.5925443480724830632401754e0 * c(m-4) - 0.6897142765790609546343709e-2 * c(m-2) - 0.5363098747528542488971874e-2 * c(m-1) - 0.5205147429855955657625694e-2 * c(m) + 0.9977064356292750529201981e0 * c(m-5) 0.7272438906214475928744770e-1 * c(m-4) + 0.1964682777744275219350831e-1 * c(m-3) - 0.5952475275883259619711594e-2 * c(m-1) - 0.1635430866921887819487473e-2 * c(m) + 0.2921234010758621482958052e-1 * c(m-6) - 0.4659516693228870973898560e0 * c(m-5) 0.5891947149681041048896399e-1 * c(m-4) + 0.1858378996391679448655070e-1 * c(m-3) + 0.7240905383565181316381731e-2 * c(m-2) + 0.2349927974590068869356781e-1 * c(m) - 0.4046360079256766884300687e-1 * c(m-6) + 0.1223513270418807666970488e0 * c(m-5) -0.2404661162020836566908542e-1 * c(m-4) - 0.7348845587775519698437916e-2 * c(m-3) - 0.8105784530576404277872603e-3 * c(m-2) + 0.9574633163221758060736592e-2 * c(m-1) - 0.1828896813877197352675410e-1 * c(m) + 0.1350326632905990039353503e-1 * c(m-6) - 0.1315967038382618382356495e-1 * c(m-5);
+            0.5522702088127090209264064e-3 * c(m-7) - 0.3265435411305071914756373e-2 * c(m-6) + 0.7462059484530855073291365e-2 * c(m-5) - 0.4748894282038492179461399e-2 * c(m-4) 0.5528052133944605740009217e-1 * c(m-6) - 0.8631683980217122275970376e-1 * c(m-5) - 0.3276463639080639163926118e-1 * c(m-7) + 0.5268984374242044588776166e-1 * c(m-4) 0.5331362125287625412555844e-1 * c(m-7) + 0.1736073411355428563685818e0 * c(m-5) + 0.8671038084174692625075159e-2 * c(m-3) + 0.8084259844422177692569663e-1 * c(m-6) - 0.1664345989168155800449120e0 * c(m-4) -0.2720908083525083608370563e-1 * c(m-7) - 0.1931148612480615118957263e0 * c(m-6) - 0.3332941113251635390801278e-1 * c(m-3) + 0.2605582646183255957264249e-3 * c(m-2) + 0.1432116665752147607469646e-2 * c(m-1) + 0.1207544072304193806052558e-2 * c(m) - 0.1348436986667115543203552e1 * c(m-5) + 0.1687723507780044227927853e-1 * c(m-4) 0.6107825764368264576481962e-2 * c(m-7) + 0.1155752633643216628010304e0 * c(m-6) + 0.2096413329579026439044119e1 * c(m-5) + 0.3357721707576477199985656e0 * c(m-3) + 0.3291545083271862858501887e-3 * c(m-2) + 0.6641183499427826101618457e-2 * c(m-1) + 0.3449455095910233625229891e-2 * c(m) + 0.8270696421223286922584620e0 * c(m-4) -0.4995827370863505253765970e-1 * c(m-6) - 0.1263507837371824205693950e1 * c(m-5) - 0.8712928907711754187084757e-2 * c(m-2) - 0.2487040599390160764166412e-1 * c(m-1) - 0.1486895819265604128572498e-1 * c(m) - 0.1726565392121567634950213e1 * c(m-4) 0.5402985338373433052255418e0 * c(m-5) - 0.1979290298620869974478871e0 * c(m-3) - 0.2760353365637712827793337e-1 * c(m-1) - 0.4671751091575462868310238e-2 * c(m) - 0.6952587985456154591014641e-1 * c(m-6) + 0.1571507277911208446562686e1 * c(m-4) -0.1319358558853174530078498e0 * c(m-5) - 0.1872196143003808021730728e0 * c(m-3) + 0.9147192682075630179962131e-2 * c(m-2) + 0.6712774475803763988977355e-1 * c(m) + 0.9630407686703666967100804e-1 * c(m-6) - 0.6882132817757726722141421e0 * c(m-4) 0.1241625568998496895352046e-1 * c(m-5) + 0.7403484645316174090533193e-1 * c(m-3) - 0.1023976547309387874453988e-2 * c(m-2) + 0.4440063948509876221050939e-1 * c(m-1) - 0.5224403464202056316702078e-1 * c(m) - 0.3213800979246298453953842e-1 * c(m-6) + 0.1178181682424363524005403e0 * c(m-4);
+            0.6272075574042975468177820e-3 * c(m-6) - 0.1200429618441003833696998e-1 * c(m-5) + 0.1137708862700574079015220e-1 * c(m-4) -0.5373770512016897565958305e-2 * c(m-6) + 0.1453421858063658498587377e0 * c(m-5) - 0.1399684152943489522927794e0 * c(m-4) -0.5013247356072127938999311e0 * c(m-5) + 0.5021853752328231128475915e0 * c(m-4) - 0.1197175073672143005877150e-1 * c(m-6) 0.3590669644811151307464697e-1 * c(m-6) - 0.5925443480724830632401754e0 * c(m-4) - 0.6897142765790609546343709e-2 * c(m-2) - 0.5363098747528542488971874e-2 * c(m-1) - 0.5205147429855955657625694e-2 * c(m) + 0.9977064356292750529201981e0 * c(m-5) -0.4995827370863505253765970e-1 * c(m-6) - 0.1263507837371824205693950e1 * c(m-5) - 0.8712928907711754187084757e-2 * c(m-2) - 0.2487040599390160764166412e-1 * c(m-1) - 0.1486895819265604128572498e-1 * c(m) - 0.1726565392121567634950213e1 * c(m-4) 0.2760393423824887721078848e-1 * c(m-6) + 0.1190550338687608873798462e1 * c(m-5) + 0.4253084328734353394994388e1 * c(m-4) + 0.2306367624634749229113646e0 * c(m-2) + 0.9313657638804699948929701e-1 * c(m-1) + 0.6409299775987186986730499e-1 * c(m) -0.8755807343482262259774782e0 * c(m-5) - 0.3645285178085761821545207e1 * c(m-4) + 0.1033717994630886401730470e0 * c(m-1) + 0.2013769413884797246646959e-1 * c(m) + 0.4106783858513785463625543e-1 * c(m-6) 0.3956598149904136332753521e0 * c(m-5) + 0.1630560443616104907615866e1 * c(m-4) - 0.2421320004064592721552708e0 * c(m-2) - 0.2893557395653431666593814e0 * c(m) - 0.5688529641249387985434413e-1 * c(m-6) -0.7684117160199014594442072e-1 * c(m-5) - 0.2928439026361256842196229e0 * c(m-4) + 0.2710530961648671297733465e-1 * c(m-2) - 0.1662748711097054895317080e0 * c(m-1) + 0.2251991532891353212689574e0 * c(m) + 0.1898341454096471754822498e-1 * c(m-6);
+            0.9209089963443799485648361e-2 * c(m-5) - 0.3129629392354775191148163e-3 * c(m-6) - 0.8896127024208321966533544e-2 * c(m-4) -0.1059816030196818445908057e0 * c(m-5) + 0.1014880675788250237247178e0 * c(m-4) + 0.4493535440856820866087846e-2 * c(m-6) 0.3328335104489738933610597e0 * c(m-5) - 0.3179803804558436283847901e0 * c(m-4) - 0.5111353189352474549563559e-2 * c(m-3) - 0.9741776803777790426705996e-2 * c(m-6) 0.7272438906214475928744770e-1 * c(m-4) + 0.1964682777744275219350831e-1 * c(m-3) - 0.5952475275883259619711594e-2 * c(m-1) - 0.1635430866921887819487473e-2 * c(m) + 0.2921234010758621482958052e-1 * c(m-6) - 0.4659516693228870973898560e0 * c(m-5) 0.5402985338373433052255418e0 * c(m-5) - 0.1979290298620869974478871e0 * c(m-3) - 0.2760353365637712827793337e-1 * c(m-1) - 0.4671751091575462868310238e-2 * c(m) - 0.6952587985456154591014641e-1 * c(m-6) + 0.1571507277911208446562686e1 * c(m-4) -0.8755807343482262259774782e0 * c(m-5) - 0.3645285178085761821545207e1 * c(m-4) + 0.1033717994630886401730470e0 * c(m-1) + 0.2013769413884797246646959e-1 * c(m) + 0.4106783858513785463625543e-1 * c(m-6) 0.1070920689960817104203947e1 * c(m-5) + 0.3717418466925056542408153e1 * c(m-4) + 0.1166740554279680007487795e0 * c(m-3) + 0.1147318200715868527529827e0 * c(m-1) + 0.6327161147136873807796515e-2 * c(m) + 0.6235373239336055200426697e-1 * c(m-6) -0.6639605248735044787146222e0 * c(m-5) - 0.1865625445986772763641423e1 * c(m-4) + 0.1103611313171476425250639e0 * c(m-3) - 0.9091410269992464604926176e-1 * c(m) - 0.8636954541126674177407762e-1 * c(m-6) 0.1582127073537215443965653e0 * c(m-5) + 0.3746489300753517635549495e0 * c(m-4) - 0.4364163147111892346990101e-1 * c(m-3) - 0.1845476106024151050283847e0 * c(m-1) + 0.7075642937243715046279337e-1 * c(m) + 0.2882271848190011329385407e-1 * c(m-6);
+            -0.3576545132696983143406173e-2 * c(m-5) + 0.4335019854436220306755673e-3 * c(m-6) + 0.3143043147253361112730605e-2 * c(m-4) 0.4093499466767054661591066e-1 * c(m-5) - 0.3471075437892810033585296e-1 * c(m-4) - 0.6224240288742446280057699e-2 * c(m-6) -0.1080774142196007991746827e0 * c(m-5) + 0.9941834083648937298100811e-1 * c(m-4) - 0.4834791406446907590553793e-2 * c(m-3) + 0.1349386478955833378422842e-1 * c(m-6) 0.5891947149681041048896399e-1 * c(m-4) + 0.1858378996391679448655070e-1 * c(m-3) + 0.7240905383565181316381731e-2 * c(m-2) + 0.2349927974590068869356781e-1 * c(m) - 0.4046360079256766884300687e-1 * c(m-6) + 0.1223513270418807666970488e0 * c(m-5) -0.1319358558853174530078498e0 * c(m-5) - 0.1872196143003808021730728e0 * c(m-3) + 0.9147192682075630179962131e-2 * c(m-2) + 0.6712774475803763988977355e-1 * c(m) + 0.9630407686703666967100804e-1 * c(m-6) - 0.6882132817757726722141421e0 * c(m-4) 0.3956598149904136332753521e0 * c(m-5) + 0.1630560443616104907615866e1 * c(m-4) - 0.2421320004064592721552708e0 * c(m-2) - 0.2893557395653431666593814e0 * c(m) - 0.5688529641249387985434413e-1 * c(m-6) -0.6639605248735044787146222e0 * c(m-5) - 0.1865625445986772763641423e1 * c(m-4) + 0.1103611313171476425250639e0 * c(m-3) - 0.9091410269992464604926176e-1 * c(m) - 0.8636954541126674177407762e-1 * c(m-6) 0.4681819359722749441073885e0 * c(m-5) + 0.1015239189167790053447110e1 * c(m-4) + 0.1043897828092562609502636e0 * c(m-3) + 0.2542001760457345743492403e0 * c(m-2) + 0.1306332157111667628555907e1 * c(m) + 0.1196351539550049336518187e0 * c(m-6) -0.1195777325611201766551392e0 * c(m-5) - 0.2187310061229745694542609e0 * c(m-4) - 0.4128029838349298819825156e-1 * c(m-3) - 0.2845627370491611369031341e-1 * c(m-2) - 0.1016689339350338144430605e1 * c(m) - 0.3992391469197282238624438e-1 * c(m-6);
+            0.5593983696629863059347067e-3 * c(m-5) - 0.1446656414398166805849327e-3 * c(m-6) - 0.4147327282231696253497740e-3 * c(m-4) -0.6486184157331537899459796e-2 * c(m-5) + 0.4409068609809831485979484e-2 * c(m-4) + 0.2077115547521706413480312e-2 * c(m-6) 0.1319674981073749167009902e-1 * c(m-5) - 0.1060554802883657391328704e-1 * c(m-4) + 0.1911888563316170927411831e-2 * c(m-3) - 0.4503090345217088684223814e-2 * c(m-6) -0.2404661162020836566908542e-1 * c(m-4) - 0.7348845587775519698437916e-2 * c(m-3) - 0.8105784530576404277872603e-3 * c(m-2) + 0.9574633163221758060736592e-2 * c(m-1) - 0.1828896813877197352675410e-1 * c(m) + 0.1350326632905990039353503e-1 * c(m-6) - 0.1315967038382618382356495e-1 * c(m-5) 0.1241625568998496895352046e-1 * c(m-5) + 0.7403484645316174090533193e-1 * c(m-3) - 0.1023976547309387874453988e-2 * c(m-2) + 0.4440063948509876221050939e-1 * c(m-1) - 0.5224403464202056316702078e-1 * c(m) - 0.3213800979246298453953842e-1 * c(m-6) + 0.1178181682424363524005403e0 * c(m-4) -0.7684117160199014594442072e-1 * c(m-5) - 0.2928439026361256842196229e0 * c(m-4) + 0.2710530961648671297733465e-1 * c(m-2) - 0.1662748711097054895317080e0 * c(m-1) + 0.2251991532891353212689574e0 * c(m) + 0.1898341454096471754822498e-1 * c(m-6) 0.1582127073537215443965653e0 * c(m-5) + 0.3746489300753517635549495e0 * c(m-4) - 0.4364163147111892346990101e-1 * c(m-3) - 0.1845476106024151050283847e0 * c(m-1) + 0.7075642937243715046279337e-1 * c(m) + 0.2882271848190011329385407e-1 * c(m-6) -0.1195777325611201766551392e0 * c(m-5) - 0.2187310061229745694542609e0 * c(m-4) - 0.4128029838349298819825156e-1 * c(m-3) - 0.2845627370491611369031341e-1 * c(m-2) - 0.1016689339350338144430605e1 * c(m) - 0.3992391469197282238624438e-1 * c(m-6) 0.3167964748016105299646518e-1 * c(m-5) + 0.4976563420877041544013670e-1 * c(m-4) + 0.1632404042590951953384672e-1 * c(m-3) + 0.3185519088796429015220016e-2 * c(m-2) + 0.2968472090638000742888467e0 * c(m-1) + 0.7912667594695582093926295e0 * c(m) + 0.1332316557164627464149716e-1 * c(m-6);
+        ];
+
+        M(5,10)=M(10,5);
+        M(m-4,m-9)=M(m-9,m-4);
+
+        M=M/h;
+
+        D2 = HI*(-M - c(1)*e_l*d1_l' + c(m)*e_r*d1_r');
+    end
+    D2 = @D2_fun;
+
+    % Fourth derivative, 1th order accurate at first 8 boundary points (still
+    % yield 5th order convergence if stable: for example u_tt=-u_xxxx
+    stencil = [7/240, -2/5, 169/60, -122/15, 91/8, -122/15, 169/60, -2/5, 7/240];
+    diags = -4:4;
+    M4 = stripeMatrix(stencil, diags, m);
+
+    M4_U = [
+        0.1394226315049e13/0.367201486080e12 -0.1137054563243e13/0.114750464400e12 0.16614189027367e14/0.1836007430400e13 -0.1104821700277e13/0.306001238400e12 0.1355771086763e13/0.1836007430400e13 -0.27818686453e11/0.459001857600e12 -0.40671054239e11/0.1836007430400e13 0.5442887371e10/0.306001238400e12;
+        -0.1137054563243e13/0.114750464400e12 0.70616795535409e14/0.2570410402560e13 -0.173266854731041e15/0.6426026006400e13 0.28938615291031e14/0.2570410402560e13 -0.146167361863e12/0.71400288960e11 0.2793470836571e13/0.12852052012800e14 0.6219558097e10/0.428401733760e12 -0.7313844559e10/0.166909766400e12;
+        0.16614189027367e14/0.1836007430400e13 -0.173266854731041e15/0.6426026006400e13 0.378613061504779e15/0.12852052012800e14 -0.9117069604217e13/0.642602600640e12 0.632177582849e12/0.233673672960e12 -0.1057776382577e13/0.6426026006400e13 0.443019868399e12/0.4284017337600e13 -0.3707981e7/0.2318191200e10;
+        -0.1104821700277e13/0.306001238400e12 0.28938615291031e14/0.2570410402560e13 -0.9117069604217e13/0.642602600640e12 0.5029150721885e13/0.514082080512e12 -0.5209119714341e13/0.1285205201280e13 0.12235427457469e14/0.12852052012800e14 -0.13731270505e11/0.64260260064e11 0.2933596129e10/0.40800165120e11;
+        0.1355771086763e13/0.1836007430400e13 -0.146167361863e12/0.71400288960e11 0.632177582849e12/0.233673672960e12 -0.5209119714341e13/0.1285205201280e13 0.14871726798559e14/0.2570410402560e13 -0.7504337615347e13/0.1606506501600e13 0.310830296467e12/0.171360693504e12 -0.55284274391e11/0.183600743040e12;
+        -0.27818686453e11/0.459001857600e12 0.2793470836571e13/0.12852052012800e14 -0.1057776382577e13/0.6426026006400e13 0.12235427457469e14/0.12852052012800e14 -0.7504337615347e13/0.1606506501600e13 0.106318657014853e15/0.12852052012800e14 -0.14432772918527e14/0.2142008668800e13 0.58102695589e11/0.22666758400e11;
+        -0.40671054239e11/0.1836007430400e13 0.6219558097e10/0.428401733760e12 0.443019868399e12/0.4284017337600e13 -0.13731270505e11/0.64260260064e11 0.310830296467e12/0.171360693504e12 -0.14432772918527e14/0.2142008668800e13 0.27102479467823e14/0.2570410402560e13 -0.1216032192203e13/0.153000619200e12;
+        0.5442887371e10/0.306001238400e12 -0.7313844559e10/0.166909766400e12 -0.3707981e7/0.2318191200e10 0.2933596129e10/0.40800165120e11 -0.55284274391e11/0.183600743040e12 0.58102695589e11/0.22666758400e11 -0.1216032192203e13/0.153000619200e12 0.20799922829107e14/0.1836007430400e13;
+    ];
+
+    M4(1:8,1:8) = M4_U;
+    M4(m-7:m,m-7:m) = rot90(  M4_U ,2 );
+    M4 = M4/h^3;
+
+
+
+    D4=HI*(M4 - e_l*d3_l'+e_r*d3_r' + d1_l*d2_l'-d1_r*d2_r');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_2to2_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_2to2_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,47 @@
+function [IC2F,IF2C,Hc,Hf] = IntOp_orders_2to2_ratio2to1(mc,hc,ACC)
+
+% ACC is a string.
+% ACC = 'C2F' creates IC2F with one order of accuracy higher than IF2C.
+% ACC = 'F2C' creates IF2C with one order of accuracy higher than IC2F.
+ratio = 2;
+mf = ratio*mc-1; 
+hf = hc/ratio;
+
+switch ACC
+    case 'F2C'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_2to2_ratio_2to1_accC2F1_accF2C2;
+    case 'C2F'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_2to2_ratio_2to1_accC2F2_accF2C1;
+end
+
+stencil_width = length(stencil_F2C);
+stencil_hw = (stencil_width-1)/2;
+[BC_rows,BC_cols] = size(BC_F2C);
+
+%%% Norm matrices %%%
+Hc = speye(mc,mc);
+HcUm = length(HcU); 
+Hc(1:HcUm,1:HcUm) = spdiags(HcU',0,HcUm,HcUm);
+Hc(mc-HcUm+1:mc,mc-HcUm+1:mc) = spdiags(rot90(HcU',2),0,HcUm,HcUm);
+Hc = Hc*hc;
+
+Hf = speye(mf,mf);
+HfUm = length(HfU);
+Hf(1:HfUm,1:HfUm) = spdiags(HfU',0,HfUm,HfUm);
+Hf(mf-length(HfU)+1:mf,mf-length(HfU)+1:mf) = spdiags(rot90(HfU',2),0,HfUm,HfUm);
+Hf = Hf*hf;
+%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IF2C from stencil and BC
+IF2C = sparse(mc,mf);
+for i = BC_rows+1 : mc-BC_rows
+    IF2C(i,ratio*i-1+(-stencil_hw:stencil_hw)) = stencil_F2C; %#ok<SPRIX>
+end
+IF2C(1:BC_rows,1:BC_cols) = BC_F2C;
+IF2C(end-BC_rows+1:end,end-BC_cols+1:end) = rot90(BC_F2C,2);
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IC2F using symmetry condition %%%%
+IC2F = Hf\IF2C.'*Hc;
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_2to2_ratio_2to1_accC2F1_accF2C2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_2to2_ratio_2to1_accC2F1_accF2C2.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,17 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_2to2_ratio_2to1_accC2F1_accF2C2
+%INT_ORDERS_2TO2_RATIO_2TO1_ACCC2F1_ACCF2C2_STENCIL_5_BC_2_5
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_2TO2_RATIO_2TO1_ACCC2F1_ACCF2C2_STENCIL_5_BC_2_5
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:36:07
+
+stencil_F2C = [-1.0./8.0,1.0./4.0,3.0./4.0,1.0./4.0,-1.0./8.0];
+if nargout > 1
+    BC_F2C = reshape([6.288191560529559e-1,-6.440957802647795e-2,6.855471317807184e-1,1.572264341096408e-1,-2.438028498638558e-1,7.469014249319279e-1,-8.431231982626708e-2,2.921561599131335e-1,1.374888185644862e-2,-1.318744409282243e-1],[2,5]);
+end
+if nargout > 2
+    HcU = 1.0./2.0;
+end
+if nargout > 3
+    HfU = 1.0./2.0;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_2to2_ratio_2to1_accC2F2_accF2C1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_2to2_ratio_2to1_accC2F2_accF2C1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,17 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_2to2_ratio_2to1_accC2F2_accF2C1
+%INT_ORDERS_2TO2_RATIO_2TO1_ACCC2F2_ACCF2C1_STENCIL_5_BC_1_3
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_2TO2_RATIO_2TO1_ACCC2F2_ACCF2C1_STENCIL_5_BC_1_3
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:36:08
+
+stencil_F2C = [1.0./4.0,1.0./2.0,1.0./4.0];
+if nargout > 1
+    BC_F2C = [1.0./2.0,1.0./2.0];
+end
+if nargout > 2
+    HcU = 1.0./2.0;
+end
+if nargout > 3
+    HfU = 1.0./2.0;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_4to4_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_4to4_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,47 @@
+function [IC2F,IF2C,Hc,Hf] = IntOp_orders_4to4_ratio2to1(mc,hc,ACC)
+
+% ACC is a string.
+% ACC = 'C2F' creates IC2F with one order of accuracy higher than IF2C.
+% ACC = 'F2C' creates IF2C with one order of accuracy higher than IC2F.
+ratio = 2;
+mf = ratio*mc-1; 
+hf = hc/ratio;
+
+switch ACC
+    case 'F2C'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_4to4_ratio_2to1_accC2F2_accF2C3;
+    case 'C2F'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_4to4_ratio_2to1_accC2F3_accF2C2;
+end
+
+stencil_width = length(stencil_F2C);
+stencil_hw = (stencil_width-1)/2;
+[BC_rows,BC_cols] = size(BC_F2C);
+
+%%% Norm matrices %%%
+Hc = speye(mc,mc);
+HcUm = length(HcU); 
+Hc(1:HcUm,1:HcUm) = spdiags(HcU',0,HcUm,HcUm);
+Hc(mc-HcUm+1:mc,mc-HcUm+1:mc) = spdiags(rot90(HcU',2),0,HcUm,HcUm);
+Hc = Hc*hc;
+
+Hf = speye(mf,mf);
+HfUm = length(HfU);
+Hf(1:HfUm,1:HfUm) = spdiags(HfU',0,HfUm,HfUm);
+Hf(mf-length(HfU)+1:mf,mf-length(HfU)+1:mf) = spdiags(rot90(HfU',2),0,HfUm,HfUm);
+Hf = Hf*hf;
+%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IF2C from stencil and BC
+IF2C = sparse(mc,mf);
+for i = BC_rows+1 : mc-BC_rows
+    IF2C(i,ratio*i-1+(-stencil_hw:stencil_hw)) = stencil_F2C; %#ok<SPRIX>
+end
+IF2C(1:BC_rows,1:BC_cols) = BC_F2C;
+IF2C(end-BC_rows+1:end,end-BC_cols+1:end) = rot90(BC_F2C,2);
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IC2F using symmetry condition %%%%
+IC2F = Hf\IF2C.'*Hc;
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_4to4_ratio_2to1_accC2F2_accF2C3.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_4to4_ratio_2to1_accC2F2_accF2C3.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,18 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_4to4_ratio_2to1_accC2F2_accF2C3
+%INT_ORDERS_4TO4_RATIO_2TO1_ACCC2F2_ACCF2C3_STENCIL_9_BC_3_11
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_4TO4_RATIO_2TO1_ACCC2F2_ACCF2C3_STENCIL_9_BC_3_11
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:36:01
+
+stencil_F2C = [7.0./2.56e2,-1.0./3.2e1,-7.0./6.4e1,9.0./3.2e1,8.5e1./1.28e2,9.0./3.2e1,-7.0./6.4e1,-1.0./3.2e1,7.0./2.56e2];
+if nargout > 1
+    BC_F2C = reshape([7.523257802630956e-2,2.447812262221267e-1,-1.679313063616916e-1,1.290510950666589,6.315723344677289e-3,1.67178747937954e-1,1.982667903557025,-7.554383893379468e-1,7.215271362899867e-1,-2.820478831383137,1.807034411305536,-7.589683751979843e-1,-7.685973268458095e-1,3.965751544535173e-1,4.119789638051451e-1,1.574000556785898e-1,-1.113618964927466e-1,3.631000220124657e-1,1.639694219982991,-9.114074742274862e-1,4.952715520862987e-1,-4.524162151353456e-1,2.65481378213589e-1,-2.268273408674622e-1,3.455365956773523e-1,-2.009765975089827e-1,1.722179564305811e-1,-5.52933488235368e-1,3.18109976271229e-1,-2.171481232558432e-1,1.033835580108027e-1,-5.911351224351343e-2,3.960076712054991e-2],[3,11]);
+end
+if nargout > 2
+    t2 = [1.7e1./4.8e1,5.9e1./4.8e1,4.3e1./4.8e1,4.9e1./4.8e1];
+    HcU = t2;
+end
+if nargout > 3
+    HfU = t2;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_4to4_ratio_2to1_accC2F3_accF2C2.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_4to4_ratio_2to1_accC2F3_accF2C2.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,18 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_4to4_ratio_2to1_accC2F3_accF2C2
+%INT_ORDERS_4TO4_RATIO_2TO1_ACCC2F3_ACCF2C2_STENCIL_9_BC_3_11
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_4TO4_RATIO_2TO1_ACCC2F3_ACCF2C2_STENCIL_9_BC_3_11
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:36:05
+
+stencil_F2C = [-1.0./2.56e2,-1.0./3.2e1,1.0./6.4e1,9.0./3.2e1,6.1e1./1.28e2,9.0./3.2e1,1.0./6.4e1,-1.0./3.2e1,-1.0./2.56e2];
+if nargout > 1
+    BC_F2C = reshape([1.0./2.0,0.0,0.0,1.77e2./2.72e2,3.0./8.0,-5.9e1./6.88e2,1.125919117647059e-2,3.546742584745763e-1,1.335392441860465e-2,-4.9e1./5.44e2,2.335805084745763e-1,3.204941860465116e-1,-1.194852941176471e-2,1.350635593220339e-2,5.308866279069767e-1,-9.0./5.44e2,-1.11228813559322e-2,2.943313953488372e-1,-2.803308823529412e-2,2.105402542372881e-2,-1.580668604651163e-2,-9.0./5.44e2,1.430084745762712e-2,-5.450581395348837e-2,-9.191176470588235e-4,7.944915254237288e-4,-5.450581395348837e-3,1.0./5.44e2,-1.588983050847458e-3,2.180232558139535e-3,2.297794117647059e-4,-1.986228813559322e-4,2.725290697674419e-4],[3,11]);
+end
+if nargout > 2
+    t2 = [1.7e1./4.8e1,5.9e1./4.8e1,4.3e1./4.8e1,4.9e1./4.8e1];
+    HcU = t2;
+end
+if nargout > 3
+    HfU = t2;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_6to6_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_6to6_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,47 @@
+function [IC2F,IF2C,Hc,Hf] = IntOp_orders_6to6_ratio2to1(mc,hc,ACC)
+
+% ACC is a string.
+% ACC = 'C2F' creates IC2F with one order of accuracy higher than IF2C.
+% ACC = 'F2C' creates IF2C with one order of accuracy higher than IC2F.
+ratio = 2;
+mf = ratio*mc-1; 
+hf = hc/ratio;
+
+switch ACC
+    case 'F2C'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_6to6_ratio_2to1_accC2F3_accF2C4;
+    case 'C2F'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_6to6_ratio_2to1_accC2F4_accF2C3;
+end
+
+stencil_width = length(stencil_F2C);
+stencil_hw = (stencil_width-1)/2;
+[BC_rows,BC_cols] = size(BC_F2C);
+
+%%% Norm matrices %%%
+Hc = speye(mc,mc);
+HcUm = length(HcU); 
+Hc(1:HcUm,1:HcUm) = spdiags(HcU',0,HcUm,HcUm);
+Hc(mc-HcUm+1:mc,mc-HcUm+1:mc) = spdiags(rot90(HcU',2),0,HcUm,HcUm);
+Hc = Hc*hc;
+
+Hf = speye(mf,mf);
+HfUm = length(HfU);
+Hf(1:HfUm,1:HfUm) = spdiags(HfU',0,HfUm,HfUm);
+Hf(mf-length(HfU)+1:mf,mf-length(HfU)+1:mf) = spdiags(rot90(HfU',2),0,HfUm,HfUm);
+Hf = Hf*hf;
+%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IF2C from stencil and BC
+IF2C = sparse(mc,mf);
+for i = BC_rows+1 : mc-BC_rows
+    IF2C(i,ratio*i-1+(-stencil_hw:stencil_hw)) = stencil_F2C; %#ok<SPRIX>
+end
+IF2C(1:BC_rows,1:BC_cols) = BC_F2C;
+IF2C(end-BC_rows+1:end,end-BC_cols+1:end) = rot90(BC_F2C,2);
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IC2F using symmetry condition %%%%
+IC2F = Hf\IF2C.'*Hc;
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_6to6_ratio_2to1_accC2F3_accF2C4.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_6to6_ratio_2to1_accC2F3_accF2C4.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,18 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_6to6_ratio_2to1_accC2F3_accF2C4
+%INT_ORDERS_6TO6_RATIO_2TO1_ACCC2F3_ACCF2C4_STENCIL_13_BC_3_17
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_6TO6_RATIO_2TO1_ACCC2F3_ACCF2C4_STENCIL_13_BC_3_17
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:35:47
+
+stencil_F2C = [-5.95703125e-3,3.0./5.12e2,3.57421875e-2,-2.5e1./5.12e2,-8.935546875e-2,7.5e1./2.56e2,3.17e2./5.12e2,7.5e1./2.56e2,-8.935546875e-2,-2.5e1./5.12e2,3.57421875e-2,3.0./5.12e2,-5.95703125e-3];
+if nargout > 1
+    BC_F2C = reshape([5.233890618131365e-1,-1.594459192645467e-2,3.532688727637403e-2,8.021234957689208e-1,3.90683205173562e-1,-1.73222951632239e-1,-8.87662686483442e-2,2.90091235796637e-1,-1.600356115709148e-1,-1.044025375027475e-1,2.346179009198368e-1,6.091329306528956e-1,1.561275522703128e-1,-1.168382445709856e-1,1.040987887887311,-2.387061036980731e-1,1.363504965974361e-1,1.082611928255256e-1,-5.745310654054326e-1,3.977694249198785e-1,-9.376217911402619e-1,3.554518646054656e-2,5.609157787396987e-5,-1.564625311232018e-1,6.107907974027401e-1,-3.786608696698368e-1,7.02265869951125e-1,2.054294270642538e-1,-1.302300112378257e-1,2.478941407690889e-1,-2.657085326191479e-1,1.568761445933572e-1,-2.632906518005349e-1,-1.228047556139644e-1,7.182193248980271e-2,-1.1291238242346e-1,5.811258780405158e-2,-3.466364400805378e-2,5.683680203338252e-2,1.781337575097077e-2,-1.030572999042704e-2,1.577197067502767e-2,-1.443802115768554e-2,8.391316308374261e-3,-1.29534117369052e-2,-1.548018627738296e-3,8.794183904936319e-4,-1.298961407229805e-3,1.573818938200601e-3,-8.940753636685258e-4,1.320610764016968e-3],[3,17]);
+end
+if nargout > 2
+    t2 = [3.159490740740741e-1,1.390393518518519,6.275462962962963e-1,1.240509259259259,9.116898148148148e-1,1.013912037037037];
+    HcU = t2;
+end
+if nargout > 3
+    HfU = t2;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_6to6_ratio_2to1_accC2F4_accF2C3.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_6to6_ratio_2to1_accC2F4_accF2C3.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,18 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_6to6_ratio_2to1_accC2F4_accF2C3
+%INT_ORDERS_6TO6_RATIO_2TO1_ACCC2F4_ACCF2C3_STENCIL_13_BC_4_17
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_6TO6_RATIO_2TO1_ACCC2F4_ACCF2C3_STENCIL_13_BC_4_17
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:35:56
+
+stencil_F2C = [1.07421875e-3,3.0./5.12e2,-6.4453125e-3,-2.5e1./5.12e2,1.611328125e-2,7.5e1./2.56e2,2.45e2./5.12e2,7.5e1./2.56e2,1.611328125e-2,-2.5e1./5.12e2,-6.4453125e-3,3.0./5.12e2,1.07421875e-3];
+if nargout > 1
+    BC_F2C = reshape([1.0./2.0,0.0,0.0,0.0,6.876076086160158e-1,1.5e1./3.2e1,-3.461879841386942e-1,3.502577439820862e-2,3.099721991995751e-3,2.228547003766753e-1,9.363652999354482e-3,-3.15791046603844e-3,-1.05789143206462e-1,2.35563165945226e-1,6.070385985337514e-1,-4.847496617839149e-2,-4.809232246867902e-3,5.154694068405061e-3,7.049223649022501e-1,1.016749349808733e-2,3.460117842882262e-2,-4.996621498584866e-2,5.210650763094799e-1,2.233592875303228e-1,-2.239024779745769e-3,4.254668119953384e-4,9.213872590833641e-3,3.910524351558127e-1,-9.048711215107334e-2,8.597375629526346e-2,-3.468219752858724e-1,3.250682992395969e-1,-1.309107466664224e-1,1.199249722306043e-1,-4.071552384959425e-1,1.474417123938701e-1,-3.02863877390285e-2,3.046016554982103e-2,-1.081315128181483e-1,1.120705238850532e-2,7.977722870036266e-2,-6.772545887788229e-2,2.00270418837606e-1,-5.427183680490763e-2,6.524845570188292e-2,-5.637610037043203e-2,1.711235764016968e-1,-4.203646902407166e-2,4.639548341453586e-3,-4.055884445496545e-3,1.258630924935448e-2,-2.776451559292779e-3,-1.023784366070774e-2,8.817108288936985e-3,-2.659664906860937e-2,7.14445034054861e-3,-1.435466025441424e-3,1.240274208149505e-3,-3.764718680837329e-3,1.028716295017727e-3,1.032012418492197e-3,-8.794183904936319e-4,2.597922814459609e-3,-6.571159498040679e-4,1.892022767235695e-4,-1.612267049238325e-4,4.76285849317595e-4,-1.204712574640791e-4],[4,17]);
+end
+if nargout > 2
+    t2 = [3.159490740740741e-1,1.390393518518519,6.275462962962963e-1,1.240509259259259,9.116898148148148e-1,1.013912037037037];
+    HcU = t2;
+end
+if nargout > 3
+    HfU = t2;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_8to8_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_8to8_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,47 @@
+function [IC2F,IF2C,Hc,Hf] = IntOp_orders_8to8_ratio2to1(mc,hc,ACC)
+
+% ACC is a string.
+% ACC = 'C2F' creates IC2F with one order of accuracy higher than IF2C.
+% ACC = 'F2C' creates IF2C with one order of accuracy higher than IC2F.
+ratio = 2;
+mf = ratio*mc-1; 
+hf = hc/ratio;
+
+switch ACC
+    case 'F2C'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_8to8_ratio_2to1_accC2F4_accF2C5;
+    case 'C2F'
+        [stencil_F2C,BC_F2C,HcU,HfU] = ...
+        sbp.implementations.intOpAWW_orders_8to8_ratio_2to1_accC2F5_accF2C4;
+end
+
+stencil_width = length(stencil_F2C);
+stencil_hw = (stencil_width-1)/2;
+[BC_rows,BC_cols] = size(BC_F2C);
+
+%%% Norm matrices %%%
+Hc = speye(mc,mc);
+HcUm = length(HcU); 
+Hc(1:HcUm,1:HcUm) = spdiags(HcU',0,HcUm,HcUm);
+Hc(mc-HcUm+1:mc,mc-HcUm+1:mc) = spdiags(rot90(HcU',2),0,HcUm,HcUm);
+Hc = Hc*hc;
+
+Hf = speye(mf,mf);
+HfUm = length(HfU);
+Hf(1:HfUm,1:HfUm) = spdiags(HfU',0,HfUm,HfUm);
+Hf(mf-length(HfU)+1:mf,mf-length(HfU)+1:mf) = spdiags(rot90(HfU',2),0,HfUm,HfUm);
+Hf = Hf*hf;
+%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IF2C from stencil and BC
+IF2C = sparse(mc,mf);
+for i = BC_rows+1 : mc-BC_rows
+    IF2C(i,ratio*i-1+(-stencil_hw:stencil_hw)) = stencil_F2C; %#ok<SPRIX>
+end
+IF2C(1:BC_rows,1:BC_cols) = BC_F2C;
+IF2C(end-BC_rows+1:end,end-BC_cols+1:end) = rot90(BC_F2C,2);
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%% Create IC2F using symmetry condition %%%%
+IC2F = Hf\IF2C.'*Hc;
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_8to8_ratio_2to1_accC2F4_accF2C5.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_8to8_ratio_2to1_accC2F4_accF2C5.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,18 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_8to8_ratio_2to1_accC2F4_accF2C5
+%INT_ORDERS_8TO8_RATIO_2TO1_ACCC2F4_ACCF2C5_STENCIL_17_BC_5_24
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_8TO8_RATIO_2TO1_ACCC2F4_ACCF2C5_STENCIL_17_BC_5_24
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:35:02
+
+stencil_F2C = [1.324608212425595e-3,-1.220703125e-3,-1.059686569940476e-2,1.1962890625e-2,3.708902994791667e-2,-5.9814453125e-2,-7.417805989583333e-2,2.99072265625e-1,5.927225748697917e-1,2.99072265625e-1,-7.417805989583333e-2,-5.9814453125e-2,3.708902994791667e-2,1.1962890625e-2,-1.059686569940476e-2,-1.220703125e-3,1.324608212425595e-3];
+if nargout > 1
+    BC_F2C = reshape([2.087365925359584,-1.227221822236823,1.090916714284468e1,-1.041312149906314,1.134214373258162,-1.269686811479259,2.075368250436277,-1.520771409696474e1,1.389750473974189,-1.48485748783569,-1.040579640776707,8.899721508624742e-1,-7.177691661032869,6.882712043721976e-1,-7.599347599660409e-1,-1.26440526850463,1.160658043364166,-5.391509178445742,6.679923135342851e-1,-7.521725463922262e-1,3.752349810676949,-2.906684049793639,2.672876913566556e1,-2.493145660873,2.782825829667436,1.443588084644871e-1,-1.307230271348211e-1,2.216804748506809,1.437719804483573e-1,-1.145830952112369e-1,3.2149320801083e-1,-2.34361439272989e-1,1.855837403850803,1.286992417665136e-1,-5.758238484341108e-2,-1.301103772185027,9.973408313121463e-1,-8.837520107531879,9.534930382604288e-1,-1.429199518808459e-2,-2.384453600787036,1.818345997558567,-1.577342441239303e1,1.422846302346762,3.154159322410927e-3,3.589377915408905e-1,-2.109524979864723e-1,9.363227187483732e-1,6.301238593470628e-2,5.732390257964316e-2,2.793582225299658,-2.033528056927806,1.621324028555783e1,-1.189222718426265,6.189671387692164e-2,5.342131492864642e-1,-4.222231296997605e-1,3.787253511209165,-3.350064226195165e-1,1.245325350855226e-2,-2.184146687275183,1.551331905163865,-1.19387312118926e1,8.349589004472998e-1,-1.35383591594438e-1,-8.014367493869704e-1,5.668415377001197e-1,-4.302842643863972,2.84183319528176e-1,3.83514596570461e-2,9.45794880458861e-1,-6.732638898386457e-1,5.234390273661413,-3.83498639699941e-1,1.440453495443018e-1,5.645065377027613e-1,-4.039220855868618e-1,3.170156487564899,-2.383074337879712e-1,1.216617375214008e-1,-1.937863224145611e-1,1.358891032584724e-1,-1.023378722711107,6.830621267493578e-2,-4.169135139842575e-3,2.270306426219975e-2,-2.38399209865252e-2,2.928388757260058e-1,-4.02060181933195e-2,6.880595419697505e-2,9.638828970166005e-2,-6.98778025332229e-2,5.609317796857676e-1,-4.429526993510467e-2,2.882554468024363e-2,3.582431391759518e-2,-2.671910644265286e-2,2.251335440088556e-1,-1.966486325944329e-2,1.791756577091828e-2,-3.350790201878844e-1,2.581411034605136e-1,-2.283079071439122,2.162064132948073e-1,-2.321676317817421e-1,6.356644993195555e-2,-4.921907141164279e-2,4.384534411523264e-1,-4.198474091936761e-2,4.597203884996652e-2,2.261662512481835e-2,-1.740429407604355e-2,1.537038474929879e-1,-1.452709057733876e-2,1.556101844926456e-2,3.097679325854209e-2,-2.394872918869654e-2,2.128879105995857e-1,-2.032077838507769e-2,2.213372706946953e-2],[5,24]);
+end
+if nargout > 2
+    t2 = [2.948906761778786e-1,1.525720623897707,2.57452876984127e-1,1.798113701499118,4.127080577601411e-1,1.278484623015873,9.232955798059965e-1,1.009333860859158];
+    HcU = t2;
+end
+if nargout > 3
+    HfU = t2;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpAWW_orders_8to8_ratio_2to1_accC2F5_accF2C4.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpAWW_orders_8to8_ratio_2to1_accC2F5_accF2C4.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,18 @@
+function [stencil_F2C,BC_F2C,HcU,HfU] = intOpAWW_orders_8to8_ratio_2to1_accC2F5_accF2C4
+%INT_ORDERS_8TO8_RATIO_2TO1_ACCC2F5_ACCF2C4_STENCIL_17_BC_6_24
+%    [STENCIL_F2C,BC_F2C,HCU,HFU] = INT_ORDERS_8TO8_RATIO_2TO1_ACCC2F5_ACCF2C4_STENCIL_17_BC_6_24
+
+%    This function was generated by the Symbolic Math Toolbox version 8.0.
+%    21-May-2018 15:35:39
+
+stencil_F2C = [-2.564929780505952e-4,-1.220703125e-3,2.051943824404762e-3,1.1962890625e-2,-7.181803385416667e-3,-5.9814453125e-2,1.436360677083333e-2,2.99072265625e-1,4.820454915364583e-1,2.99072265625e-1,1.436360677083333e-2,-5.9814453125e-2,-7.181803385416667e-3,1.1962890625e-2,2.051943824404762e-3,-1.220703125e-3,-2.564929780505952e-4];
+if nargout > 1
+    BC_F2C = reshape([-1.673327822994457e1,1.665420585653232e1,-1.973927473454954e2,2.826257908914756e1,-6.156813484052936e1,3.974966126696054,2.880639373222355e1,-2.660797294399895e1,3.202303847857831e2,-4.598960974033412e1,1.003152507870138e2,-6.481221721577338,8.061874893005659,-7.706608975219419,9.234201483040626e1,-1.322147613066874e1,2.880209985918895e1,-1.859523138300886,-2.19528557898034e1,2.13763239391502e1,-2.476320412310993e2,3.572924955195535e1,-7.795290920161567e1,5.036097395109802,-1.287197329845376,1.244100160910233,-1.394684346537857e1,2.112320869857597,-4.60441856527933,2.978264879234002e-1,1.935199269380359,-1.88580031845933,2.330807783420723e1,-2.91749306966336,6.644427567385864,-4.302395355488564e-1,-1.148984264037686,1.109982778464842,-1.314799057941425e1,2.137017065505111,-4.084082382904703,2.606486561845403e-1,1.565462612018858,-1.508309105065004,1.772442871757061e1,-2.40060893717649,6.31422909250156,-4.052444871368164e-1,3.179380137695096e-1,-3.071741522636364e-1,3.636264382483117,-5.183996466001354e-1,2.322192602480252,-6.467931586900172e-2,6.277081831671831e-1,-6.107890751034906e-1,7.335850436798604,-1.091016872160133,3.089218691662174,6.988892111841499e-2,1.639756762532723,-1.583883992641009,1.876236237708381e1,-2.685390559486947,5.859855615166555,3.919312696253764e-3,1.611803934956753,-1.540778869185931,1.795955382224485e1,-2.495154500270907,5.003492494640851,-4.157919873785453e-2,-6.213413520816026e-1,6.242581523412814e-1,-7.823535324240331,1.222418137438074,-3.120142966701915,2.975831327541895e-1,2.12230710100161,-2.0451058741188,2.412395225004063e1,-3.423544496956294,7.325914828631551,-4.793445914188063e-1,-4.31809447483846,4.158975059021769,-4.906211424150023e1,6.975058620124194,-1.501259943091044e1,9.418983630154896e-1,-6.138797742037704e-1,5.810969368378602e-1,-6.6821474226667,9.113864351863538e-1,-1.814400062103318,1.002574935832871e-1,-9.860044240994036e-2,9.448685284232805e-2,-1.106188847377502,1.552858946803229e-1,-3.265426230113952e-1,2.062042480203908e-2,-2.745034502159738,2.655226942873441,-3.151193386341271e1,4.520932327069998,-9.883338555855938,6.423439846307804e-1,2.139968493382333,-2.067738462547628,2.450223844197562e1,-3.50699574523559,7.635005983192545,-4.923960464980415e-1,1.036406872394752,-1.002008838408551,1.188339891704641e1,-1.70302259679446,3.715789696036691,-2.407301455417931e-1,1.606428513214277,-1.552524985439685,1.840245870449254e1,-2.635131753653705,5.741508438443495,-3.708346905830083e-1,5.659562678739624e-2,-5.465656201303744e-2,6.471932864664631e-1,-9.253169145609999e-2,2.010909570941804e-1,-1.292046400706276e-2,5.435391241988039e-1,-5.252672844681129e-1,6.225561585258754,-8.91344337215917e-1,1.941632399616401,-1.253426955105431e-1,-1.552116972709218,1.499962759958308,-1.777819805127299e1,2.545472086708348,-5.545140384142844,3.580057322157566e-1],[6,24]);
+end
+if nargout > 2
+    t2 = [2.948906761778786e-1,1.525720623897707,2.57452876984127e-1,1.798113701499118,4.127080577601411e-1,1.278484623015873,9.232955798059965e-1,1.009333860859158];
+    HcU = t2;
+end
+if nargout > 3
+    HfU = t2;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpMC_orders_2to2_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpMC_orders_2to2_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,35 @@
+function [IC2F,IF2C] = intOpMC_orders_2to2_ratio2to1(mc)
+
+mf = 2*(mc-1) + 1;
+
+stencil_F2C = [1.0./4.0,1.0./2.0,1.0./4.0];
+stencil_width = length(stencil_F2C);
+stencil_halfwidth = (stencil_width-1)/2;
+
+BC_F2C = [1.0./2.0,1.0./2.0];
+
+Hc = speye(mc,mc);
+Hc(1,1) = 1/2;
+Hc(end,end) = 1/2;
+
+Hf = 1/2*speye(mf,mf);
+Hf(1,1) = 1/4;
+Hf(end,end) = 1/4; 
+
+IF2C = sparse(mc,mf);
+[BCrows, BCcols] = size(BC_F2C);
+IF2C(1:BCrows, 1:BCcols) = BC_F2C;
+IF2C(mc-BCrows+1:mc, mf-BCcols+1:mf) = rot90(BC_F2C,2);
+
+for i = BCrows+1 : mc-BCrows
+	IF2C(i,(2*i-stencil_halfwidth-1) :(2*i+stencil_halfwidth-1))...
+		 = stencil_F2C;
+end
+
+IC2F = Hf\(IF2C'*Hc);
+
+
+
+
+
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpMC_orders_4to4_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpMC_orders_4to4_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,66 @@
+% Marks New interpolation operators
+% 4th order to 2nd order accurate (diagonal norm) 
+% M=9 is the minimum amount of points on the coarse mesh
+
+function [IC2F,IF2C] = intOpMC_orders_4to4_ratio2to1(M_C)
+
+M_F=M_C*2-1;
+
+% Coarse to fine
+I1=zeros(M_F,M_C);
+t1=[  2047/2176 , 129/1088 , -129/2176 , 0 , 0 , 0 , 0 ,...
+      0  ;...
+    429/944 , 279/472 , -43/944 , 0 , 0 , 0 , 0 , 0 ;...
+    111/2752 , 4913/5504 , 3/32 , -147/5504 ,...
+      0 , 0 , 0 , 0  ;...
+    -103/784 , 549/784 , 387/784 , -1/16 , 0 ,...
+      0 , 0 , 0  ;...
+    -335/3072 , 205/768 , 2365/3072 , 49/512 ,...
+      -3/128 , 0 , 0 , 0  ;...
+    -9/256 , 5/256 , 129/256 , 147/256 ,...
+      -1/16 , 0 , 0 , 0  ;...
+    5/192 , -59/1024 , 43/512 , 2695/3072 ,...
+      3/32 , -3/128 , 0 , 0 ;...
+    23/768 , -37/768 , -43/768 , 147/256 ,...
+      9/16 , -1/16 , 0 , 0  ;...
+    13/2048 , -11/1024 , -43/2048 , 49/512 ,...
+      55/64 , 3/32 , -3/128 , 0 ;...
+    -1/384 , 1/256 , 0 , -49/768 , 9/16 ,...
+      9/16 , -1/16 , 0  ;...
+    -1/1024 , 3/2048 , 0 , -49/2048 , 3/32 ,...
+      55/64 , 3/32 , -3/128];
+
+
+t2=[-3/128 3/32 55/64 3/32 -3/128];
+t3=[-1/16 9/16 9/16 -1/16];
+I1(1:11,1:8)=t1;
+I1(M_F-10:M_F,M_C-7:M_C)=fliplr(flipud(t1));
+I1(12,5:8)=t3;
+for i=13:2:M_F-12
+    j=(i-1)/2;
+    I1(i,j-1:j+3)=t2;
+    I1(i+1,j:j+3)=t3;
+end
+
+% Fine to coarse
+I2=zeros(M_C,M_F);
+
+t1=[ 2047/4352 , 429/544 , 111/2176 , -103/544 ...
+      , -335/2176 , -27/544 , 5/136 , 23/544 ,...
+      39/4352 , -1/272 , -3/2176 ;...
+    129/7552 , 279/944 , 4913/15104 , 549/1888 ...
+      , 205/1888 , 15/1888 , -3/128 , -37/1888 ...
+      , -33/7552 , 3/1888 , 9/15104 ];
+t2=[-3/256 -1/32 3/64 9/32 55/128 9/32 3/64 -1/32 -3/256];
+
+I2(1:2,1:11)=t1;      
+
+I2(M_C-1:M_C,M_F-10:M_F)=fliplr(flipud(t1));
+
+for i=3:M_C-2
+    j=2*(i-3)+1;
+    I2(i,j:j+8)=t2;
+end
+
+IC2F = sparse(I1);
+IF2C = sparse(I2);
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpMC_orders_6to6_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpMC_orders_6to6_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,115 @@
+% Marks New interpolation operators
+% 6th order accurate (diagonal norm) 
+% M=19 is the minimum amount of points on the coarse mesh
+
+function [IC2F,IF2C] = intOpMC_orders_6to6_ratio2to1(M_C)
+
+M_F=M_C*2-1;
+
+% Coarse to fine
+I1=zeros(M_F,M_C);
+
+t1=    [6854313/6988288 , 401925/6988288 , -401925/6988288 ...
+      , 133975/6988288 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0  ; ...
+    560547/1537664 , 1201479/1537664 , -240439/1537664 ...
+      , 16077/1537664 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ; ...
+    203385/5552128 , 1225647/1388032 , 364155/2776064 ...
+      , -80385/1388032 , 39385/5552128 , 0 , 0 , 0 , 0 , 0 , 0 , 0  ; ...
+    -145919/2743808 , 721527/1371904 , 105687/171488 , ...
+      -25/256 , 23631/2743808 , 0 , 0 , 0 , 0 , 0 , 0 , 0  ; ...
+    -178863/4033024 , 1178085/8066048 , ...
+      1658587/2016512 , 401925/4033024 , -15/512 , ...
+      43801/8066048 , 0 , 0 , 0 , 0 , 0 , 0 ; ...
+    -1668147/11213056 , 4193225/11213056 , ...
+      375675/2803264 , 2009625/2803264 , ...
+      -984625/11213056 , 3/256 , 0 , 0 , 0 , 0 , 0 , 0 ; ...
+    -561187/2949120 , 831521/1474560 , -788801/1474560 ...
+      , 412643/368640 , 39385/589824 , -43801/1474560 ...
+      , 5/1024 , 0 , 0 , 0 , 0 , 0 ; ...
+    23/1024 , 23/147456 , -43435/221184 , ...
+      26795/36864 , 39385/73728 , -43801/442368 , ...
+      3/256 , 0 , 0 , 0 , 0 , 0  ; ...
+    79379/368640 , -1664707/2949120 , 284431/737280 , ...
+      26795/294912 , 606529/737280 , 43801/589824 , ...
+      -15/512 , 5/1024 , 0 , 0 , 0 , 0 ; ...
+    3589/27648 , -2225/6144 , 22939/73728 , ...
+      -26795/221184 , 39385/73728 , 43801/73728 , ...
+      -25/256 , 3/256 , 0 , 0 , 0 , 0 ; ...
+    -720623/14745600 , 10637/92160 , -89513/1474560 , ...
+      -5359/147456 , 39385/589824 , 3372677/3686400 , ...
+      75/1024 , -15/512 , 5/1024 , 0 , 0 , 0 ; ...
+    -6357/81920 , 55219/276480 , -8707/61440 , ...
+      5359/368640 , -39385/442368 , 43801/73728 , ...
+      75/128 , -25/256 , 3/256 , 0 , 0 , 0 ; ...
+    -13315/884736 , 2589/65536 , -479/16384 , ...
+      5359/884736 , -7877/294912 , 43801/589824 , ...
+      231/256 , 75/1024 , -15/512 , 5/1024 , 0 , 0  ; ...
+    8299/737280 , -7043/245760 , 5473/276480 , 0 , ...
+      7877/737280 , -43801/442368 , 75/128 , ...
+      75/128 , -25/256 , 3/256 , 0 , 0 ; ...
+    11027/2949120 , -8461/884736 , 655/98304 , 0 , ...
+      7877/1769472 , -43801/1474560 , 75/1024 , ...
+      231/256 , 75/1024 , -15/512 , 5/1024 , 0 ; ...
+    -601/614400 , 601/245760 , -601/368640 , 0 , 0 , ...
+      43801/3686400 , -25/256 , 75/128 , ...
+      75/128 , -25/256 , 3/256 , 0 ; ...
+    -601/1474560 , 601/589824 , -601/884736 , 0 , 0 , ...
+      43801/8847360 , -15/512 , 75/1024 , ...
+      231/256 , 75/1024 , -15/512 , 5/1024 ] ;
+  
+  t2=  [5/1024 , -15/512 , 75/1024, 231/256 , 75/1024 , -15/512 , 5/1024];
+      
+  t3=  [3/256 , -25/256 , 75/128 , 75/128 , -25/256 , 3/256];     
+
+I1(1:17,1:12)=t1;
+I1(M_F-16:M_F,M_C-11:M_C)=fliplr(flipud(t1));
+I1(18,7:12)=t3;
+for i=19:2:M_F-18
+    j=(i-3)/2;
+    I1(i,j-1:j+5)=t2;
+    I1(i+1,j:j+5)=t3;
+end
+
+% Fine to coarse
+I2=zeros(M_C,M_F);
+
+t1=[6854313/13976576 , 2802735/3494144 , ...
+      1016925/27953152 , -729595/6988288 , ...
+      -894315/13976576 , -1668147/6988288 , ...
+      -8417805/27953152 , 15525/436768 , ...
+      1190685/3494144 , 89725/436768 , ...
+      -2161869/27953152 , -858195/6988288 , ...
+      -332875/13976576 , 124485/6988288 , ...
+      165405/27953152 , -5409/3494144 , -9015/13976576;  ...
+    80385/12301312 , 1201479/3075328 , 1225647/6150656 ...
+      , 721527/3075328 , 1178085/24602624 , ...
+      838645/6150656 , 60843/300032 , 345/6150656 , ...
+      -4994121/24602624 , -100125/768832 , ...
+      31911/768832 , 55219/768832 , 349515/24602624 , ...
+      -63387/6150656 , -42305/12301312 , 5409/6150656 ...
+      , 9015/24602624  ; ...
+    -80385/5552128 , -240439/1388032 , 364155/5552128 ...
+      , 105687/173504 , 1658587/2776064 , 75135/694016 ...
+      , -2366403/5552128 , -217175/1388032 , ...
+      853293/2776064 , 344085/1388032 , ...
+      -268539/5552128 , -78363/694016 , -64665/2776064 ...
+      , 5473/347008 , 29475/5552128 , -1803/1388032 , ...
+      -3005/5552128];
+
+
+  
+ t2=[  5/2048 , 3/512 , -15/1024 , -25/512 , ...
+      75/2048 , 75/256 , 231/512 , 75/256 , ...
+      75/2048 , -25/512 , -15/1024 , 3/512 , 5/2048];
+  
+I2(1:3,1:17)=t1;      
+
+I2(M_C-2:M_C,M_F-16:M_F)=fliplr(flipud(t1));
+
+for i=4:M_C-3
+    j=2*(i-4)+1;
+    I2(i,j:j+12)=t2;
+end
+IC2F = sparse(I1);
+IF2C = sparse(I2);
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/+implementations/intOpMC_orders_8to8_ratio2to1.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/+implementations/intOpMC_orders_8to8_ratio2to1.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,53 @@
+% Marks New interpolation operators
+% 8th order accurate (diagonal norm) 
+% M=19 is the minimum amount of points on the coarse mesh
+
+function [IC2F,IF2C] = intOpMC_orders_8to8_ratio2to1(M_C)
+
+M_F=M_C*2-1;
+
+% Coarse to fine
+I1=zeros(M_F,M_C);
+
+t1=    [0.99340647972821530406e0 0.26374081087138783775e-1 -0.39561121630708175663e-1 0.26374081087138783775e-1 -0.65935202717846959438e-2 0 0 0 0 0 0 0 0 0 0 0; 0.31183959860287729600e0 0.94014160558849081601e0 -0.31646240838273622401e0 0.65141605588490816007e-1 -0.66040139712270400169e-3 0 0 0 0 0 0 0 0 0 0 0; -0.33163591467432411328e-1 0.11092588191512759415e1 -0.10539936193077965253e0 -0.77189144409925778387e-2 0.60418595406382404105e-1 -0.23395546718453703858e-1 0 0 0 0 0 0 0 0 0 0; -0.63951987538041216890e-1 0.56657207530367360435e0 0.56073157416571775151e0 -0.67107298938782711711e-1 0.54915118559238359570e-2 -0.17358748484912632117e-2 0 0 0 0 0 0 0 0 0 0; 0.22970968995770386894e0 -0.84424237330911973043e0 0.20693327723706358111e1 -0.42910115554542331920e0 -0.13191478386190563918e0 0.11675567167691342983e0 -0.10539821288804421121e-1 0 0 0 0 0 0 0 0 0; 0.10195433776615307267e0 -0.45344410547614678949e0 0.11049699103276728065e1 0.26297465812771521534e0 -0.38617448080010680341e-1 0.23925781250000000000e-1 -0.17631339153836246986e-2 0 0 0 0 0 0 0 0 0; -0.33882356049961665258e0 0.12718893449497745294e1 -0.16822328941798626751e1 0.17813590728082409984e1 0.11793036905675500906e0 -0.18266200597575250398e0 0.37689938246258754051e-1 -0.51502644057974593120e-2 0 0 0 0 0 0 0 0; -0.50400650482311136546e0 0.19901277318227816880e1 -0.29708252195230746436e1 0.23722122500767090037e1 0.24457622727717445252e0 -0.15152936311741758892e0 0.21886284536938453771e-1 -0.24414062500000000000e-2 0 0 0 0 0 0 0 0; 0.37882732714731866331e-2 0.12115606818363056270e0 -0.53924884156527999826e0 0.88886598075786086512e0 0.27660232216640139169e0 0.33730204543181760125e0 -0.12179633685076087365e0 0.38041730885639608773e-1 -0.47112422807823442564e-2 0 0 0 0 0 0 0; 0.41123781086486062886e0 -0.14418811327145423418e1 0.16793759240044487847e1 -0.57156511000645013503e0 0.24685906775203751929e0 0.76471858554416232639e0 -0.11045284035765094522e0 0.24149101163134162809e-1 -0.24414062500000000000e-2 0 0 0 0 0 0 0; 0.36463669929508579110e0 -0.13698743320477484358e1 0.18268133133896437122e1 -0.93074264690533336964e0 0.10888458847499176143e0 0.85685706622610101431e0 0.24359267370152174731e0 -0.13314605809973863070e0 0.37689938246258754051e-1 -0.47112422807823442564e-2 0 0 0 0 0 0; 0.25541802394537278164e0 -0.10497853549910180363e1 0.15921730465359157986e1 -0.96615555845660927855e0 -0.49371813550407503858e-1 0.76471858554416232639e0 0.55226420178825472608e0 -0.12074550581567081404e0 0.23925781250000000000e-1 -0.24414062500000000000e-2 0 0 0 0 0 0; -0.93469656691661424206e-1 0.26634337856674539612e0 -0.17694629839462736800e0 -0.64947940656920645005e-1 -0.54442294237495880713e-1 0.33730204543181760125e0 0.61880473767909428853e0 0.26629211619947726141e0 -0.13191478386190563918e0 0.37689938246258754051e-1 -0.47112422807823442564e-2 0 0 0 0 0; -0.49445400002561969522e0 0.18168098496802059221e1 -0.23462477366129557292e1 0.11091140417405116705e1 0.98743627100815007716e-2 -0.15294371710883246528e0 0.55226420178825472608e0 0.60372752907835407022e0 -0.11962890625000000000e0 0.23925781250000000000e-1 -0.24414062500000000000e-2 0 0 0 0 0; -0.24633538738293361369e0 0.93021448723433316305e0 -0.12527182680719820488e1 0.63698038058706249354e0 0.15554941210713108775e-1 -0.16865102271590880063e0 0.24359267370152174731e0 0.67646871560981190145e0 0.26382956772381127836e0 -0.13191478386190563918e0 0.37689938246258754051e-1 -0.47112422807823442564e-2 0 0 0 0; 0.23150628239599695492e0 -0.82682792555928440531e0 0.10237569354829334077e1 -0.45129113643047460593e0 -0.10075880316409694665e-2 0.30588743421766493056e-1 -0.11045284035765094522e0 0.60372752907835407022e0 0.59814453125000000000e0 -0.11962890625000000000e0 0.23925781250000000000e-1 -0.24414062500000000000e-2 0 0 0 0; 0.19518658723021413499e0 -0.70515100787561674409e0 0.88870680011413432419e0 -0.40458631782898657259e0 -0.19443676513391385969e-2 0.48186006490259657322e-1 -0.12179633685076087365e0 0.26629211619947726141e0 0.67021304034523590205e0 0.26382956772381127836e0 -0.13191478386190563918e0 0.37689938246258754051e-1 -0.47112422807823442564e-2 0 0 0; -0.43403699494753775353e-1 0.15442805550926787092e0 -0.18997683853068679729e0 0.82584189359473172950e-1 0 -0.31213003491598462302e-2 0.22090568071530189043e-1 -0.12074550581567081404e0 0.59814453125000000000e0 0.59814453125000000000e0 -0.11962890625000000000e0 0.23925781250000000000e-1 -0.24414062500000000000e-2 0 0 0; -0.58783367481931040778e-1 0.20994477957758583150e0 -0.25976152530269196017e0 0.11403438083569734975e0 0 -0.60232508112824571652e-2 0.34798953385931678187e-1 -0.13314605809973863070e0 0.26382956772381127836e0 0.67021304034523590205e0 0.26382956772381127836e0 -0.13191478386190563918e0 0.37689938246258754051e-1 -0.47112422807823442564e-2 0 0; 0.63390647713259204145e-2 -0.22373993350504987875e-1 0.27185871992161665013e-1 -0.11561529976981026786e-1 0 0 -0.22541395991357335758e-2 0.24149101163134162809e-1 -0.11962890625000000000e0 0.59814453125000000000e0 0.59814453125000000000e0 -0.11962890625000000000e0 0.23925781250000000000e-1 -0.24414062500000000000e-2 0 0; 0.10649583863025939259e-1 -0.37634916628131671889e-1 0.45812371547331598336e-1 -0.19540204529147604911e-1 0 0 -0.43498691732414597734e-2 0.38041730885639608773e-1 -0.13191478386190563918e0 0.26382956772381127836e0 0.67021304034523590205e0 0.26382956772381127836e0 -0.13191478386190563918e0 0.37689938246258754051e-1 -0.47112422807823442564e-2 0; -0.45575492476359756866e-3 0.15951422366725914903e-2 -0.19141706840071097884e-2 0.79757111833629574515e-3 0 0 0 -0.24641939962381798784e-2 0.23925781250000000000e-1 -0.11962890625000000000e0 0.59814453125000000000e0 0.59814453125000000000e0 -0.11962890625000000000e0 0.23925781250000000000e-1 -0.24414062500000000000e-2 0; -0.87948159845213680356e-3 0.30781855945824788125e-2 -0.36938227134989745750e-2 0.15390927972912394062e-2 0 0 0 -0.47552163607049510966e-2 0.37689938246258754051e-1 -0.13191478386190563918e0 0.26382956772381127836e0 0.67021304034523590205e0 0.26382956772381127836e0 -0.13191478386190563918e0 0.37689938246258754051e-1 -0.47112422807823442564e-2;];
+
+  
+  t2=  [-0.456778318652801649905139026187255979136056340856723240855601037075101451671715366e81 / 0.96954962498118328965695036971472316719781487805298788537830810438965808195608854955e83 0.3654226549222413199241112209498047833088450726853785926844808296600811613373722928e82 / 0.96954962498118328965695036971472316719781487805298788537830810438965808195608854955e83 -0.1827113274611206599620556104749023916544225363426892963422404148300405806686861464e82 / 0.13850708928302618423670719567353188102825926829328398362547258634137972599372693565e83 0.3654226549222413199241112209498047833088450726853785926844808296600811613373722928e82 / 0.13850708928302618423670719567353188102825926829328398362547258634137972599372693565e83 0.1856585148354920384923865861096125662293072684152233190798249652677391616531107981e82 / 0.2770141785660523684734143913470637620565185365865679672509451726827594519874538713e82 0.3654226549222413199241112209498047833088450726853785926844808296600811613373722928e82 / 0.13850708928302618423670719567353188102825926829328398362547258634137972599372693565e83 -0.1827113274611206599620556104749023916544225363426892963422404148300405806686861464e82 / 0.13850708928302618423670719567353188102825926829328398362547258634137972599372693565e83 0.3654226549222413199241112209498047833088450726853785926844808296600811613373722928e82 / 0.96954962498118328965695036971472316719781487805298788537830810438965808195608854955e83 -0.456778318652801649905139026187255979136056340856723240855601037075101451671715366e81 / 0.96954962498118328965695036971472316719781487805298788537830810438965808195608854955e83;];
+
+  t3=  [-0.5e1 / 0.2048e4 0.49e2 / 0.2048e4 -0.245e3 / 0.2048e4 0.1225e4 / 0.2048e4 0.1225e4 / 0.2048e4 -0.245e3 / 0.2048e4 0.49e2 / 0.2048e4 -0.5e1 / 0.2048e4;];
+I1(1:23,1:16)=t1;
+I1(M_F-22:M_F,M_C-15:M_C)=fliplr(flipud(t1));
+I1(24,9:16)=t3;
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%DEBUGGING
+
+for i=25:2:M_F-24
+    j=(i-3)/2;
+    I1(i,j-2:j+6)=t2;
+    I1(i+1,j-1:j+6)=t3;
+end
+
+% Fine to coarse: A
+I2=zeros(M_C,M_F);
+
+t1=[0.49670323986410765203e0 0.80670591743192512511e0 -0.14476656476698073533e-1 -0.19497555250083395132e0 0.16074268813765884450e0 0.22100911221277072755e0 -0.53042418939472250452e0 -0.86254139670456354517e0 0.64231825172866668299e-2 0.69727164011248914487e0 0.61825742343094006838e0 0.43307239695721032895e0 -0.15848187861199173328e0 -0.83836831742920925562e0 -0.41767239062238727391e0 0.39252899650233765024e0 0.33094736964907844809e0 -0.73592865087013788440e-1 -0.99669762780958210515e-1 0.10748160731101219580e-1 0.18056833808814782786e-1 -0.77275234787125894193e-3 -0.14911993994710636483e-2; 0.25487859584304862664e-2 0.47007080279424540800e0 0.93589176759289320118e-1 0.33386224041716468423e0 -0.11418395501435496457e0 -0.18998278818813064037e0 0.38484431284491986603e0 0.65828018436035862232e0 0.39704539050575728856e-1 -0.47252462545568042557e0 -0.44892698918501097924e0 -0.34402935194949605213e0 0.87284452472801643396e-1 0.59539401290875351190e0 0.30484430526276345964e0 -0.27096308216867871783e0 -0.23108785344796321535e0 0.50608234918774219796e-1 0.68801842319351676214e-1 -0.73322707316320135247e-2 -0.12333488857215226757e-1 0.52275043402033040521e-3 0.10087644967132781708e-2; -0.22656973277393401539e-1 -0.93771184228725468159e0 -0.52699680965389826267e-1 0.19581430555012001670e1 0.16586148101136731602e1 0.27435837109255836264e1 -0.30164708462284474624e1 -0.58235016129647971089e1 -0.10472767830023645070e1 0.32615209891555982371e1 0.35478595826728208891e1 0.30921640208240511054e1 -0.34364793368678654581e0 -0.45566547247355317663e1 -0.24329078834671892590e1 0.19882413967858906122e1 0.17259601262271516763e1 -0.36895458453625989435e0 -0.50448363278283993228e0 0.52797763052066775846e-1 0.88972343374038343284e-1 -0.37175165926095403240e-2 -0.71737841052106668688e-2; 0.21626748627943672418e-2 0.27636709246281031633e-1 -0.55259484658035070394e-3 -0.33553649469391355855e-1 -0.49244245327794891233e-1 0.93489376222103426899e-1 0.45734620580442859300e0 0.66579609152388478842e0 0.24716623315221892947e0 -0.15893464065423852815e0 -0.25881084331023040874e0 -0.26865808253702445366e0 -0.18060020510041282529e-1 0.30841043055726240020e0 0.17712461121229459766e0 -0.12549015561536110372e0 -0.11250298507032009025e0 0.22964117700293735857e-1 0.31709446610808019222e-1 -0.32149051440245356510e-2 -0.54335286230388551025e-2 0.22177994574852164638e-3 0.42797426992744435493e-3;];
+
+
+  
+ t2=[-0.23556211403911721282e-2 -0.12207031250000000000e-2 0.18844969123129377026e-1 0.11962890625000000000e-1 -0.65957391930952819589e-1 -0.59814453125000000000e-1 0.13191478386190563918e0 0.29907226562500000000e0 0.33510652017261795103e0 0.29907226562500000000e0 0.13191478386190563918e0 -0.59814453125000000000e-1 -0.65957391930952819589e-1 0.11962890625000000000e-1 0.18844969123129377026e-1 -0.12207031250000000000e-2 -0.23556211403911721282e-2;];
+
+  
+I2(1:4,1:23)=t1;      
+
+I2(M_C-3:M_C,M_F-22:M_F)=fliplr(flipud(t1));
+
+for i=5:M_C-4
+    j=2*(i-5)+1;
+    I2(i,j:j+16)=t2;
+end
+
+IC2F = sparse(I1);
+IF2C = sparse(I2);
+
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D1Gauss.m
--- a/+sbp/D1Gauss.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D1Gauss.m	Fri Sep 07 14:40:58 2018 +0200
@@ -37,5 +37,9 @@
 
             obj.borrowing = [];
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
     end
 end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D1Nonequidistant.m
--- a/+sbp/D1Nonequidistant.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D1Nonequidistant.m	Fri Sep 07 14:40:58 2018 +0200
@@ -81,6 +81,11 @@
             obj.Q = obj.H*obj.D1 - obj.e_r*obj.e_r' + obj.e_l*obj.e_l';
 
             obj.borrowing = [];
+
+        end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
         end
     end
 end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D1Upwind.m
--- a/+sbp/D1Upwind.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D1Upwind.m	Fri Sep 07 14:40:58 2018 +0200
@@ -53,6 +53,10 @@
         	obj.borrowing = [];
 
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
     end
 
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D2BlockNorm.m
--- a/+sbp/D2BlockNorm.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D2BlockNorm.m	Fri Sep 07 14:40:58 2018 +0200
@@ -50,6 +50,10 @@
             obj.m = m;
 
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
     end
 
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D2Standard.m
--- a/+sbp/D2Standard.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D2Standard.m	Fri Sep 07 14:40:58 2018 +0200
@@ -64,10 +64,10 @@
 
             obj.m = m;
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
+
     end
 end
-
-
-
-
-
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D2Variable.m
--- a/+sbp/D2Variable.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D2Variable.m	Fri Sep 07 14:40:58 2018 +0200
@@ -18,7 +18,7 @@
 
     methods
         function obj = D2Variable(m,lim,order)
-            
+
             x_l = lim{1};
             x_r = lim{2};
             L = x_r-x_l;
@@ -26,28 +26,48 @@
             obj.x = linspace(x_l,x_r,m)';
 
             switch order
+
+                case 6
+
+                    [obj.H, obj.HI, obj.D1, obj.D2, ...
+                    ~, obj.e_l, obj.e_r, ~, ~, ~, ~, ~,...
+                     obj.d1_l, obj.d1_r] = ...
+                        sbp.implementations.d4_variable_6(m, obj.h);
+                    obj.borrowing.M.d1 = 0.1878;
+                    obj.borrowing.R.delta_D = 0.3696;
+                    % Borrowing e^T*D1 - d1 from R
+
                 case 4
                     [obj.H, obj.HI, obj.D1, obj.D2, obj.e_l,...
                         obj.e_r, obj.d1_l, obj.d1_r] = ...
                         sbp.implementations.d2_variable_4(m,obj.h);
-                    obj.borrowing.M.S = 0.2505765857;
+                    obj.borrowing.M.d1 = 0.2505765857;
+
+                    obj.borrowing.R.delta_D = 0.577587500088313;
+                    % Borrowing e^T*D1 - d1 from R
                 case 2
                     [obj.H, obj.HI, obj.D1, obj.D2, obj.e_l,...
                         obj.e_r, obj.d1_l, obj.d1_r] = ...
                         sbp.implementations.d2_variable_2(m,obj.h);
-                    obj.borrowing.M.S = 0.3636363636; 
+                    obj.borrowing.M.d1 = 0.3636363636; 
                     % Borrowing const taken from Virta 2014
+
+                    obj.borrowing.R.delta_D = 1.000000538455350;
+                    % Borrowing e^T*D1 - d1 from R
                     
                 otherwise
                     error('Invalid operator order %d.',order);
             end
-
+            obj.borrowing.H11 = obj.H(1,1)/obj.h; % First element in H/h,
             obj.m = m;
             obj.M = [];
-
+        end
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
         end
     end
 
+
 end
 
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D2VariablePeriodic.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/D2VariablePeriodic.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,71 @@
+classdef D2VariablePeriodic < sbp.OpSet
+    properties
+        D1 % SBP operator approximating first derivative
+        H % Norm matrix
+        HI % H^-1
+        Q % Skew-symmetric matrix
+        e_l % Left boundary operator
+        e_r % Right boundary operator
+        D2 % SBP operator for second derivative
+        M % Norm matrix, second derivative
+        d1_l % Left boundary first derivative
+        d1_r % Right boundary first derivative
+        m % Number of grid points.
+        h % Step size
+        x % grid
+        borrowing % Struct with borrowing limits for different norm matrices
+    end
+
+    methods
+        function obj = D2VariablePeriodic(m,lim,order)
+
+            x_l = lim{1};
+            x_r = lim{2};
+            L = x_r-x_l;
+            obj.h = L/m;
+            x = linspace(x_l,x_r,m+1)';
+            obj.x = x(1:end-1);
+
+            switch order
+
+                case 6
+                    [obj.H, obj.HI, obj.D1, obj.D2, obj.e_l,...
+                        obj.e_r, obj.d1_l, obj.d1_r] = ...
+                        sbp.implementations.d2_variable_periodic_6(m,obj.h);
+                    obj.borrowing.M.d1 = 0.1878;
+                    obj.borrowing.R.delta_D = 0.3696;
+                    % Borrowing e^T*D1 - d1 from R
+
+                case 4
+                    [obj.H, obj.HI, obj.D1, obj.D2, obj.e_l,...
+                        obj.e_r, obj.d1_l, obj.d1_r] = ...
+                        sbp.implementations.d2_variable_periodic_4(m,obj.h);
+                    obj.borrowing.M.d1 = 0.2505765857;
+
+                    obj.borrowing.R.delta_D = 0.577587500088313;
+                    % Borrowing e^T*D1 - d1 from R
+                case 2
+                    [obj.H, obj.HI, obj.D1, obj.D2, obj.e_l,...
+                        obj.e_r, obj.d1_l, obj.d1_r] = ...
+                        sbp.implementations.d2_variable_periodic_2(m,obj.h);
+                    obj.borrowing.M.d1 = 0.3636363636; 
+                    % Borrowing const taken from Virta 2014
+
+                    obj.borrowing.R.delta_D = 1.000000538455350;
+                    % Borrowing e^T*D1 - d1 from R
+                    
+                otherwise
+                    error('Invalid operator order %d.',order);
+            end
+            obj.borrowing.H11 = obj.H(1,1)/obj.h; % First element in H/h,
+
+            obj.m = m;
+            obj.M = [];
+        end
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
+    end
+
+
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D4Compatible.m
--- a/+sbp/D4Compatible.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D4Compatible.m	Fri Sep 07 14:40:58 2018 +0200
@@ -28,8 +28,8 @@
 
     methods
         function obj = D4Compatible(m,lim,order)
-            
-            
+
+
             x_l = lim{1};
             x_r = lim{2};
             L = x_r-x_l;
@@ -68,6 +68,10 @@
 
 
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
     end
 
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D4CompatibleVariable.m
--- a/+sbp/D4CompatibleVariable.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-classdef D4CompatibleVariable < sbp.OpSet
-    properties
-        D1 % SBP operator approximating first derivative
-        H % Norm matrix
-        HI % H^-1
-        Q % Skew-symmetric matrix
-        e_l % Left boundary operator
-        e_r % Right boundary operator
-        D2 % SBP operator for second derivative
-        M % Norm matrix, second derivative
-        d1_l % Left boundary first derivative
-        d1_r % Right boundary first derivative
-        D3 % SBP operator for third derivative
-        Q3 % Skew-symmetric matrix in third derivative
-        d2_l % Left boundary second derivative
-        d2_r % Right boundary second derivative
-        D4 % SBP operator for fourth derivative
-        M4 % Norm matrix, fourth derivative
-        d3_l % Left boundary third derivative
-        d3_r % Right boundary third derivative
-        m % Number of grid points.
-        h % Step size
-        x % grid
-        borrowing % Struct with borrowing limits for different norm matrices
-    end
-
-
-
-    methods
-        function obj = D4CompatibleVariable(m,lim,order)
-            
-            x_l = lim{1};
-            x_r = lim{2};
-            L = x_r-x_l;
-            obj.h = L/(m-1);
-            obj.x = linspace(x_l,x_r,m)';
-
-            if order == 2
-                [obj.H, obj.HI, ~, obj.D2, ~, obj.D4, obj.e_l, obj.e_r,...
-                 obj.M4, ~, obj.d2_l, obj.d2_r, obj.d3_l,...
-                    obj.d3_r, obj.d1_l, obj.d1_r] =...
-                    sbp.implementations.d4_compatible_halfvariable_2(m,obj.h);
-                obj.borrowing.N.S2 = 1.2500;
-                obj.borrowing.N.S3 = 0.4000;
-            elseif order == 4
-                [obj.H, obj.HI, obj.D2, obj.D4, obj.e_l, obj.e_r, obj.M4,...
-                 obj.d2_l, obj.d2_r, obj.d3_l, obj.d3_r, obj.d1_l,...
-                    obj.d1_r] =...
-                    sbp.implementations.d4_compatible_halfvariable_4(m,obj.h);
-                obj.borrowing.N.S2 = 0.5055;
-                obj.borrowing.N.S3 = 0.9290;
-            elseif order == 6
-                [obj.H, obj.HI, obj.D2, obj.D4, obj.e_l, obj.e_r, obj.M4,...
-                 obj.d2_l, obj.d2_r, obj.d3_l, obj.d3_r, obj.d1_l,...
-                    obj.d1_r] =...
-                    sbp.implementations.d4_compatible_halfvariable_6(m,obj.h);
-                obj.borrowing.N.S2 = 0.3259;
-                obj.borrowing.N.S3 = 0.1580;
-            else
-                error('Invalid operator order.');
-            end
-
-            obj.m = m;
-            
-            obj.D1 = [];
-            obj.D3 = [];
-
-
-        end
-    end
-
-
-
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D4Lonely.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/D4Lonely.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,124 @@
+classdef D4Lonely < sbp.OpSet
+    properties
+        m    % Number of grid points.
+        h    % Step size
+        x    % grid
+        H    % Norm matrix
+        HI   % H^-1
+        D4   % SBP operator for fourth derivative
+        M4   % Norm matrix, fourth derivative
+        e_l,  e_r  % Left and right boundary operator
+        d1_l, d1_r % Left and right boundary first derivative
+        d2_l, d2_r % Left and right boundary second derivative
+        d3_l, d3_r % Left and right boundary third derivative
+        borrowing % Struct with borrowing limits for different norm matrices
+        opt
+        order
+    end
+
+    methods
+        function obj = D4Lonely(m, lim, order, opt)
+            default_arg('opt', '')
+
+            obj.opt = opt;
+            obj.order = order;
+
+            x_l = lim{1};
+            x_r = lim{2};
+            L = x_r-x_l;
+            obj.h = L/(m-1);
+            obj.x = linspace(x_l, x_r,m)';
+
+            if order == 2
+                switch opt
+                    case ''
+                        [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_variable_2(m, obj.h);
+                        obj.borrowing.N.S2 = 1.2500;
+                        obj.borrowing.N.S3 = 0.4000;
+                    otherwise
+                        error('Invalid operator option.');
+                end
+
+            elseif order == 4
+                switch opt
+                    case 'min_boundary_points'
+                        [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_lonely_4_min_boundary_points(m, obj.h);
+                        obj.borrowing.N.S2 = 0.6244;
+                        obj.borrowing.N.S3 = 1.3961;
+                    case ''
+                        [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_variable_4(m, obj.h);
+                        obj.borrowing.N.S2 = 0.5055;
+                        obj.borrowing.N.S3 = 0.9290;
+                    otherwise
+                        error('Invalid operator option.');
+                end
+
+            elseif order == 6
+                switch opt
+                    case '2'
+                        [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_lonely_6_2(m, obj.h);
+                        obj.borrowing.N.S2 = 0.2931;
+                        obj.borrowing.N.S3 = 0.0807;
+                    case '3'
+                        [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_lonely_6_3(m, obj.h);
+                        obj.borrowing.N.S2 = 0.2842;
+                        obj.borrowing.N.S3 = 0.0709;
+                    case 'min_boundary_points'
+                        [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_lonely_6_min_boundary_points(m, obj.h);
+                        obj.borrowing.N.S2 = 0.3569;
+                        obj.borrowing.N.S3 = 0.1908;
+                    case ''
+                        [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_variable_6(m, obj.h);
+                        obj.borrowing.N.S2 = 0.3259;
+                        obj.borrowing.N.S3 = 0.1580;
+                    otherwise
+                        error('Invalid operator option.');
+                end
+
+            elseif order == 8
+                switch opt
+                    case 'min_boundary_points'
+                        [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_lonely_8_min_boundary_points(m, obj.h);
+                        obj.borrowing.N.S2 = 0.2804;
+                        obj.borrowing.N.S3 = 0.0740;
+                    case ''
+                        [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                            sbp.implementations.d4_lonely_8_higher_boundary_order(m, obj.h);
+                        obj.borrowing.N.S2 = 0.2475;
+                        obj.borrowing.N.S3 = 0.0401;
+                    otherwise
+                        error('Invalid operator option.');
+                    end
+            else
+                error('Invalid operator order.');
+            end
+
+            obj.m = m;
+
+            obj.H    = H;
+            obj.HI   = HI;
+            obj.D4   = D4;
+            obj.M4   = M4;
+            obj.e_l  = e_l;
+            obj.e_r  = e_r;
+            obj.d1_l = d1_l;
+            obj.d1_r = d1_r;
+            obj.d2_l = d2_l;
+            obj.d2_r = d2_r;
+            obj.d3_l = d3_l;
+            obj.d3_r = d3_r;
+        end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order) '_' obj.opt];
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D4Standard.m
--- a/+sbp/D4Standard.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/D4Standard.m	Fri Sep 07 14:40:58 2018 +0200
@@ -28,7 +28,7 @@
 
     methods
         function obj = D4Standard(m,lim,order)
-            
+
             x_l = lim{1};
             x_r = lim{2};
             L = x_r-x_l;
@@ -56,6 +56,10 @@
             obj.m = m;
 
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
     end
 
 
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/D4Variable.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/D4Variable.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,75 @@
+classdef D4Variable < sbp.OpSet
+    properties
+        m    % Number of grid points.
+        h    % Step size
+        x    % grid
+        H    % Norm matrix
+        HI   % H^-1
+        D1   % SBP operator approximating first derivative
+        D2   % SBP operator for second derivative
+        D4   % SBP operator for fourth derivative
+        Q    % Skew-symmetric matrix
+        M    % Norm matrix, second derivative
+        M4   % Norm matrix, fourth derivative
+        e_l,  e_r  % Left and right boundary operator
+        d1_l, d1_r % Left and right boundary first derivative
+        d2_l, d2_r % Left and right boundary second derivative
+        d3_l, d3_r % Left and right boundary third derivative
+        borrowing % Struct with borrowing limits for different norm matrices
+        order
+    end
+
+    methods
+        function obj = D4Variable(m, lim, order)
+            x_l = lim{1};
+            x_r = lim{2};
+            L = x_r-x_l;
+            obj.h = L/(m-1);
+            obj.x = linspace(x_l, x_r,m)';
+
+            if order == 2
+                [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                    sbp.implementations.d4_variable_2(m, obj.h);
+                obj.borrowing.M.d1 = 0.4000;
+                obj.borrowing.N.S2 = 1.2500;
+                obj.borrowing.N.S3 = 0.4000;
+            elseif order == 4
+                [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                    sbp.implementations.d4_variable_4(m, obj.h);
+                obj.borrowing.M.d1 = 0.2508;
+                obj.borrowing.N.S2 = 0.5055;
+                obj.borrowing.N.S3 = 0.9290;
+            elseif order == 6
+                [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = ...
+                    sbp.implementations.d4_variable_6(m, obj.h);
+                obj.borrowing.M.d1 = 0.1878;
+                obj.borrowing.N.S2 = 0.3259;
+                obj.borrowing.N.S3 = 0.1580;
+            else
+                error('Invalid operator order.');
+            end
+
+            obj.m = m;
+            obj.order = order;
+
+            obj.H    = H;
+            obj.HI   = HI;
+            obj.D1   = D1;
+            obj.D2   = D2;
+            obj.D4   = D4;
+            obj.M4   = M4;
+            obj.e_l  = e_l;
+            obj.e_r  = e_r;
+            obj.d1_l = d1_l;
+            obj.d1_r = d1_r;
+            obj.d2_l = d2_l;
+            obj.d2_r = d2_r;
+            obj.d3_l = d3_l;
+            obj.d3_r = d3_r;
+        end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/InterpAWW.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/InterpAWW.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,68 @@
+classdef InterpAWW < sbp.InterpOps
+    properties
+
+        % Interpolation operators
+        IC2F
+        IF2C
+
+        % Orders used on coarse and fine sides
+        order_C
+        order_F
+
+        % Grid points, refinement ratio.
+        ratio
+        m_C
+        m_F
+
+        % Boundary accuracy of IC2F and IF2C.
+        acc_C2F
+        acc_F2C
+    end
+
+    methods
+        % accOp : String, 'C2F' or 'F2C'. Specifies which of the operators
+        % should have higher accuracy.
+        function obj = InterpAWW(m_C,m_F,order_C,order_F,accOp)
+            assertIsMember(accOp, {'C2F','F2C'});
+
+            ratio = (m_F-1)/(m_C-1);
+            h_C = 1;
+
+            assert(order_C == order_F,...
+                    'Error: Different orders of accuracy not available');
+
+            switch ratio
+            case 2
+                switch order_C
+                case 2
+                    [IC2F,IF2C] = sbp.implementations.intOpAWW_orders_2to2_ratio2to1(m_C, h_C, accOp);
+                case 4
+                    [IC2F,IF2C] = sbp.implementations.intOpAWW_orders_4to4_ratio2to1(m_C, h_C, accOp);
+                case 6
+                    [IC2F,IF2C] = sbp.implementations.intOpAWW_orders_6to6_ratio2to1(m_C, h_C, accOp);
+                case 8
+                    [IC2F,IF2C] = sbp.implementations.intOpAWW_orders_8to8_ratio2to1(m_C, h_C, accOp);
+                otherwise
+                    error(['Order ' num2str(order_C) ' not available.']);
+                end
+            otherwise
+                error(['Grid ratio ' num2str(ratio) ' not available']);
+            end
+
+            obj.IC2F = IC2F;
+            obj.IF2C = IF2C;
+            obj.order_C = order_C;
+            obj.order_F = order_F;
+            obj.ratio = ratio;
+            obj.m_C = m_C;
+            obj.m_F = m_F;
+
+        end
+
+        function str = string(obj)
+            str = [class(obj) '_orders' num2str(obj.order_F) 'to'...
+            num2str(obj.order_C) '_ratio' num2str(obj.ratio) 'to1'];
+        end
+
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/InterpMC.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/InterpMC.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,61 @@
+classdef InterpMC < sbp.InterpOps
+    properties
+
+        % Interpolation operators
+        IC2F
+        IF2C
+
+        % Orders used on coarse and fine sides
+        order_C
+        order_F
+
+        % Grid points, refinement ratio.
+        ratio
+        m_C
+        m_F
+    end
+
+    methods
+        function obj = InterpMC(m_C,m_F,order_C,order_F)
+
+            ratio = (m_F-1)/(m_C-1);
+
+            assert(order_C == order_F,...
+                    'Error: Different orders of accuracy not available');
+
+            switch ratio
+            case 2
+                switch order_C
+                case 2
+                    [IC2F,IF2C] = sbp.implementations.intOpMC_orders_2to2_ratio2to1(m_C);
+                case 4
+                    [IC2F,IF2C] = sbp.implementations.intOpMC_orders_4to4_ratio2to1(m_C);
+                case 6
+                    [IC2F,IF2C] = sbp.implementations.intOpMC_orders_6to6_ratio2to1(m_C);
+                case 8
+                    [IC2F,IF2C] = sbp.implementations.intOpMC_orders_8to8_ratio2to1(m_C);
+                otherwise
+                    error(['Order ' num2str(order_C) ' not available.']);
+                end
+            otherwise
+                error(['Grid ratio ' num2str(ratio) ' not available']);
+            end
+
+            obj.IC2F = IC2F;
+            obj.IF2C = IF2C;
+            obj.order_C = order_C;
+            obj.order_F = order_F;
+            obj.ratio = ratio;
+            obj.m_C = m_C;
+            obj.m_F = m_F;
+
+
+        end
+
+        function str = string(obj)
+            str = [class(obj) '_orders' num2str(obj.order_F) 'to'...
+            num2str(obj.order_C) '_ratio' num2str(obj.ratio) 'to1'];
+        end
+
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/InterpOps.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+sbp/InterpOps.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,14 @@
+classdef (Abstract) InterpOps
+    properties (Abstract)
+        % C and F may refer to coarse and fine, but it's not a must.
+        IC2F % Interpolation operator from "C" to "F"
+        IF2C % Interpolation operator from "F" to "C"
+
+    end
+
+    methods (Abstract)
+        % Returns a string representation of the type of operator.
+        str = string(obj)
+    end
+
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +sbp/OpSet.m
--- a/+sbp/OpSet.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+sbp/OpSet.m	Fri Sep 07 14:40:58 2018 +0200
@@ -6,4 +6,9 @@
         x % Grid
     end
 
+    methods (Abstract)
+        % Returns a string representation of the type of operator.
+        str = string(obj)
+    end
+
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Beam.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/Beam.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,263 @@
+classdef Beam < scheme.Scheme
+    properties
+        order % Order accuracy for the approximation
+        grid
+
+        D % non-stabalized scheme operator
+        alpha
+
+        h
+        H % Discrete norm
+        Hi
+
+        e_l,  e_r
+        d1_l, d1_r
+        d2_l, d2_r
+        d3_l, d3_r
+        gamm
+        delt
+        alphaII
+        alphaIII
+
+        opt
+    end
+
+    methods
+        function obj = Beam(grid, order, alpha, opsGen, opt)
+            default_arg('alpha', -1);
+
+            % default_arg('opsGen', @sbp.D4);
+            default_arg('opsGen', @sbp.D4Variable); % Supposed to be better
+
+            opt_default.interface_l.tuning = 1.1;
+            opt_default.interface_l.tau = [];
+            opt_default.interface_l.sig = [];
+            opt_default.interface_r.tuning = 1.1;
+            opt_default.interface_r.tau = [];
+            opt_default.interface_r.sig = [];
+            default_struct('opt', opt_default);
+
+            if ~isa(grid, 'grid.Cartesian') || grid.D() ~= 1
+                error('Grid must be 1d cartesian');
+            end
+
+            obj.grid = grid;
+            obj.order = order;
+            obj.alpha = alpha;
+
+            m = grid.m;
+            h = grid.scaling();
+
+            x_lim = {grid.x{1}(1), grid.x{1}(end)};
+            ops = opsGen(m, x_lim, order);
+
+            D4       = ops.D4;
+            obj.H    = ops.H;
+            obj.Hi   = ops.HI;
+            obj.e_l  = ops.e_l;
+            obj.e_r  = ops.e_r;
+            obj.d1_l = ops.d1_l;
+            obj.d1_r = ops.d1_r;
+            obj.d2_l = ops.d2_l;
+            obj.d2_r = ops.d2_r;
+            obj.d3_l = ops.d3_l;
+            obj.d3_r = ops.d3_r;
+
+            obj.D = alpha*D4;
+
+            alphaII  = ops.borrowing.N.S2/2;
+            alphaIII = ops.borrowing.N.S3/2;
+
+            obj.gamm = h*alphaII;
+            obj.delt = h^3*alphaIII;
+            obj.alphaII = alphaII;
+            obj.alphaIII = alphaIII;
+            obj.h = h;
+            obj.opt = opt;
+        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.
+        %       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)
+            default_arg('type','dn');
+
+            [e, d1, d2, d3, s] = obj.get_boundary_ops(boundary);
+            gamm = obj.gamm;
+            delt = obj.delt;
+
+
+            % TODO: Can this be simplifed? Can I handle conditions on u on its own, u_x on its own ...
+
+            switch type
+                case {'dn', 'clamped'} % Dirichlet-neumann boundary condition
+                    alpha = obj.alpha;
+
+                    % tau1 < -alpha^2/gamma
+                    % tuning = 2;
+                    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 = obj.Hi*(tau*e' + sig*d1');
+
+                    penalty{1} = -obj.Hi*tau;
+                    penalty{2} = -obj.Hi*sig;
+
+
+                case {'free'}
+                    a = obj.alpha;
+
+                    tau =  s*a*d1;
+                    sig = -s*a*e;
+
+                    closure = obj.Hi*(tau*d2' + sig*d3');
+                    penalty{1} = -obj.Hi*tau;
+                    penalty{1} = -obj.Hi*sig;
+
+                case 'e'
+                    alpha = obj.alpha;
+                    tuning = 1.1;
+
+                    tau1 = tuning * alpha/delt;
+                    tau4 = s*alpha;
+
+                    tau = tau1*e+tau4*d3;
+
+                    closure = obj.Hi*tau*e';
+                    penalty = -obj.Hi*tau;
+                case 'd1'
+                    alpha = obj.alpha;
+
+                    tuning = 1.1;
+
+                    sig2 = tuning * alpha/gamm;
+                    sig3 = -s*alpha;
+
+                    sig = sig2*d1+sig3*d2;
+
+                    closure = obj.Hi*sig*d1';
+                    penalty = -obj.Hi*sig;
+
+                case 'd2'
+                    a = obj.alpha;
+
+                    tau =  s*a*d1;
+
+                    closure = obj.Hi*tau*d2';
+                    penalty = -obj.Hi*tau;
+                case 'd3'
+                    a = obj.alpha;
+
+                    sig = -s*a*e;
+
+                    closure = obj.Hi*sig*d3';
+                    penalty = -obj.Hi*sig;
+
+                otherwise % Unknown, boundary condition
+                    error('No such boundary condition: type = %s',type);
+            end
+        end
+
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            [e_u,d1_u,d2_u,d3_u,s_u] = obj.get_boundary_ops(boundary);
+            [e_v,d1_v,d2_v,d3_v,s_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary);
+
+
+            alpha_u = obj.alpha;
+            alpha_v = neighbour_scheme.alpha;
+
+
+            switch boundary
+                case 'l'
+                    interface_opt = obj.opt.interface_l;
+                case 'r'
+                    interface_opt = obj.opt.interface_r;
+            end
+
+
+            if isempty(interface_opt.tau) && isempty(interface_opt.sig)
+                gamm_u = obj.gamm;
+                delt_u = obj.delt;
+
+                gamm_v = neighbour_scheme.gamm;
+                delt_v = neighbour_scheme.delt;
+
+                tuning = interface_opt.tuning;
+
+                tau1 = ((alpha_u/2)/delt_u + (alpha_v/2)/delt_v)/2*tuning;
+                sig2 = ((alpha_u/2)/gamm_u + (alpha_v/2)/gamm_v)/2*tuning;
+            else
+                h_u = obj.h;
+                h_v = neighbour_scheme.h;
+
+                switch neighbour_boundary
+                    case 'l'
+                        neighbour_interface_opt = neighbour_scheme.opt.interface_l;
+                    case 'r'
+                        neighbour_interface_opt = neighbour_scheme.opt.interface_r;
+                end
+
+                tau_u = interface_opt.tau;
+                sig_u = interface_opt.sig;
+                tau_v = neighbour_interface_opt.tau;
+                sig_v = neighbour_interface_opt.sig;
+
+                tau1 = tau_u/h_u^3 + tau_v/h_v^3;
+                sig2 = sig_u/h_u   + sig_v/h_v;
+            end
+
+            tau4 = s_u*alpha_u/2;
+            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 =  obj.Hi*(tau*e_u' + sig*d1_u' + phi*alpha_u*d2_u' + psi*alpha_u*d3_u');
+            penalty = -obj.Hi*(tau*e_v' + sig*d1_v' + phi*alpha_v*d2_v' + psi*alpha_v*d3_v');
+        end
+
+        % Returns the boundary ops and sign for the boundary specified by the string boundary.
+        % The right boundary is considered the positive boundary
+        function [e, d1, d2, d3, s] = get_boundary_ops(obj,boundary)
+            switch boundary
+                case 'l'
+                    e  = obj.e_l;
+                    d1 = obj.d1_l;
+                    d2 = obj.d2_l;
+                    d3 = obj.d3_l;
+                    s = -1;
+                case 'r'
+                    e  = obj.e_r;
+                    d1 = obj.d1_r;
+                    d2 = obj.d2_r;
+                    d3 = obj.d3_r;
+                    s = 1;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+        end
+
+        function N = size(obj)
+            N = obj.grid.N;
+        end
+
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Beam2d.m
--- a/+scheme/Beam2d.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+scheme/Beam2d.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,10 +1,6 @@
 classdef Beam2d < scheme.Scheme
     properties
-        m % Number of points in each direction, possibly a vector
-        N % Number of points total
-        h % Grid spacing
-        u,v % Grid
-        x,y % Values of x and y for each grid point
+        grid
         order % Order accuracy for the approximation
 
         D % non-stabalized scheme operator
@@ -27,21 +23,23 @@
 
     methods
         function obj = Beam2d(m,lim,order,alpha,opsGen)
+            default_arg('alpha',1);
             default_arg('opsGen',@sbp.Higher);
-            default_arg('a',1);
 
-            if length(m) == 1
-                m = [m m];
+            if ~isa(grid, 'grid.Cartesian') || grid.D() ~= 2
+                error('Grid must be 2d cartesian');
             end
 
-            m_x = m(1);
-            m_y = m(2);
+            obj.grid = grid;
+            obj.alpha = alpha;
+            obj.order = order;
 
-            xlim = lim{1};
-            ylim = lim{2};
+            m_x = grid.m(1);
+            m_y = grid.m(2);
 
-            [x, h_x] = util.get_grid(xlim{:},m_x);
-            [y, h_y] = util.get_grid(ylim{:},m_y);
+            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);
@@ -49,9 +47,6 @@
             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);
@@ -105,16 +100,7 @@
             obj.d3_s = kr(I_x,d3_l_y);
             obj.d3_n = kr(I_x,d3_r_y);
 
-            obj.m = m;
-            obj.h = [h_x h_y];
-            obj.order = order;
-
-            obj.alpha = alpha;
             obj.D = alpha*D4;
-            obj.u = x;
-            obj.v = y;
-            obj.x = kr(x,ones(m_y,1));
-            obj.y = kr(ones(m_x,1),y);
 
             obj.gamm_x = h_x*ops_x.borrowing.N.S2/2;
             obj.delt_x = h_x^3*ops_x.borrowing.N.S3/2;
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Elastic2dCurvilinear.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/Elastic2dCurvilinear.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,621 @@
+classdef Elastic2dCurvilinear < scheme.Scheme
+
+% Discretizes the elastic wave equation in curvilinear coordinates.
+%
+% Untransformed equation:
+% rho u_{i,tt} = di lambda dj u_j + dj mu di u_j + dj mu dj u_i 
+%
+% Transformed equation:
+% J*rho u_{i,tt} = dk J b_ik lambda b_jl dl u_j 
+%                + dk J b_jk mu b_il dl u_j 
+%                + dk J b_jk mu b_jl dl u_i 
+% opSet should be cell array of opSets, one per dimension. This
+% is useful if we have periodic BC in one direction.
+
+    properties
+        m % Number of points in each direction, possibly a vector
+        h % Grid spacing
+
+        grid
+        dim
+
+        order % Order of accuracy for the approximation
+
+        % Diagonal matrices for varible coefficients
+        LAMBDA % Variable coefficient, related to dilation
+        MU     % Shear modulus, variable coefficient
+        RHO, RHOi % Density, variable
+
+        % Metric coefficients
+        b % Cell matrix of size dim x dim
+        J, Ji
+        beta % Cell array of scale factors
+
+        D % Total operator
+        D1 % First derivatives
+
+        % Second derivatives
+        D2_lambda
+        D2_mu
+
+        % Traction operators used for BC
+        T_l, T_r
+        tau_l, tau_r
+
+        H, Hi % Inner products
+        phi % Borrowing constant for (d1 - e^T*D1) from R
+        gamma % Borrowing constant for d1 from M
+        H11 % First element of H
+        e_l, e_r
+        d1_l, d1_r % Normal derivatives at the boundary
+        E % E{i}^T picks out component i
+        
+        H_boundary_l, H_boundary_r % Boundary inner products
+
+        % Kroneckered norms and coefficients
+        RHOi_kron
+        Ji_kron, J_kron
+        Hi_kron, H_kron
+    end
+
+    methods
+
+        function obj = Elastic2dCurvilinear(g ,order, lambda_fun, mu_fun, rho_fun, opSet)
+            default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable});
+            default_arg('lambda_fun', @(x,y) 0*x+1);
+            default_arg('mu_fun', @(x,y) 0*x+1);
+            default_arg('rho_fun', @(x,y) 0*x+1);
+            dim = 2;
+
+            lambda = grid.evalOn(g, lambda_fun);
+            mu = grid.evalOn(g, mu_fun);
+            rho = grid.evalOn(g, rho_fun);
+            m = g.size();
+            obj.m = m;
+            m_tot = g.N();
+
+            % 1D operators
+            ops = cell(dim,1);
+            for i = 1:dim
+                ops{i} = opSet{i}(m(i), {0, 1}, order);
+            end
+
+            % Borrowing constants
+            for i = 1:dim
+                beta = ops{i}.borrowing.R.delta_D;
+                obj.H11{i} = ops{i}.borrowing.H11;
+                obj.phi{i} = beta/obj.H11{i};
+                obj.gamma{i} = ops{i}.borrowing.M.d1;
+            end
+
+            I = cell(dim,1);
+            D1 = cell(dim,1);
+            D2 = cell(dim,1);
+            H = cell(dim,1);
+            Hi = cell(dim,1);
+            e_l = cell(dim,1);
+            e_r = cell(dim,1);
+            d1_l = cell(dim,1);
+            d1_r = cell(dim,1);
+
+            for i = 1:dim
+                I{i} = speye(m(i));
+                D1{i} = ops{i}.D1;
+                D2{i} = ops{i}.D2;
+                H{i} =  ops{i}.H;
+                Hi{i} = ops{i}.HI;
+                e_l{i} = ops{i}.e_l;
+                e_r{i} = ops{i}.e_r;
+                d1_l{i} = ops{i}.d1_l;
+                d1_r{i} = ops{i}.d1_r;
+            end
+
+            %====== Assemble full operators ========
+
+            % Variable coefficients
+            LAMBDA = spdiag(lambda);
+            obj.LAMBDA = LAMBDA;
+            MU = spdiag(mu);
+            obj.MU = MU;
+            RHO = spdiag(rho);
+            obj.RHO = RHO;
+            obj.RHOi = inv(RHO);
+
+            % Allocate
+            obj.D1 = cell(dim,1);
+            obj.D2_lambda = cell(dim,dim,dim);
+            obj.D2_mu = cell(dim,dim,dim);
+            obj.e_l = cell(dim,1);
+            obj.e_r = cell(dim,1);
+            obj.d1_l = cell(dim,1);
+            obj.d1_r = cell(dim,1);
+
+            % D1
+            obj.D1{1} = kron(D1{1},I{2});
+            obj.D1{2} = kron(I{1},D1{2});
+
+            % -- Metric coefficients ----
+            coords = g.points();
+            x = coords(:,1);
+            y = coords(:,2);
+
+            % Use non-periodic difference operators for metric even if opSet is periodic.
+            xmax = max(ops{1}.x);
+            ymax = max(ops{2}.x);
+            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); 
+
+            x_xi = D1Metric{1}*x;
+            x_eta = D1Metric{2}*x;
+            y_xi = D1Metric{1}*y;
+            y_eta = D1Metric{2}*y;
+
+            J = x_xi.*y_eta - x_eta.*y_xi;
+
+            b = cell(dim,dim);
+            b{1,1} = y_eta./J;
+            b{1,2} = -x_eta./J;
+            b{2,1} = -y_xi./J;
+            b{2,2} = x_xi./J;
+
+            % Scale factors for boundary integrals
+            beta = cell(dim,1);
+            beta{1} = sqrt(x_eta.^2 + y_eta.^2);
+            beta{2} = sqrt(x_xi.^2 + y_xi.^2);
+
+            J = spdiag(J);
+            Ji = inv(J);
+            for i = 1:dim
+                beta{i} = spdiag(beta{i});
+                for j = 1:dim
+                    b{i,j} = spdiag(b{i,j});
+                end
+            end
+            obj.J = J;
+            obj.Ji = Ji;
+            obj.b = b;
+            obj.beta = beta;
+            %----------------------------
+
+            % Boundary operators
+            obj.e_l{1} = kron(e_l{1},I{2});
+            obj.e_l{2} = kron(I{1},e_l{2});
+            obj.e_r{1} = kron(e_r{1},I{2});
+            obj.e_r{2} = kron(I{1},e_r{2});
+
+            obj.d1_l{1} = kron(d1_l{1},I{2});
+            obj.d1_l{2} = kron(I{1},d1_l{2});
+            obj.d1_r{1} = kron(d1_r{1},I{2});
+            obj.d1_r{2} = kron(I{1},d1_r{2});
+
+            % D2
+            for i = 1:dim
+                for j = 1:dim
+                    for k = 1:dim
+                        obj.D2_lambda{i,j,k} = sparse(m_tot);
+                        obj.D2_mu{i,j,k} = sparse(m_tot);
+                    end
+                end
+            end
+            ind = grid.funcToMatrix(g, 1:m_tot);
+
+            % x-dir
+            for i = 1:dim
+                for j = 1:dim
+                    for k = 1
+
+                        coeff_lambda = J*b{i,k}*b{j,k}*lambda;
+                        coeff_mu = J*b{j,k}*b{i,k}*mu;
+
+                        for col = 1:m(2)
+                            D_lambda = D2{1}(coeff_lambda(ind(:,col)));
+                            D_mu = D2{1}(coeff_mu(ind(:,col)));
+
+                            p = ind(:,col);
+                            obj.D2_lambda{i,j,k}(p,p) = D_lambda;
+                            obj.D2_mu{i,j,k}(p,p) = D_mu;
+                        end
+
+                    end
+                end
+            end
+
+            % y-dir
+            for i = 1:dim
+                for j = 1:dim
+                    for k = 2
+
+                        coeff_lambda = J*b{i,k}*b{j,k}*lambda;
+                        coeff_mu = J*b{j,k}*b{i,k}*mu;
+
+                        for row = 1:m(1)
+                            D_lambda = D2{2}(coeff_lambda(ind(row,:)));
+                            D_mu = D2{2}(coeff_mu(ind(row,:)));
+
+                            p = ind(row,:);
+                            obj.D2_lambda{i,j,k}(p,p) = D_lambda;
+                            obj.D2_mu{i,j,k}(p,p) = D_mu;
+                        end
+
+                    end
+                end
+            end
+
+            % Quadratures
+            obj.H = kron(H{1},H{2});
+            obj.Hi = inv(obj.H);
+            obj.H_boundary_l = cell(dim,1);
+            obj.H_boundary_l{1} = obj.e_l{1}'*beta{1}*obj.e_l{1}*H{2};
+            obj.H_boundary_l{2} = obj.e_l{2}'*beta{2}*obj.e_l{2}*H{1};
+            obj.H_boundary_r = cell(dim,1);
+            obj.H_boundary_r{1} = obj.e_r{1}'*beta{1}*obj.e_r{1}*H{2};
+            obj.H_boundary_r{2} = obj.e_r{2}'*beta{2}*obj.e_r{2}*H{1};
+
+            % E{i}^T picks out component i.
+            E = cell(dim,1);
+            I = speye(m_tot,m_tot);
+            for i = 1:dim
+                e = sparse(dim,1);
+                e(i) = 1;
+                E{i} = kron(I,e);
+            end
+            obj.E = E;
+
+            % Differentiation matrix D (without SAT)
+            D2_lambda = obj.D2_lambda;
+            D2_mu = obj.D2_mu;
+            D1 = obj.D1;
+            D = sparse(dim*m_tot,dim*m_tot);
+            d = @kroneckerDelta;    % Kronecker delta
+            db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
+            for i = 1:dim
+                for j = 1:dim
+                    for k = 1:dim
+                        for l = 1:dim
+                            D = D + E{i}*Ji*inv(RHO)*( d(k,l)*D2_lambda{i,j,k}*E{j}' + ...
+                                                      db(k,l)*D1{k}*J*b{i,k}*b{j,l}*LAMBDA*D1{l}*E{j}' ...
+                                                  );
+
+                            D = D + E{i}*Ji*inv(RHO)*( d(k,l)*D2_mu{i,j,k}*E{j}' + ...
+                                                      db(k,l)*D1{k}*J*b{j,k}*b{i,l}*MU*D1{l}*E{j}' ...
+                                                  );
+
+                            D = D + E{i}*Ji*inv(RHO)*( d(k,l)*D2_mu{j,j,k}*E{i}' + ...
+                                                      db(k,l)*D1{k}*J*b{j,k}*b{j,l}*MU*D1{l}*E{i}' ...
+                                                  );
+
+                        end
+                    end
+                end
+            end
+            obj.D = D;
+            %=========================================%
+
+            % Numerical traction operators for BC.
+            % Because d1 =/= e0^T*D1, the numerical tractions are different
+            % at every boundary.
+            T_l = cell(dim,1);
+            T_r = cell(dim,1);
+            tau_l = cell(dim,1);
+            tau_r = cell(dim,1);
+            % tau^{j}_i = sum_k T^{j}_{ik} u_k
+
+            d1_l = obj.d1_l;
+            d1_r = obj.d1_r;
+            e_l = obj.e_l;
+            e_r = obj.e_r;
+
+            % Loop over boundaries
+            for j = 1:dim
+                T_l{j} = cell(dim,dim);
+                T_r{j} = cell(dim,dim);
+                tau_l{j} = cell(dim,1);
+                tau_r{j} = cell(dim,1);
+
+                % Loop over components
+                for i = 1:dim
+                    tau_l{j}{i} = sparse(m_tot,dim*m_tot);
+                    tau_r{j}{i} = sparse(m_tot,dim*m_tot);
+
+                    % Loop over components that T_{ik}^{(j)} acts on
+                    for k = 1:dim
+
+                        T_l{j}{i,k} = sparse(m_tot,m_tot);
+                        T_r{j}{i,k} = sparse(m_tot,m_tot);
+
+                        for m = 1:dim
+                            for l = 1:dim
+                                T_l{j}{i,k} = T_l{j}{i,k} + ... 
+                                -d(k,l)* J*b{i,j}*b{k,m}*LAMBDA*(d(m,j)*e_l{m}*d1_l{m}' + db(m,j)*D1{m}) ...
+                                -d(k,l)* J*b{k,j}*b{i,m}*MU*(d(m,j)*e_l{m}*d1_l{m}' + db(m,j)*D1{m}) ...
+                                -d(i,k)* J*b{l,j}*b{l,m}*MU*(d(m,j)*e_l{m}*d1_l{m}' + db(m,j)*D1{m});
+
+                                T_r{j}{i,k} = T_r{j}{i,k} + ... 
+                                d(k,l)* J*b{i,j}*b{k,m}*LAMBDA*(d(m,j)*e_r{m}*d1_r{m}' + db(m,j)*D1{m}) + ...
+                                d(k,l)* J*b{k,j}*b{i,m}*MU*(d(m,j)*e_r{m}*d1_r{m}' + db(m,j)*D1{m}) + ...
+                                d(i,k)* J*b{l,j}*b{l,m}*MU*(d(m,j)*e_r{m}*d1_r{m}' + db(m,j)*D1{m});
+                            end
+                        end
+
+                        T_l{j}{i,k} = inv(beta{j})*T_l{j}{i,k};
+                        T_r{j}{i,k} = inv(beta{j})*T_r{j}{i,k}; 
+
+                        tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}';
+                        tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}';
+                    end
+
+                end
+            end
+            obj.T_l = T_l;
+            obj.T_r = T_r;
+            obj.tau_l = tau_l;
+            obj.tau_r = tau_r;
+
+            % Kroneckered norms and coefficients
+            I_dim = speye(dim);
+            obj.RHOi_kron = kron(obj.RHOi, I_dim);
+            obj.Ji_kron = kron(obj.Ji, I_dim);
+            obj.Hi_kron = kron(obj.Hi, I_dim);
+            obj.H_kron = kron(obj.H, I_dim);
+            obj.J_kron = kron(obj.J, I_dim);
+
+            % Misc.
+            obj.h = g.scaling();
+            obj.order = order;
+            obj.grid = g;
+            obj.dim = dim;
+
+        end
+
+
+        % Closure functions return the operators applied to the own domain to close the boundary
+        % Penalty functions return the operators 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'.
+        %       bc                  is a cell array of component and bc type, e.g. {1, 'd'} for Dirichlet condition
+        %                           on the first component.
+        %       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, bc, tuning)
+            default_arg('tuning', 1.2);
+
+            assert( iscell(bc), 'The BC type must be a 2x1 cell array' );
+            comp = bc{1};
+            type = bc{2};
+
+            % j is the coordinate direction of the boundary
+            j = obj.get_boundary_number(boundary);
+            [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
+
+            E = obj.E;
+            Hi = obj.Hi;
+            LAMBDA = obj.LAMBDA;
+            MU = obj.MU;
+            RHOi = obj.RHOi;
+            Ji = obj.Ji;
+
+            dim = obj.dim;
+            m_tot = obj.grid.N();
+
+            % Preallocate
+            closure = sparse(dim*m_tot, dim*m_tot);
+            penalty = sparse(dim*m_tot, m_tot/obj.m(j));
+
+            % Loop over components that we (potentially) have different BC on
+            k = comp;
+            switch type
+
+            % Dirichlet boundary condition
+            case {'D','d','dirichlet','Dirichlet'}
+
+                phi = obj.phi{j};
+                h = obj.h(j);
+                h11 = obj.H11{j}*h;
+                gamma = obj.gamma{j};
+
+                a_lambda = dim/h11 + 1/(h11*phi);
+                a_mu_i = 2/(gamma*h);
+                a_mu_ij = 2/h11 + 1/(h11*phi);
+
+                d = @kroneckerDelta;  % Kronecker delta
+                db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
+                alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ...
+                                      + d(i,j)* a_mu_i*MU ...
+                                      + db(i,j)*a_mu_ij*MU ); 
+
+                % Loop over components that Dirichlet penalties end up on
+                for i = 1:dim
+                    C = T{k,i};
+                    A = -d(i,k)*alpha(i,j);
+                    B = A + C;
+                    closure = closure + E{i}*RHOi*Hi*Ji*B'*e*H_gamma*(e'*E{k}' ); 
+                    penalty = penalty - E{i}*RHOi*Hi*Ji*B'*e*H_gamma;
+                end 
+
+            % Free boundary condition
+            case {'F','f','Free','free','traction','Traction','t','T'}
+                    closure = closure - E{k}*RHOi*Ji*Hi*e*H_gamma* (e'*tau{k} ); 
+                    penalty = penalty + E{k}*RHOi*Ji*Hi*e*H_gamma;
+
+            % Unknown boundary condition
+            otherwise
+                error('No such boundary condition: type = %s',type);
+            end
+        end
+
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            % Operators without subscripts are from the own domain.
+            error('Not implemented');
+            tuning = 1.2;
+
+            % j is the coordinate direction of the boundary
+            j = obj.get_boundary_number(boundary);
+            j_v = neighbour_scheme.get_boundary_number(neighbour_boundary);
+
+            % Get boundary operators
+            [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
+            [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary);
+
+            % Operators and quantities that correspond to the own domain only
+            Hi = obj.Hi;
+            RHOi = obj.RHOi;
+            dim = obj.dim;
+        
+            %--- Other operators ----
+            m_tot_u = obj.grid.N();
+            E = obj.E;
+            LAMBDA_u = obj.LAMBDA;
+            MU_u = obj.MU;
+            lambda_u = e'*LAMBDA_u*e;
+            mu_u = e'*MU_u*e;
+
+            m_tot_v = neighbour_scheme.grid.N();
+            E_v = neighbour_scheme.E;
+            LAMBDA_v = neighbour_scheme.LAMBDA;
+            MU_v = neighbour_scheme.MU;
+            lambda_v = e_v'*LAMBDA_v*e_v;
+            mu_v = e_v'*MU_v*e_v;
+            %-------------------------
+            
+            % Borrowing constants
+            phi_u = obj.phi{j};
+            h_u = obj.h(j);
+            h11_u = obj.H11{j}*h_u;
+            gamma_u = obj.gamma{j};
+
+            phi_v = neighbour_scheme.phi{j_v};
+            h_v = neighbour_scheme.h(j_v);
+            h11_v = neighbour_scheme.H11{j_v}*h_v;
+            gamma_v = neighbour_scheme.gamma{j_v};
+
+            % E > sum_i 1/(2*alpha_ij)*(tau_i)^2
+            function [alpha_ii, alpha_ij] = computeAlpha(phi,h,h11,gamma,lambda,mu) 
+                th1 = h11/(2*dim);
+                th2 = h11*phi/2;
+                th3 = h*gamma;
+                a1 = ( (th1 + th2)*th3*lambda + 4*th1*th2*mu ) / (2*th1*th2*th3);
+                a2 = ( 16*(th1 + th2)*lambda*mu ) / (th1*th2*th3);
+                alpha_ii = a1 + sqrt(a2 + a1^2);
+
+                alpha_ij = mu*(2/h11 + 1/(phi*h11));
+            end
+
+            [alpha_ii_u, alpha_ij_u] = computeAlpha(phi_u,h_u,h11_u,gamma_u,lambda_u,mu_u);
+            [alpha_ii_v, alpha_ij_v] = computeAlpha(phi_v,h_v,h11_v,gamma_v,lambda_v,mu_v);  
+            sigma_ii = tuning*(alpha_ii_u + alpha_ii_v)/4;
+            sigma_ij = tuning*(alpha_ij_u + alpha_ij_v)/4;
+
+            d = @kroneckerDelta;  % Kronecker delta
+            db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
+            sigma = @(i,j) tuning*(d(i,j)*sigma_ii + db(i,j)*sigma_ij);
+
+            % Preallocate
+            closure = sparse(dim*m_tot_u, dim*m_tot_u);
+            penalty = sparse(dim*m_tot_u, dim*m_tot_v);
+
+            % Loop over components that penalties end up on
+            for i = 1:dim
+                closure = closure - E{i}*RHOi*Hi*e*sigma(i,j)*H_gamma*e'*E{i}';
+                penalty = penalty + E{i}*RHOi*Hi*e*sigma(i,j)*H_gamma*e_v'*E_v{i}';
+
+                closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*e'*tau{i};
+                penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*e_v'*tau_v{i};
+
+                % Loop over components that we have interface conditions on
+                for k = 1:dim
+                    closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}'; 
+                    penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}'; 
+                end 
+            end
+        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)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch boundary
+                case {'w','W','west','West','s','S','south','South'}
+                    nj = -1;
+                case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                    nj = 1;
+            end
+        end
+
+        % Returns the boundary operator op for the boundary specified by the string boundary.
+        % op: may be a cell array of strings
+        function [varargout] = get_boundary_operator(obj, op, boundary)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            if ~iscell(op)
+                op = {op};
+            end
+
+            for i = 1:length(op)
+                switch op{i}
+                    case 'e'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.e_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.e_r{j};
+                        end
+                    case 'd'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.d1_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.d1_r{j};
+                        end
+                    case 'H'
+                        switch boundary 
+                            case {'w','W','west','West','s','S','south','South'}
+                                    varargout{i} = obj.H_boundary_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                    varargout{i} = obj.H_boundary_r{j};
+                        end
+                    case 'T'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.T_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.T_r{j};
+                        end
+                    case 'tau'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.tau_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.tau_r{j};
+                        end                        
+                    otherwise
+                        error(['No such operator: operator = ' op{i}]);
+                end
+            end
+
+        end
+
+        function N = size(obj)
+            N = obj.dim*prod(obj.m);
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Elastic2dVariable.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/Elastic2dVariable.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,512 @@
+classdef Elastic2dVariable < scheme.Scheme
+
+% Discretizes the elastic wave equation:
+% rho u_{i,tt} = di lambda dj u_j + dj mu di u_j + dj mu dj u_i
+% opSet should be cell array of opSets, one per dimension. This
+% is useful if we have periodic BC in one direction.
+
+    properties
+        m % Number of points in each direction, possibly a vector
+        h % Grid spacing
+
+        grid
+        dim
+
+        order % Order of accuracy for the approximation
+
+        % Diagonal matrices for varible coefficients
+        LAMBDA % Variable coefficient, related to dilation
+        MU     % Shear modulus, variable coefficient
+        RHO, RHOi % Density, variable
+
+        D % Total operator
+        D1 % First derivatives
+
+        % Second derivatives
+        D2_lambda
+        D2_mu
+
+        % Traction operators used for BC
+        T_l, T_r
+        tau_l, tau_r
+
+        H, Hi % Inner products
+
+        phi % Borrowing constant for (d1 - e^T*D1) from R
+        gamma % Borrowing constant for d1 from M
+        H11 % First element of H
+
+        % Borrowing from H, M, and R
+        thH
+        thM
+        thR
+
+        e_l, e_r
+        d1_l, d1_r % Normal derivatives at the boundary
+        E % E{i}^T picks out component i
+
+        H_boundary % Boundary inner products
+
+        % Kroneckered norms and coefficients
+        RHOi_kron
+        Hi_kron
+    end
+
+    methods
+
+        function obj = Elastic2dVariable(g ,order, lambda_fun, mu_fun, rho_fun, opSet)
+            default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable});
+            default_arg('lambda_fun', @(x,y) 0*x+1);
+            default_arg('mu_fun', @(x,y) 0*x+1);
+            default_arg('rho_fun', @(x,y) 0*x+1);
+            dim = 2;
+
+            assert(isa(g, 'grid.Cartesian'))
+
+            lambda = grid.evalOn(g, lambda_fun);
+            mu = grid.evalOn(g, mu_fun);
+            rho = grid.evalOn(g, rho_fun);
+            m = g.size();
+            m_tot = g.N();
+
+            h = g.scaling();
+            lim = g.lim;
+            if isempty(lim)
+                x = g.x;
+                lim = cell(length(x),1);
+                for i = 1:length(x)
+                    lim{i} = {min(x{i}), max(x{i})};
+                end
+            end
+
+            % 1D operators
+            ops = cell(dim,1);
+            for i = 1:dim
+                ops{i} = opSet{i}(m(i), lim{i}, order);
+            end
+
+            % Borrowing constants
+            for i = 1:dim
+                beta = ops{i}.borrowing.R.delta_D;
+                obj.H11{i} = ops{i}.borrowing.H11;
+                obj.phi{i} = beta/obj.H11{i};
+                obj.gamma{i} = ops{i}.borrowing.M.d1;
+
+                % Better names
+                obj.thR{i} = ops{i}.borrowing.R.delta_D;
+                obj.thM{i} = ops{i}.borrowing.M.d1;
+                obj.thH{i} = ops{i}.borrowing.H11;
+            end
+
+            I = cell(dim,1);
+            D1 = cell(dim,1);
+            D2 = cell(dim,1);
+            H = cell(dim,1);
+            Hi = cell(dim,1);
+            e_l = cell(dim,1);
+            e_r = cell(dim,1);
+            d1_l = cell(dim,1);
+            d1_r = cell(dim,1);
+
+            for i = 1:dim
+                I{i} = speye(m(i));
+                D1{i} = ops{i}.D1;
+                D2{i} = ops{i}.D2;
+                H{i} =  ops{i}.H;
+                Hi{i} = ops{i}.HI;
+                e_l{i} = ops{i}.e_l;
+                e_r{i} = ops{i}.e_r;
+                d1_l{i} = ops{i}.d1_l;
+                d1_r{i} = ops{i}.d1_r;
+            end
+
+            %====== Assemble full operators ========
+            LAMBDA = spdiag(lambda);
+            obj.LAMBDA = LAMBDA;
+            MU = spdiag(mu);
+            obj.MU = MU;
+            RHO = spdiag(rho);
+            obj.RHO = RHO;
+            obj.RHOi = inv(RHO);
+
+            obj.D1 = cell(dim,1);
+            obj.D2_lambda = cell(dim,1);
+            obj.D2_mu = cell(dim,1);
+            obj.e_l = cell(dim,1);
+            obj.e_r = cell(dim,1);
+            obj.d1_l = cell(dim,1);
+            obj.d1_r = cell(dim,1);
+
+            % D1
+            obj.D1{1} = kron(D1{1},I{2});
+            obj.D1{2} = kron(I{1},D1{2});
+
+            % Boundary operators
+            obj.e_l{1} = kron(e_l{1},I{2});
+            obj.e_l{2} = kron(I{1},e_l{2});
+            obj.e_r{1} = kron(e_r{1},I{2});
+            obj.e_r{2} = kron(I{1},e_r{2});
+
+            obj.d1_l{1} = kron(d1_l{1},I{2});
+            obj.d1_l{2} = kron(I{1},d1_l{2});
+            obj.d1_r{1} = kron(d1_r{1},I{2});
+            obj.d1_r{2} = kron(I{1},d1_r{2});
+
+            % D2
+            for i = 1:dim
+                obj.D2_lambda{i} = sparse(m_tot);
+                obj.D2_mu{i} = sparse(m_tot);
+            end
+            ind = grid.funcToMatrix(g, 1:m_tot);
+
+            for i = 1:m(2)
+                D_lambda = D2{1}(lambda(ind(:,i)));
+                D_mu = D2{1}(mu(ind(:,i)));
+
+                p = ind(:,i);
+                obj.D2_lambda{1}(p,p) = D_lambda;
+                obj.D2_mu{1}(p,p) = D_mu;
+            end
+
+            for i = 1:m(1)
+                D_lambda = D2{2}(lambda(ind(i,:)));
+                D_mu = D2{2}(mu(ind(i,:)));
+
+                p = ind(i,:);
+                obj.D2_lambda{2}(p,p) = D_lambda;
+                obj.D2_mu{2}(p,p) = D_mu;
+            end
+
+            % Quadratures
+            obj.H = kron(H{1},H{2});
+            obj.Hi = inv(obj.H);
+            obj.H_boundary = cell(dim,1);
+            obj.H_boundary{1} = H{2};
+            obj.H_boundary{2} = H{1};
+
+            % E{i}^T picks out component i.
+            E = cell(dim,1);
+            I = speye(m_tot,m_tot);
+            for i = 1:dim
+                e = sparse(dim,1);
+                e(i) = 1;
+                E{i} = kron(I,e);
+            end
+            obj.E = E;
+
+            % Differentiation matrix D (without SAT)
+            D2_lambda = obj.D2_lambda;
+            D2_mu = obj.D2_mu;
+            D1 = obj.D1;
+            D = sparse(dim*m_tot,dim*m_tot);
+            d = @kroneckerDelta;    % Kronecker delta
+            db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
+            for i = 1:dim
+                for j = 1:dim
+                    D = D + E{i}*inv(RHO)*( d(i,j)*D2_lambda{i}*E{j}' +...
+                                            db(i,j)*D1{i}*LAMBDA*D1{j}*E{j}' ...
+                                          );
+                    D = D + E{i}*inv(RHO)*( d(i,j)*D2_mu{i}*E{j}' +...
+                                            db(i,j)*D1{j}*MU*D1{i}*E{j}' + ...
+                                            D2_mu{j}*E{i}' ...
+                                          );
+                end
+            end
+            obj.D = D;
+            %=========================================%
+
+            % Numerical traction operators for BC.
+            % Because d1 =/= e0^T*D1, the numerical tractions are different
+            % at every boundary.
+            T_l = cell(dim,1);
+            T_r = cell(dim,1);
+            tau_l = cell(dim,1);
+            tau_r = cell(dim,1);
+            % tau^{j}_i = sum_k T^{j}_{ik} u_k
+
+            d1_l = obj.d1_l;
+            d1_r = obj.d1_r;
+            e_l = obj.e_l;
+            e_r = obj.e_r;
+            D1 = obj.D1;
+
+            % Loop over boundaries
+            for j = 1:dim
+                T_l{j} = cell(dim,dim);
+                T_r{j} = cell(dim,dim);
+                tau_l{j} = cell(dim,1);
+                tau_r{j} = cell(dim,1);
+
+                % Loop over components
+                for i = 1:dim
+                    tau_l{j}{i} = sparse(m_tot,dim*m_tot);
+                    tau_r{j}{i} = sparse(m_tot,dim*m_tot);
+                    for k = 1:dim
+                        T_l{j}{i,k} = ...
+                        -d(i,j)*LAMBDA*(d(i,k)*e_l{k}*d1_l{k}' + db(i,k)*D1{k})...
+                        -d(j,k)*MU*(d(i,j)*e_l{i}*d1_l{i}' + db(i,j)*D1{i})...
+                        -d(i,k)*MU*e_l{j}*d1_l{j}';
+
+                        T_r{j}{i,k} = ...
+                        d(i,j)*LAMBDA*(d(i,k)*e_r{k}*d1_r{k}' + db(i,k)*D1{k})...
+                        +d(j,k)*MU*(d(i,j)*e_r{i}*d1_r{i}' + db(i,j)*D1{i})...
+                        +d(i,k)*MU*e_r{j}*d1_r{j}';
+
+                        tau_l{j}{i} = tau_l{j}{i} + T_l{j}{i,k}*E{k}';
+                        tau_r{j}{i} = tau_r{j}{i} + T_r{j}{i,k}*E{k}';
+                    end
+
+                end
+            end
+            obj.T_l = T_l;
+            obj.T_r = T_r;
+            obj.tau_l = tau_l;
+            obj.tau_r = tau_r;
+
+            % Kroneckered norms and coefficients
+            I_dim = speye(dim);
+            obj.RHOi_kron = kron(obj.RHOi, I_dim);
+            obj.Hi_kron = kron(obj.Hi, I_dim);
+
+            % Misc.
+            obj.m = m;
+            obj.h = h;
+            obj.order = order;
+            obj.grid = g;
+            obj.dim = dim;
+
+        end
+
+
+        % Closure functions return the operators applied to the own domain to close the boundary
+        % Penalty functions return the operators 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'.
+        %       bc                  is a cell array of component and bc type, e.g. {1, 'd'} for Dirichlet condition
+        %                           on the first component.
+        %       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, bc, tuning)
+            default_arg('tuning', 1.2);
+
+            assert( iscell(bc), 'The BC type must be a 2x1 cell array' );
+            comp = bc{1};
+            type = bc{2};
+
+            % j is the coordinate direction of the boundary
+            j = obj.get_boundary_number(boundary);
+            [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
+
+            E = obj.E;
+            Hi = obj.Hi;
+            LAMBDA = obj.LAMBDA;
+            MU = obj.MU;
+            RHOi = obj.RHOi;
+
+            dim = obj.dim;
+            m_tot = obj.grid.N();
+
+            % Preallocate
+            closure = sparse(dim*m_tot, dim*m_tot);
+            penalty = sparse(dim*m_tot, m_tot/obj.m(j));
+
+            k = comp;
+            switch type
+
+            % Dirichlet boundary condition
+            case {'D','d','dirichlet','Dirichlet'}
+
+                phi = obj.phi{j};
+                h = obj.h(j);
+                h11 = obj.H11{j}*h;
+                gamma = obj.gamma{j};
+
+                a_lambda = dim/h11 + 1/(h11*phi);
+                a_mu_i = 2/(gamma*h);
+                a_mu_ij = 2/h11 + 1/(h11*phi);
+
+                d = @kroneckerDelta;  % Kronecker delta
+                db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
+                alpha = @(i,j) tuning*( d(i,j)* a_lambda*LAMBDA ...
+                                      + d(i,j)* a_mu_i*MU ...
+                                      + db(i,j)*a_mu_ij*MU );
+
+                % Loop over components that Dirichlet penalties end up on
+                for i = 1:dim
+                    C = T{k,i};
+                    A = -d(i,k)*alpha(i,j);
+                    B = A + C;
+                    closure = closure + E{i}*RHOi*Hi*B'*e*H_gamma*(e'*E{k}' );
+                    penalty = penalty - E{i}*RHOi*Hi*B'*e*H_gamma;
+                end
+
+            % Free boundary condition
+            case {'F','f','Free','free','traction','Traction','t','T'}
+                    closure = closure - E{k}*RHOi*Hi*e*H_gamma* (e'*tau{k} );
+                    penalty = penalty + E{k}*RHOi*Hi*e*H_gamma;
+
+            % Unknown boundary condition
+            otherwise
+                error('No such boundary condition: type = %s',type);
+            end
+        end
+
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            % Operators without subscripts are from the own domain.
+            tuning = 1.2;
+
+            % j is the coordinate direction of the boundary
+            j = obj.get_boundary_number(boundary);
+            j_v = neighbour_scheme.get_boundary_number(neighbour_boundary);
+
+            % Get boundary operators
+            [e, T, tau, H_gamma] = obj.get_boundary_operator({'e','T','tau','H'}, boundary);
+            [e_v, tau_v] = neighbour_scheme.get_boundary_operator({'e','tau'}, neighbour_boundary);
+
+            % Operators and quantities that correspond to the own domain only
+            Hi = obj.Hi;
+            RHOi = obj.RHOi;
+            dim = obj.dim;
+
+            %--- Other operators ----
+            m_tot_u = obj.grid.N();
+            E = obj.E;
+            LAMBDA_u = obj.LAMBDA;
+            MU_u = obj.MU;
+            lambda_u = e'*LAMBDA_u*e;
+            mu_u = e'*MU_u*e;
+
+            m_tot_v = neighbour_scheme.grid.N();
+            E_v = neighbour_scheme.E;
+            LAMBDA_v = neighbour_scheme.LAMBDA;
+            MU_v = neighbour_scheme.MU;
+            lambda_v = e_v'*LAMBDA_v*e_v;
+            mu_v = e_v'*MU_v*e_v;
+            %-------------------------
+
+            % Borrowing constants
+            h_u = obj.h(j);
+            thR_u = obj.thR{j}*h_u;
+            thM_u = obj.thM{j}*h_u;
+            thH_u = obj.thH{j}*h_u;
+
+            h_v = neighbour_scheme.h(j_v);
+            thR_v = neighbour_scheme.thR{j_v}*h_v;
+            thH_v = neighbour_scheme.thH{j_v}*h_v;
+            thM_v = neighbour_scheme.thM{j_v}*h_v;
+
+            % alpha = penalty strength for normal component, beta for tangential
+            alpha_u = dim*lambda_u/(4*thH_u) + lambda_u/(4*thR_u) + mu_u/(2*thM_u);
+            alpha_v = dim*lambda_v/(4*thH_v) + lambda_v/(4*thR_v) + mu_v/(2*thM_v);
+            beta_u = mu_u/(2*thH_u) + mu_u/(4*thR_u);
+            beta_v = mu_v/(2*thH_v) + mu_v/(4*thR_v);
+            alpha = alpha_u + alpha_v;
+            beta = beta_u + beta_v;
+
+            d = @kroneckerDelta;  % Kronecker delta
+            db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
+            strength = @(i,j) tuning*(d(i,j)*alpha + db(i,j)*beta);
+
+            % Preallocate
+            closure = sparse(dim*m_tot_u, dim*m_tot_u);
+            penalty = sparse(dim*m_tot_u, dim*m_tot_v);
+
+            % Loop over components that penalties end up on
+            for i = 1:dim
+                closure = closure - E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e'*E{i}';
+                penalty = penalty + E{i}*RHOi*Hi*e*strength(i,j)*H_gamma*e_v'*E_v{i}';
+
+                closure = closure - 1/2*E{i}*RHOi*Hi*e*H_gamma*e'*tau{i};
+                penalty = penalty - 1/2*E{i}*RHOi*Hi*e*H_gamma*e_v'*tau_v{i};
+
+                % Loop over components that we have interface conditions on
+                for k = 1:dim
+                    closure = closure + 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e'*E{k}';
+                    penalty = penalty - 1/2*E{i}*RHOi*Hi*T{k,i}'*e*H_gamma*e_v'*E_v{k}';
+                end
+            end
+        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)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch boundary
+                case {'w','W','west','West','s','S','south','South'}
+                    nj = -1;
+                case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                    nj = 1;
+            end
+        end
+
+        % Returns the boundary operator op for the boundary specified by the string boundary.
+        % op: may be a cell array of strings
+        function [varargout] = get_boundary_operator(obj, op, boundary)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            if ~iscell(op)
+                op = {op};
+            end
+
+            for i = 1:length(op)
+                switch op{i}
+                    case 'e'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.e_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.e_r{j};
+                        end
+                    case 'd'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.d1_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.d1_r{j};
+                        end
+                    case 'H'
+                        varargout{i} = obj.H_boundary{j};
+                    case 'T'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.T_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.T_r{j};
+                        end
+                    case 'tau'
+                        switch boundary
+                            case {'w','W','west','West','s','S','south','South'}
+                                varargout{i} = obj.tau_l{j};
+                            case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                                varargout{i} = obj.tau_r{j};
+                        end
+                    otherwise
+                        error(['No such operator: operator = ' op{i}]);
+                end
+            end
+
+        end
+
+        function N = size(obj)
+            N = obj.dim*prod(obj.m);
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Heat2dCurvilinear.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/Heat2dCurvilinear.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,385 @@
+classdef Heat2dCurvilinear < scheme.Scheme
+
+% Discretizes the Laplacian with variable coefficent, curvilinear,
+% in the Heat equation way (i.e., the discretization matrix is not necessarily 
+% symmetric)
+% 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.
+
+    properties
+        m % Number of points in each direction, possibly a vector
+        h % Grid spacing
+
+        grid
+        dim
+
+        order % Order of accuracy for the approximation
+
+        % Diagonal matrix for variable coefficients
+        KAPPA % Variable coefficient
+
+        D % Total operator
+        D1 % First derivatives
+
+        % Second derivatives
+        D2_kappa
+
+        H, Hi % Inner products
+        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 
+
+        % Metric coefficients
+        b % Cell matrix of size dim x dim
+        J, Ji
+        beta % Cell array of scale factors
+
+        % Numerical boundary flux operators
+        flux_l, flux_r
+
+    end
+
+    methods
+
+        function obj = Heat2dCurvilinear(g ,order, kappa_fun, opSet)
+            default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable});
+            default_arg('kappa_fun', @(x,y) 0*x+1);
+            dim = 2;
+
+            kappa = grid.evalOn(g, kappa_fun);
+            m = g.size();
+            m_tot = g.N();
+
+            % 1D operators
+            ops = cell(dim,1);
+            for i = 1:dim
+                ops{i} = opSet{i}(m(i), {0, 1}, order);
+            end
+
+            I = cell(dim,1);
+            D1 = cell(dim,1);
+            D2 = cell(dim,1);
+            H = cell(dim,1);
+            Hi = cell(dim,1);
+            e_l = cell(dim,1);
+            e_r = cell(dim,1);
+            d1_l = cell(dim,1);
+            d1_r = cell(dim,1);
+
+            for i = 1:dim
+                I{i} = speye(m(i));
+                D1{i} = ops{i}.D1;
+                D2{i} = ops{i}.D2;
+                H{i} =  ops{i}.H;
+                Hi{i} = ops{i}.HI;
+                e_l{i} = ops{i}.e_l;
+                e_r{i} = ops{i}.e_r;
+                d1_l{i} = ops{i}.d1_l;
+                d1_r{i} = ops{i}.d1_r;
+            end
+
+            %====== Assemble full operators ========
+            KAPPA = spdiag(kappa);
+            obj.KAPPA = KAPPA;
+
+            % Allocate
+            obj.D1 = cell(dim,1);
+            obj.D2_kappa = cell(dim,1);
+            obj.e_l = cell(dim,1);
+            obj.e_r = cell(dim,1);
+            obj.d1_l = cell(dim,1);
+            obj.d1_r = cell(dim,1);
+
+            % D1
+            obj.D1{1} = kron(D1{1},I{2});
+            obj.D1{2} = kron(I{1},D1{2});
+
+            % -- Metric coefficients ----
+            coords = g.points();
+            x = coords(:,1);
+            y = coords(:,2);
+
+            % Use non-periodic difference operators for metric even if opSet is periodic.
+            xmax = max(ops{1}.x);
+            ymax = max(ops{2}.x);
+            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); 
+
+            x_xi = D1Metric{1}*x;
+            x_eta = D1Metric{2}*x;
+            y_xi = D1Metric{1}*y;
+            y_eta = D1Metric{2}*y;
+
+            J = x_xi.*y_eta - x_eta.*y_xi;
+
+            b = cell(dim,dim);
+            b{1,1} = y_eta./J;
+            b{1,2} = -x_eta./J;
+            b{2,1} = -y_xi./J;
+            b{2,2} = x_xi./J;
+
+            % Scale factors for boundary integrals
+            beta = cell(dim,1);
+            beta{1} = sqrt(x_eta.^2 + y_eta.^2);
+            beta{2} = sqrt(x_xi.^2 + y_xi.^2);
+
+            J = spdiag(J);
+            Ji = inv(J);
+            for i = 1:dim
+                beta{i} = spdiag(beta{i});
+                for j = 1:dim
+                    b{i,j} = spdiag(b{i,j});
+                end
+            end
+            obj.J = J;
+            obj.Ji = Ji;
+            obj.b = b;
+            obj.beta = beta;
+            %----------------------------
+
+            % Boundary operators
+            obj.e_l{1} = kron(e_l{1},I{2});
+            obj.e_l{2} = kron(I{1},e_l{2});
+            obj.e_r{1} = kron(e_r{1},I{2});
+            obj.e_r{2} = kron(I{1},e_r{2});
+
+            obj.d1_l{1} = kron(d1_l{1},I{2});
+            obj.d1_l{2} = kron(I{1},d1_l{2});
+            obj.d1_r{1} = kron(d1_r{1},I{2});
+            obj.d1_r{2} = kron(I{1},d1_r{2});
+
+            % D2 coefficients
+            kappa_coeff = cell(dim,dim);
+            for j = 1:dim
+                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;
+                end
+            end
+            ind = grid.funcToMatrix(g, 1:m_tot);
+
+            % x-dir
+            j = 1;
+            for col = 1:m(2)
+                D_kappa = D2{1}(kappa_coeff{j}(ind(:,col)));
+
+                p = ind(:,col);
+                obj.D2_kappa{j}(p,p) = D_kappa;
+            end
+
+            % y-dir
+            j = 2;
+            for row = 1:m(1)
+                D_kappa = D2{2}(kappa_coeff{j}(ind(row,:)));
+
+                p = ind(row,:);
+                obj.D2_kappa{j}(p,p) = D_kappa;
+            end
+
+            % Quadratures
+            obj.H = kron(H{1},H{2});
+            obj.Hi = inv(obj.H);
+            obj.H_boundary_l = cell(dim,1);
+            obj.H_boundary_l{1} = obj.e_l{1}'*beta{1}*obj.e_l{1}*H{2};
+            obj.H_boundary_l{2} = obj.e_l{2}'*beta{2}*obj.e_l{2}*H{1};
+            obj.H_boundary_r = cell(dim,1);
+            obj.H_boundary_r{1} = obj.e_r{1}'*beta{1}*obj.e_r{1}*H{2};
+            obj.H_boundary_r{2} = obj.e_r{2}'*beta{2}*obj.e_r{2}*H{1};
+
+            %=== Differentiation matrix D (without SAT) ===
+            D2_kappa = obj.D2_kappa;
+            D1 = obj.D1;
+            D = sparse(m_tot,m_tot);
+
+            d = @kroneckerDelta;    % Kronecker delta
+            db = @(i,j) 1-d(i,j); % Logical not of Kronecker delta
+
+            % 2nd derivatives
+            for j = 1:dim
+                D = D + Ji*D2_kappa{j};
+            end
+
+            % Mixed terms
+            for i = 1:dim
+                for j = 1:dim
+                    for k = 1:dim
+                        D = D + db(i,j)*Ji*D1{j}*b{i,j}*J*KAPPA*b{i,k}*D1{k};
+                    end
+                end
+            end
+            obj.D = D;
+            %=========================================%
+
+            % Normal flux operators for BC.
+            flux_l = cell(dim,1);
+            flux_r = cell(dim,1);
+
+            d1_l = obj.d1_l;
+            d1_r = obj.d1_r;
+            e_l = obj.e_l;
+            e_r = obj.e_r;
+
+            % Loop over boundaries
+            for j = 1:dim
+                flux_l{j} = sparse(m_tot,m_tot);
+                flux_r{j} = sparse(m_tot,m_tot);
+
+                % Loop over dummy index
+                for i = 1:dim
+                    % Loop over dummy index
+                    for k = 1:dim
+                        flux_l{j} = flux_l{j} ...
+                                  - beta{j}\b{i,j}*J*KAPPA*b{i,k}*( d(j,k)*e_l{k}*d1_l{k}' + db(j,k)*D1{k} );
+
+                        flux_r{j} = flux_r{j} ...
+                                  + beta{j}\b{i,j}*J*KAPPA*b{i,k}*( d(j,k)*e_r{k}*d1_r{k}' + db(j,k)*D1{k} );
+                    end
+
+                end
+            end
+            obj.flux_l = flux_l;
+            obj.flux_r = flux_r;
+
+            % Misc.
+            obj.m = m;
+            obj.h = g.scaling();
+            obj.order = order;
+            obj.grid = g;
+            obj.dim = dim;
+            obj.alpha = [ops{1}.borrowing.M.d1, ops{2}.borrowing.M.d1];
+
+        end
+
+
+        % Closure functions return the operators applied to the own domain to close the boundary
+        % Penalty functions return the operators 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.
+        %       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, symmetric, tuning)
+            default_arg('type','Neumann');
+            default_arg('symmetric', false);
+            default_arg('tuning',1.2);
+
+            % 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{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
+
+            Hi = obj.Hi;
+            Ji = obj.Ji;
+            KAPPA = obj.KAPPA;
+            kappa_gamma = e'*KAPPA*e; 
+            h = obj.h(j);
+            alpha = h*obj.alpha(j);
+
+            switch type
+
+            % Dirichlet boundary condition
+            case {'D','d','dirichlet','Dirichlet'}
+
+                if ~symmetric
+                    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' ) ; 
+                    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; 
+
+            % Unknown boundary condition
+            otherwise
+                error('No such boundary condition: type = %s',type);
+            end
+        end
+
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            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)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch boundary
+                case {'w','W','west','West','s','S','south','South'}
+                    nj = -1;
+                case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                    nj = 1;
+            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)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch op
+                case 'e'
+                    switch boundary
+                        case {'w','W','west','West','s','S','south','South'}
+                            return_op = obj.e_l{j};
+                        case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                            return_op = obj.e_r{j};
+                    end
+                case 'd'
+                    switch boundary
+                        case {'w','W','west','West','s','S','south','South'}
+                            return_op = obj.d1_l{j};
+                        case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                            return_op = obj.d1_r{j};
+                    end
+                otherwise
+                    error(['No such operator: operatr = ' op]);
+            end
+
+        end
+
+        function N = size(obj)
+            N = prod(obj.m);
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Heat2dVariable.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/Heat2dVariable.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,276 @@
+classdef Heat2dVariable < scheme.Scheme
+
+% Discretizes the Laplacian with variable coefficent,
+% In the Heat equation way (i.e., the discretization matrix is not necessarily 
+% symmetric)
+% 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.
+
+    properties
+        m % Number of points in each direction, possibly a vector
+        h % Grid spacing
+
+        grid
+        dim
+
+        order % Order of accuracy for the approximation
+
+        % Diagonal matrix for variable coefficients
+        KAPPA % Variable coefficient
+
+        D % Total operator
+        D1 % First derivatives
+
+        % Second derivatives
+        D2_kappa
+
+        H, Hi % Inner products
+        e_l, e_r
+        d1_l, d1_r % Normal derivatives at the boundary
+        alpha % Vector of borrowing constants
+        
+        H_boundary % Boundary inner products
+
+    end
+
+    methods
+
+        function obj = Heat2dVariable(g ,order, kappa_fun, opSet)
+            default_arg('opSet',{@sbp.D2Variable, @sbp.D2Variable});
+            default_arg('kappa_fun', @(x,y) 0*x+1);
+            dim = 2;
+
+            assert(isa(g, 'grid.Cartesian'))
+
+            kappa = grid.evalOn(g, kappa_fun);
+            m = g.size();
+            m_tot = g.N();
+
+            h = g.scaling();
+            lim = g.lim;
+
+            % 1D operators
+            ops = cell(dim,1);
+            for i = 1:dim
+                ops{i} = opSet{i}(m(i), lim{i}, order);
+            end
+
+            I = cell(dim,1);
+            D1 = cell(dim,1);
+            D2 = cell(dim,1);
+            H = cell(dim,1);
+            Hi = cell(dim,1);
+            e_l = cell(dim,1);
+            e_r = cell(dim,1);
+            d1_l = cell(dim,1);
+            d1_r = cell(dim,1);
+
+            for i = 1:dim
+                I{i} = speye(m(i));
+                D1{i} = ops{i}.D1;
+                D2{i} = ops{i}.D2;
+                H{i} =  ops{i}.H;
+                Hi{i} = ops{i}.HI;
+                e_l{i} = ops{i}.e_l;
+                e_r{i} = ops{i}.e_r;
+                d1_l{i} = ops{i}.d1_l;
+                d1_r{i} = ops{i}.d1_r;
+            end
+
+            %====== Assemble full operators ========
+            KAPPA = spdiag(kappa);
+            obj.KAPPA = KAPPA;
+
+            obj.D1 = cell(dim,1);
+            obj.D2_kappa = cell(dim,1);
+            obj.e_l = cell(dim,1);
+            obj.e_r = cell(dim,1);
+            obj.d1_l = cell(dim,1);
+            obj.d1_r = cell(dim,1);
+
+            % D1
+            obj.D1{1} = kron(D1{1},I{2});
+            obj.D1{2} = kron(I{1},D1{2});
+
+            % Boundary operators
+            obj.e_l{1} = kron(e_l{1},I{2});
+            obj.e_l{2} = kron(I{1},e_l{2});
+            obj.e_r{1} = kron(e_r{1},I{2});
+            obj.e_r{2} = kron(I{1},e_r{2});
+
+            obj.d1_l{1} = kron(d1_l{1},I{2});
+            obj.d1_l{2} = kron(I{1},d1_l{2});
+            obj.d1_r{1} = kron(d1_r{1},I{2});
+            obj.d1_r{2} = kron(I{1},d1_r{2});
+
+            % D2
+            for i = 1:dim
+                obj.D2_kappa{i} = sparse(m_tot);
+            end
+            ind = grid.funcToMatrix(g, 1:m_tot);
+
+            for i = 1:m(2)
+                D_kappa = D2{1}(kappa(ind(:,i)));
+                p = ind(:,i);
+                obj.D2_kappa{1}(p,p) = D_kappa;
+            end
+
+            for i = 1:m(1)
+                D_kappa = D2{2}(kappa(ind(i,:)));
+                p = ind(i,:);
+                obj.D2_kappa{2}(p,p) = D_kappa;
+            end
+
+            % Quadratures
+            obj.H = kron(H{1},H{2});
+            obj.Hi = inv(obj.H);
+            obj.H_boundary = cell(dim,1);
+            obj.H_boundary{1} = H{2};
+            obj.H_boundary{2} = H{1};
+
+            % Differentiation matrix D (without SAT)
+            D2_kappa = obj.D2_kappa;
+            D1 = obj.D1;
+            D = sparse(m_tot,m_tot);
+            for i = 1:dim
+                D = D + D2_kappa{i};
+            end
+            obj.D = D;
+            %=========================================%
+
+            % Misc.
+            obj.m = m;
+            obj.h = h;
+            obj.order = order;
+            obj.grid = g;
+            obj.dim = dim;
+            obj.alpha = [ops{1}.borrowing.M.d1, ops{2}.borrowing.M.d1];
+
+        end
+
+
+        % Closure functions return the operators applied to the own domain to close the boundary
+        % Penalty functions return the operators 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.
+        %       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, symmetric, tuning)
+            default_arg('type','Neumann');
+            default_arg('symmetric', false);
+            default_arg('tuning',1.2);
+
+            % 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
+
+            Hi = obj.Hi;
+            H_gamma = obj.H_boundary{j};
+            KAPPA = obj.KAPPA;
+            kappa_gamma = e{j}'*KAPPA*e{j}; 
+            h = obj.h(j);
+            alpha = h*obj.alpha(j);
+
+            switch type
+
+            % Dirichlet boundary condition
+            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;
+                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;
+                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; 
+                    % penalty is for normal derivative and not for derivative, hence the sign.
+
+            % Unknown boundary condition
+            otherwise
+                error('No such boundary condition: type = %s',type);
+            end
+        end
+
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            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)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch boundary
+                case {'w','W','west','West','s','S','south','South'}
+                    nj = -1;
+                case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                    nj = 1;
+            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)
+
+            switch boundary
+                case {'w','W','west','West', 'e', 'E', 'east', 'East'}
+                    j = 1;
+                case {'s','S','south','South', 'n', 'N', 'north', 'North'}
+                    j = 2;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch op
+                case 'e'
+                    switch boundary
+                        case {'w','W','west','West','s','S','south','South'}
+                            return_op = obj.e_l{j};
+                        case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                            return_op = obj.e_r{j};
+                    end
+                case 'd'
+                    switch boundary
+                        case {'w','W','west','West','s','S','south','South'}
+                            return_op = obj.d1_l{j};
+                        case {'e', 'E', 'east', 'East','n', 'N', 'north', 'North'}
+                            return_op = obj.d1_r{j};
+                    end
+                otherwise
+                    error(['No such operator: operatr = ' op]);
+            end
+
+        end
+
+        function N = size(obj)
+            N = prod(obj.m);
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/LaplaceCurvilinear.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/LaplaceCurvilinear.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,349 @@
+classdef LaplaceCurvilinear < scheme.Scheme
+    properties
+        m % Number of points in each direction, possibly a vector
+        h % Grid spacing
+
+        grid
+
+        order % Order 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
+        x_u
+        x_v
+        y_u
+        y_v
+
+        % 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
+        gamm_u, gamm_v
+        lambda
+    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 = 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
+
+            assert(isa(g, 'grid.Curvilinear'))
+
+            m = g.size();
+            m_u = m(1);
+            m_v = m(2);
+            m_tot = g.N();
+
+            h = g.scaling();
+            h_u = h(1);
+            h_v = h(2);
+
+
+            % 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));
+
+            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;
+
+            Duu = sparse(m_tot);
+            Dvv = sparse(m_tot);
+            ind = grid.funcToMatrix(g, 1:m_tot);
+
+            for i = 1:m_v
+                D = D2_u(a11(ind(:,i)));
+                p = ind(:,i);
+                Duu(p,p) = D;
+            end
+
+            for i = 1:m_u
+                D = D2_v(a22(ind(i,:)));
+                p = ind(i,:);
+                Dvv(p,p) = D;
+            end
+
+
+            % 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.a = a;
+            obj.b = b;
+            obj.a11 = a11;
+            obj.a12 = a12;
+            obj.a22 = a22;
+            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, d, gamm, H_b, ~] = obj.get_boundary_ops(boundary);
+            switch type
+                % Dirichlet boundary condition
+                case {'D','d','dirichlet'}
+                    tuning = 1.2;
+                    % tuning = 20.2;
+
+                    b1 = gamm*obj.lambda./obj.a11.^2;
+                    b2 = gamm*obj.lambda./obj.a22.^2;
+
+                    tau1 = tuning * spdiag(-1./b1 - 1./b2);
+                    tau2 = 1;
+
+                    tau = (tau1*e + tau2*d)*H_b;
+
+                    closure =  obj.a*obj.Hi*tau*e';
+                    penalty = -obj.a*obj.Hi*tau;
+
+
+                % Neumann boundary condition
+                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;
+
+
+                % Unknown, boundary condition
+                otherwise
+                    error('No such boundary condition: type = %s',type);
+            end
+        end
+
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            tuning = 1.2;
+            % tuning = 20.2;
+            [e_u, d_u, gamm_u, H_b_u, I_u] = obj.get_boundary_ops(boundary);
+            [e_v, d_v, gamm_v, H_b_v, I_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary);
+
+            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;
+
+            tau1 = -1./(4*b1_u) -1./(4*b1_v) -1./(4*b2_u) -1./(4*b2_v);
+            tau1 = tuning * spdiag(tau1);
+            tau2 = 1/2;
+
+            sig1 = -1/2;
+            sig2 = 0;
+
+            tau = (e_u*tau1 + tau2*d_u)*H_b_u;
+            sig = (sig1*e_u + sig2*d_u)*H_b_u;
+
+            closure = obj.a*obj.Hi*( tau*e_u' + sig*d_u');
+            penalty = obj.a*obj.Hi*(-tau*e_v' + sig*d_v');
+        end
+
+        % Ruturns the boundary ops and sign for the boundary specified by the string boundary.
+        % The right boundary is considered the positive boundary
+        %
+        %  I -- the indecies of the boundary points in the grid matrix
+        function [e, d, gamm, H_b, I] = get_boundary_ops(obj, boundary)
+
+            % gridMatrix = zeros(obj.m(2),obj.m(1));
+            % gridMatrix(:) = 1:numel(gridMatrix);
+
+            ind = grid.funcToMatrix(obj.grid, 1:prod(obj.m));
+
+            switch boundary
+                case 'w'
+                    e = obj.e_w;
+                    d = obj.d_w;
+                    H_b = obj.H_w;
+                    I = ind(1,:);
+                case 'e'
+                    e = obj.e_e;
+                    d = obj.d_e;
+                    H_b = obj.H_e;
+                    I = ind(end,:);
+                case 's'
+                    e = obj.e_s;
+                    d = obj.d_s;
+                    H_b = obj.H_s;
+                    I = ind(:,1)';
+                case 'n'
+                    e = obj.e_n;
+                    d = obj.d_n;
+                    H_b = obj.H_n;
+                    I = ind(:,end)';
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch boundary
+                case {'w','e'}
+                    gamm = obj.gamm_u;
+                case {'s','n'}
+                    gamm = obj.gamm_v;
+            end
+        end
+
+        function N = size(obj)
+            N = prod(obj.m);
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Scheme.m
--- a/+scheme/Scheme.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+scheme/Scheme.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,42 +1,47 @@
-% Start with all matrix returns. When that works see how we should generalize to non-matrix stuff/nonlinear
+% Start with all matrix returns. When that works see how we should generalize
+% to non-matrix stuff/nonlinear
 classdef Scheme < handle
     properties (Abstract)
-        m % Number of points in each direction, possibly a vector
         order % Order accuracy for the approximation
 
-        % vectors u,v,w depending on dim that gives were gridpoints are in each dimension
-        % vectors x,y,z containing the x,y,z values corresponding to each grid point
-        % matrices X,Y,Z with point coordinates as multi dimensional vectors
+        grid
 
         D % non-stabalized scheme operator
         H % Discrete norm
-
-        % Should also containg:
-        % the grid points used
-        % the grid spacing
     end
 
     methods (Abstract)
-        % 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.
-        m = boundary_condition(obj,boundary,type,data)
-        m = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
-        N = size(obj) % Returns the number of degrees of freedom.
+        % 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. In some cases the penalty return value
+        % can be ommited and the closure function take care of both parts.
+        %       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.
+        %       neighbour_scheme    is an instance of Scheme that should be
+        %                           interfaced to.
+        %       neighbour_boundary  is a string specifying which boundary to
+        %                           interface to.
+        %       penalty  may be a cell array if there are several penalties with different weights
+        [closure, penalty] = boundary_condition(obj,boundary,type) % TODO: Change name to boundaryCondition
+        [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
 
+        % TODO: op = getBoundaryOperator()??
+        %   makes sense to have it available through a method instead of random properties
+
+        % Returns the number of degrees of freedom.
+        N = size(obj)
     end
 
     methods(Static)
-        % Calculates the matrcis need for the inteface coupling between boundary bound_u of scheme schm_u
-        % and bound_v of scheme schm_v.
-        %   [uu, uv, vv, vu] = inteface_couplong(A,'r',B,'l')
+        % Calculates the matrcis need for the inteface coupling between
+        % boundary bound_u of scheme schm_u and bound_v of scheme schm_v.
+        %   [uu, uv, vv, vu] = inteface_coupling(A,'r',B,'l')
         function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v)
             [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v);
             [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u);
         end
     end
-end
\ No newline at end of file
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/TODO.txt
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/TODO.txt	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,1 @@
+% TODO: Rename package and abstract class to diffOp
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/Wave2dCurve.m
--- a/+scheme/Wave2dCurve.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+scheme/Wave2dCurve.m	Fri Sep 07 14:40:58 2018 +0200
@@ -2,9 +2,9 @@
     properties
         m % Number of points in each direction, possibly a vector
         h % Grid spacing
-        u,v % Grid
-        x,y % Values of x and y for each grid point
-        X,Y % Grid point locations as matrices
+
+        grid
+
         order % Order accuracy for the approximation
 
         D % non-stabalized scheme operator
@@ -26,24 +26,32 @@
         du_n, dv_n
         gamm_u, gamm_v
         lambda
+
+        Dx, Dy % Physical derivatives
+
+        x_u
+        x_v
+        y_u
+        y_v
     end
 
     methods
-        function obj = Wave2dCurve(m,ti,order,c,opSet)
+        function obj = Wave2dCurve(g ,order, c, opSet)
             default_arg('opSet',@sbp.D2Variable);
             default_arg('c', 1);
 
-            if length(m) == 1
-                m = [m m];
-            end
+            warning('Use LaplaceCruveilinear instead')
 
+            assert(isa(g, 'grid.Curvilinear'))
+
+            m = g.size();
             m_u = m(1);
             m_v = m(2);
-            m_tot = m_u*m_v;
+            m_tot = g.N();
 
-            [u, h_u] = util.get_grid(0, 1, m_u);
-            [v, h_v] = util.get_grid(0, 1, m_v);
-
+            h = g.scaling();
+            h_u = h(1);
+            h_v = h(2);
 
             % Operators
             ops_u = opSet(m_u, {0, 1}, order);
@@ -52,66 +60,64 @@
             I_u = speye(m_u);
             I_v = speye(m_v);
 
-            D1_u = sparse(ops_u.D1);
+            D1_u = ops_u.D1;
             D2_u = ops_u.D2;
-            H_u =  sparse(ops_u.H);
-            Hi_u = sparse(ops_u.HI);
-            % M_u =  sparse(ops_u.M);
-            e_l_u = sparse(ops_u.e_l);
-            e_r_u = sparse(ops_u.e_r);
-            d1_l_u = sparse(ops_u.d1_l);
-            d1_r_u = sparse(ops_u.d1_r);
+            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 = sparse(ops_v.D1);
+            D1_v = ops_v.D1;
             D2_v = ops_v.D2;
-            H_v =  sparse(ops_v.H);
-            Hi_v = sparse(ops_v.HI);
-            % M_v =  sparse(ops_v.M);
-            e_l_v = sparse(ops_v.e_l);
-            e_r_v = sparse(ops_v.e_r);
-            d1_l_v = sparse(ops_v.d1_l);
-            d1_r_v = sparse(ops_v.d1_r);
+            H_v =  ops_v.H;
+            Hi_v = ops_v.HI;
+            e_l_v = ops_v.e_l;
+            e_r_v = ops_v.e_r;
+            d1_l_v = ops_v.d1_l;
+            d1_r_v = ops_v.d1_r;
+
+            Du = kr(D1_u,I_v);
+            Dv = kr(I_u,D1_v);
 
             % Metric derivatives
-            [X,Y] = ti.map(u,v);
+            coords = g.points();
+            x = coords(:,1);
+            y = coords(:,2);
 
-            [x_u,x_v] = gridDerivatives(X,D1_u,D1_v);
-            [y_u,y_v] = gridDerivatives(Y,D1_u,D1_v);
-
-
+            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);  %% GÖR SOM MATRISER
+            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));
 
-            dof_order = reshape(1:m_u*m_v,m_v,m_u);
+            % Assemble full operators
+            L_12 = spdiags(a12, 0, m_tot, m_tot);
+            Duv = Du*L_12*Dv;
+            Dvu = Dv*L_12*Du;
 
             Duu = sparse(m_tot);
             Dvv = sparse(m_tot);
+            ind = grid.funcToMatrix(g, 1:m_tot);
 
             for i = 1:m_v
-                D = D2_u(a11(i,:));
-                p = dof_order(i,:);
+                D = D2_u(a11(ind(:,i)));
+                p = ind(:,i);
                 Duu(p,p) = D;
             end
 
             for i = 1:m_u
-                D = D2_v(a22(:,i));
-                p = dof_order(:,i);
+                D = D2_v(a22(ind(i,:)));
+                p = ind(i,:);
                 Dvv(p,p) = D;
             end
 
-            L_12 = spdiags(a12(:),0,m_tot,m_tot);
-            Du = kr(D1_u,I_v);
-            Dv = kr(I_u,D1_v);
-
-            Duv = Du*L_12*Dv;
-            Dvu = Dv*L_12*Du;
-
-
-
             obj.H = kr(H_u,H_v);
             obj.Hi = kr(Hi_u,Hi_v);
             obj.Hu  = kr(H_u,I_v);
@@ -119,7 +125,6 @@
             obj.Hiu = kr(Hi_u,I_v);
             obj.Hiv = kr(I_u,Hi_v);
 
-            % obj.M = kr(M_u,H_v)+kr(H_u,M_v);
             obj.e_w  = kr(e_l_u,I_v);
             obj.e_e  = kr(e_r_u,I_v);
             obj.e_s  = kr(I_u,e_l_v);
@@ -133,28 +138,30 @@
             obj.du_n = (obj.e_n'*Du)';
             obj.dv_n = kr(I_u,d1_r_v);
 
+            obj.x_u = x_u;
+            obj.x_v = x_v;
+            obj.y_u = y_u;
+            obj.y_v = y_v;
+
             obj.m = m;
             obj.h = [h_u h_v];
             obj.order = order;
-
+            obj.grid = g;
 
             obj.c = c;
-            obj.J = spdiags(J(:),0,m_tot,m_tot);
-            obj.Ji = spdiags(1./J(:),0,m_tot,m_tot);
+            obj.J = spdiags(J, 0, m_tot, m_tot);
+            obj.Ji = spdiags(1./J, 0, m_tot, m_tot);
             obj.a11 = a11;
             obj.a12 = a12;
             obj.a22 = a22;
             obj.D = obj.Ji*c^2*(Duu + Duv + Dvu + Dvv);
-            obj.u = u;
-            obj.v = v;
-            obj.X = X;
-            obj.Y = Y;
-            obj.x = X(:);
-            obj.y = Y(:);
             obj.lambda = lambda;
 
-            obj.gamm_u = h_u*ops_u.borrowing.M.S;
-            obj.gamm_v = h_v*ops_v.borrowing.M.S;
+            obj.Dx = spdiag( y_v./J)*Du + spdiag(-y_u./J)*Dv;
+            obj.Dy = spdiag(-x_v./J)*Du + spdiag( x_u./J)*Dv;
+
+            obj.gamm_u = h_u*ops_u.borrowing.M.d1;
+            obj.gamm_v = h_v*ops_v.borrowing.M.d1;
         end
 
 
@@ -165,12 +172,11 @@
         %       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,data)
+        function [closure, penalty] = boundary_condition(obj, boundary, type, parameter)
             default_arg('type','neumann');
-            default_arg('data',0);
+            default_arg('parameter', []);
 
-            [e, d_n, d_t, coeff_n, coeff_t, s, gamm, halfnorm_inv] = obj.get_boundary_ops(boundary);
-
+            [e, d_n, d_t, coeff_n, coeff_t, s, gamm, halfnorm_inv  ,              ~,          ~, ~, scale_factor] = obj.get_boundary_ops(boundary);
             switch type
                 % Dirichlet boundary condition
                 case {'D','d','dirichlet'}
@@ -190,28 +196,19 @@
                     b2 = gamm*u.lambda./u.a22.^2;
 
                     tau  = -1./b1 - 1./b2;
-                    tau = tuning * spdiag(tau(:));
-                    sig1 = 1/2;
+                    tau = tuning * spdiag(tau);
+                    sig1 = 1;
 
                     penalty_parameter_1 = halfnorm_inv_n*(tau + sig1*halfnorm_inv_t*F*e'*halfnorm_t)*e;
 
                     closure = obj.Ji*obj.c^2 * penalty_parameter_1*e';
-                    pp = -obj.Ji*obj.c^2 * penalty_parameter_1;
-                    switch class(data)
-                        case 'double'
-                            penalty = pp*data;
-                        case 'function_handle'
-                            penalty = @(t)pp*data(t);
-                        otherwise
-                            error('Weird data argument!')
-                    end
+                    penalty = -obj.Ji*obj.c^2 * penalty_parameter_1;
 
 
                 % Neumann boundary condition
                 case {'N','n','neumann'}
                     c = obj.c;
 
-
                     a_n = spdiags(coeff_n,0,length(coeff_n),length(coeff_n));
                     a_t = spdiags(coeff_t,0,length(coeff_t),length(coeff_t));
                     d = (a_n * d_n' + a_t*d_t')';
@@ -221,16 +218,24 @@
                     tau = c.^2 * obj.Ji*(tau1*e + tau2*d);
 
                     closure = halfnorm_inv*tau*d';
+                    penalty = -halfnorm_inv*tau;
 
-                    pp = halfnorm_inv*tau;
-                    switch class(data)
-                        case 'double'
-                            penalty = pp*data;
-                        case 'function_handle'
-                            penalty = @(t)pp*data(t);
-                        otherwise
-                            error('Weird data argument!')
-                    end
+                % Characteristic boundary condition
+                case {'characteristic', 'char', 'c'}
+                    default_arg('parameter', 1);
+                    beta = parameter;
+                    c = obj.c;
+
+                    a_n = spdiags(coeff_n,0,length(coeff_n),length(coeff_n));
+                    a_t = spdiags(coeff_t,0,length(coeff_t),length(coeff_t));
+                    d = s*(a_n * d_n' + a_t*d_t')'; % outward facing normal derivative
+
+                    tau = -c.^2 * 1/beta*obj.Ji*e;
+
+                    warning('is this right?! /c?')
+                    closure{1} = halfnorm_inv*tau/c*spdiag(scale_factor)*e';
+                    closure{2} = halfnorm_inv*tau*beta*d';
+                    penalty = -halfnorm_inv*tau;
 
                 % Unknown, boundary condition
                 otherwise
@@ -263,7 +268,7 @@
             b2_v = gamm_v*v.lambda(I_v)./v.a22(I_v).^2;
 
             tau = -1./(4*b1_u) -1./(4*b1_v) -1./(4*b2_u) -1./(4*b2_v);
-            tau = tuning * spdiag(tau(:));
+            tau = tuning * spdiag(tau);
             sig1 = 1/2;
             sig2 = -1/2;
 
@@ -279,10 +284,12 @@
         % The right boundary is considered the positive boundary
         %
         %  I -- the indecies of the boundary points in the grid matrix
-        function [e, d_n, d_t, coeff_n, coeff_t, s, gamm, halfnorm_inv_n, halfnorm_inv_t, halfnorm_t, I] = get_boundary_ops(obj,boundary)
+        function [e, d_n, d_t, coeff_n, coeff_t, s, gamm, halfnorm_inv_n, halfnorm_inv_t, halfnorm_t, I, scale_factor] = get_boundary_ops(obj, boundary)
 
-            gridMatrix = zeros(obj.m(2),obj.m(1));
-            gridMatrix(:) = 1:numel(gridMatrix);
+            % gridMatrix = zeros(obj.m(2),obj.m(1));
+            % gridMatrix(:) = 1:numel(gridMatrix);
+
+            ind = grid.funcToMatrix(obj.grid, 1:prod(obj.m));
 
             switch boundary
                 case 'w'
@@ -291,36 +298,40 @@
                     d_t = obj.dv_w;
                     s = -1;
 
-                    I = gridMatrix(:,1);
+                    I = ind(1,:);
                     coeff_n = obj.a11(I);
                     coeff_t = obj.a12(I);
+                    scale_factor = sqrt(obj.x_v(I).^2 + obj.y_v(I).^2);
                 case 'e'
                     e = obj.e_e;
                     d_n = obj.du_e;
                     d_t = obj.dv_e;
                     s = 1;
 
-                    I = gridMatrix(:,end);
+                    I = ind(end,:);
                     coeff_n = obj.a11(I);
                     coeff_t = obj.a12(I);
+                    scale_factor = sqrt(obj.x_v(I).^2 + obj.y_v(I).^2);
                 case 's'
                     e = obj.e_s;
                     d_n = obj.dv_s;
                     d_t = obj.du_s;
                     s = -1;
 
-                    I = gridMatrix(1,:)';
+                    I = ind(:,1)';
                     coeff_n = obj.a22(I);
                     coeff_t = obj.a12(I);
+                    scale_factor = sqrt(obj.x_u(I).^2 + obj.y_u(I).^2);
                 case 'n'
                     e = obj.e_n;
                     d_n = obj.dv_n;
                     d_t = obj.du_n;
                     s = 1;
 
-                    I = gridMatrix(end,:)';
+                    I = ind(:,end)';
                     coeff_n = obj.a22(I);
                     coeff_t = obj.a12(I);
+                    scale_factor = sqrt(obj.x_u(I).^2 + obj.y_u(I).^2);
                 otherwise
                     error('No such boundary: boundary = %s',boundary);
             end
@@ -343,15 +354,6 @@
             N = prod(obj.m);
         end
 
-    end
 
-    methods(Static)
-        % Calculates the matrcis need for the inteface coupling between boundary bound_u of scheme schm_u
-        % and bound_v of scheme schm_v.
-        %   [uu, uv, vv, vu] = inteface_couplong(A,'r',B,'l')
-        function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v)
-            [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v);
-            [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u);
-        end
     end
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +scheme/bcSetup.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/bcSetup.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,110 @@
+% function [closure, S] = bcSetup(diffOp, bc)
+% Takes a diffOp and a cell array of boundary condition definitions.
+% Each bc is a struct with the fields
+%  * type     -- Type of boundary condition
+%  * boundary -- Boundary identifier
+%  * data     -- A function_handle for a function which provides boundary data.(see below)
+% Also takes S_sign which modifies the sign of S, [-1,1]
+% Returns a closure matrix and a forcing function S.
+%
+% The boundary data function can either be a function of time or a function of time and space coordinates.
+% In the case where it only depends on time it should return the data as grid function for the boundary.
+% In the case where it also takes space coordinates the number of space coordinates should match the number of dimensions of the problem domain.
+% For example in the 2D case: f(t,x,y).
+function [closure, S] = bcSetup(diffOp, bcs, S_sign)
+    default_arg('S_sign', 1);
+    assertType(bcs, 'cell');
+    assert(S_sign == 1 || S_sign == -1, 'S_sign must be either 1 or -1');
+
+    verifyBcFormat(bcs, diffOp);
+
+    % Setup storage arrays
+    closure = spzeros(size(diffOp));
+    gridData = {};
+    symbolicData = {};
+
+    % Collect closures, penalties and data
+    for i = 1:length(bcs)
+        [localClosure, penalty] = diffOp.boundary_condition(bcs{i}.boundary, bcs{i}.type);
+        closure = closure + localClosure;
+
+        [ok, isSym, data] = parseData(bcs{i}, penalty, diffOp.grid);
+
+        if ~ok
+            % There was no data
+            continue
+        end
+
+        if isSym
+            symbolicData{end+1} = data;
+        else
+            gridData{end+1} = data;
+        end
+    end
+
+    % Setup penalty function
+    O = spzeros(size(diffOp),1);
+    function v = S_fun(t)
+        v = O;
+        for i = 1:length(gridData)
+            v = v + gridData{i}.penalty*gridData{i}.func(t);
+        end
+
+        for i = 1:length(symbolicData)
+            v = v + symbolicData{i}.penalty*symbolicData{i}.func(t, symbolicData{i}.coords{:});
+        end
+
+        v = S_sign * v;
+    end
+    S = @S_fun;
+end
+
+function verifyBcFormat(bcs, diffOp)
+    for i = 1:length(bcs)
+        assertType(bcs{i}, 'struct');
+        assertStructFields(bcs{i}, {'type', 'boundary'});
+
+        if ~isfield(bcs{i}, 'data') || isempty(bcs{i}.data)
+            continue
+        end
+
+        if ~isa(bcs{i}.data, 'function_handle')
+            error('bcs{%d}.data should be a function of time or a function of time and space',i);
+        end
+
+        b = diffOp.grid.getBoundary(bcs{i}.boundary);
+
+        dim = size(b,2);
+
+        if nargin(bcs{i}.data) == 1
+            % Grid data (only function of time)
+            assertSize(bcs{i}.data(0), 1, size(b));
+        elseif nargin(bcs{i}.data) ~= 1+dim
+           error('sbplib:scheme:bcSetup:DataWrongNumberOfArguments', 'bcs{%d}.data has the wrong number of input arguments. Must be either only time or time and space.', i);
+        end
+    end
+end
+
+function [ok, isSym, dataStruct] = parseData(bc, penalty, grid)
+    if ~isfield(bc,'data') || isempty(bc.data)
+        ok = false;
+        return
+    end
+    ok = true;
+
+    nArg = nargin(bc.data);
+
+    if nArg > 1
+        % Symbolic data
+        isSym = true;
+        coord = grid.getBoundary(bc.boundary);
+        dataStruct.penalty = penalty;
+        dataStruct.func = bc.data;
+        dataStruct.coords = num2cell(coord, 1);
+    else
+        % Grid data
+        isSym = false;
+        dataStruct.penalty = penalty;
+        dataStruct.func = bcs{i}.data;
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/Cdiff.m
--- a/+time/Cdiff.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+time/Cdiff.m	Fri Sep 07 14:40:58 2018 +0200
@@ -12,22 +12,20 @@
 
 
     methods
+        % Solves u_tt = Du + Eu_t + S
+        % D, E, S can either all be constants or all be function handles,
+        % They can also be omitted by setting them equal to the empty matrix.
+        % Cdiff(D, E, S, k, t0, n0, v, v_prev)
         function obj = Cdiff(D, E, S, k, t0, n0, v, v_prev)
-            % Cdiff(D, E, S, k, t0, n0, v, v_prev)
-            m = size(D,1);
+            m = length(v);
             default_arg('E',sparse(m,m));
             default_arg('S',sparse(m,1));
 
-            if ~(issparse(D) && issparse(E) && issparse(S))
-                warning('One of the matrices D, E, S is not sparse!')
-                print_issparse(D)
-                print_issparse(E)
-                print_issparse(S)
-            end
-
             obj.D = D;
             obj.E = E;
             obj.S = S;
+
+
             obj.k = k;
             obj.t = t0;
             obj.n = n0;
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/CdiffImplicit.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/CdiffImplicit.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,152 @@
+classdef CdiffImplicit < time.Timestepper
+    properties
+        A, B, C, G
+        AA, BB, CC
+        k
+        t
+        v, v_prev
+        n
+
+        % LU factorization
+        L,U,p,q
+    end
+
+    methods
+        % Solves
+        %   A*u_tt + B*u + C*v_t = G(t)
+        %   u(t0) = f1
+        %   u_t(t0) = f2
+        % starting at time t0 with timestep k
+        function obj = CdiffImplicit(A, B, C, G, f1, f2, k, t0)
+            default_arg('A', []);
+            default_arg('C', []);
+            default_arg('G', []);
+            default_arg('f1', 0);
+            default_arg('f2', 0);
+            default_arg('t0', 0);
+
+            m = size(B,1);
+
+            if isempty(A)
+                A = speye(m);
+            end
+
+            if isempty(C)
+                C = sparse(m,m);
+            end
+
+            if isempty(G)
+                G = @(t) sparse(m,1);
+            end
+
+            if isempty(f1)
+                f1 = sparse(m,1);
+            end
+
+            if isempty(f2)
+                f2 = sparse(m,1);
+            end
+
+            obj.A = A;
+            obj.B = B;
+            obj.C = C;
+            obj.G = G;
+
+            AA = 1/k^2*A + 1/2*B + 1/(2*k)*C;
+            BB = -2/k^2*A;
+            CC = 1/k^2*A + 1/2*B - 1/(2*k)*C;
+            % AA*v_next + BB*v + CC*v_prev == G(t_n)
+
+            obj.AA = AA;
+            obj.BB = BB;
+            obj.CC = CC;
+
+            v_prev = f1;
+            I = speye(m);
+            % v = (1/k^2*A)\((1/k^2*A - 1/2*B)*f1 + (1/k*I - 1/2*C)*f2 + 1/2*G(0));
+            v = f1 + k*f2;
+
+
+            if ~issparse(A) || ~issparse(B) || ~issparse(C)
+                error('LU factorization with full pivoting only works for sparse matrices.')
+            end
+
+            [L,U,p,q] = lu(AA,'vector');
+
+            obj.L = L;
+            obj.U = U;
+            obj.p = p;
+            obj.q = q;
+
+
+            obj.k = k;
+            obj.t = t0+k;
+            obj.n = 1;
+            obj.v = v;
+            obj.v_prev = v_prev;
+        end
+
+        function [v,t] = getV(obj)
+            v = obj.v;
+            t = obj.t;
+        end
+
+        function [vt,t] = getVt(obj)
+            % Calculate next time step to be able to do centered diff.
+            v_next = zeros(size(obj.v));
+            b = obj.G(obj.t) - obj.BB*obj.v - obj.CC*obj.v_prev;
+
+            y = obj.L\b(obj.p);
+            z = obj.U\y;
+            v_next(obj.q) = z;
+
+
+            vt = (v_next-obj.v_prev)/(2*obj.k);
+            t = obj.t;
+        end
+
+        function obj = step(obj)
+            b = obj.G(obj.t) - obj.BB*obj.v - obj.CC*obj.v_prev;
+            obj.v_prev = obj.v;
+
+            % % Backslash
+            % obj.v = obj.AA\b;
+
+            % LU with column pivot
+            y = obj.L\b(obj.p);
+            z = obj.U\y;
+            obj.v(obj.q) = z;
+
+            % Update time
+            obj.t = obj.t + obj.k;
+            obj.n = obj.n + 1;
+        end
+    end
+end
+
+
+
+
+
+%%% Derivation
+% syms A B C G
+% syms n k
+% syms f1 f2
+
+% v = symfun(sym('v(n)'),n);
+
+
+% d = A/k^2 * (v(n+1) - 2*v(n) +v(n-1)) + B/2*(v(n+1)+v(n-1)) + C/(2*k)*(v(n+1) - v(n-1)) == G
+% ic1 = v(0) == f1
+% ic2 = A/k*(v(1)-f1) + k/2*(B*f1 + C*f2 - G) - f2 == 0
+
+% c = collect(d, [v(n) v(n-1) v(n+1)]) % (-(2*A)/k^2)*v(n) + (B/2 + A/k^2 - C/(2*k))*v(n - 1) + (B/2 + A/k^2 + C/(2*k))*v(n + 1) == G
+% syms AA BB CC
+% % AA = B/2 + A/k^2 + C/(2*k)
+% % BB = -(2*A)/k^2
+% % CC = B/2 + A/k^2 - C/(2*k)
+% s = subs(c, [B/2 + A/k^2 + C/(2*k), -(2*A)/k^2, B/2 + A/k^2 - C/(2*k)], [AA, BB, CC])
+
+
+% ic2_a = collect(ic2, [v(1) f1 f2]) % (A/k)*v(1) + ((B*k)/2 - A/k)*f1 + ((C*k)/2 - 1)*f2 - (G*k)/2 == 0
+
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/CdiffTimeDep.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/CdiffTimeDep.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,51 @@
+classdef CdiffTimeDep < time.Timestepper
+    properties
+        D
+        E
+        S
+        k
+        t
+        v
+        v_prev
+        n
+    end
+
+
+    methods
+        % Solves u_tt = Du + E(t)u_t + S(t)
+        % D, E, S can either all be constants or all be function handles,
+        % They can also be omitted by setting them equal to the empty matrix.
+        % CdiffTimeDep(D, E, S, k, t0, n0, v, v_prev)
+        function obj = CdiffTimeDep(D, E, S, k, t0, n0, v, v_prev)
+            m = length(v);
+            default_arg('E', @(t)sparse(m,m));
+            default_arg('S', @(t)sparse(m,1));
+
+            obj.D = D;
+            obj.E = E;
+            obj.S = S;
+
+            obj.k = k;
+            obj.t = t0;
+            obj.n = n0;
+            obj.v = v;
+            obj.v_prev = v_prev;
+        end
+
+        function [v,t] = getV(obj)
+            v = obj.v;
+            t = obj.t;
+        end
+
+        function [vt,t] = getVt(obj)
+            vt = (obj.v-obj.v_prev)/obj.k; % Could be improved using u_tt = f(u))
+            t = obj.t;
+        end
+
+        function obj = step(obj)
+            [obj.v, obj.v_prev] = time.cdiff.cdiff(obj.v, obj.v_prev, obj.k, obj.D, obj.E(obj.t), obj.S(obj.t));
+            obj.t = obj.t + obj.k;
+            obj.n = obj.n + 1;
+        end
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/Rungekutta4SecondOrder.m
--- a/+time/Rungekutta4SecondOrder.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+time/Rungekutta4SecondOrder.m	Fri Sep 07 14:40:58 2018 +0200
@@ -15,6 +15,21 @@
 
 
     methods
+        % Solves u_tt = Du + Eu_t + S by
+        % Rewriting on first order form:
+        %   w_t = M*w + C(t)
+        % where
+        %   M = [
+        %      0, I;
+        %      D, E;
+        %   ]
+        % and
+        %   C(t) = [
+        %      0;
+        %      S(t)
+        %   ]
+        % D, E, S can either all be constants or all be function handles,
+        % They can also be omitted by setting them equal to the empty matrix.
         function obj = Rungekutta4SecondOrder(D, E, S, k, t0, v0, v0t)
             obj.D = D;
             obj.E = E;
@@ -22,21 +37,55 @@
             obj.m = length(v0);
             obj.n = 0;
 
-            I = speye(obj.m);
-            O = sparse(obj.m,obj.m);
-            obj.M = [O, I; D, E*I]; % Multiply with I to allow 0 as input.
+
+            if isa(D, 'function_handle') || isa(E, 'function_handle') || isa(S, 'function_handle')
+                default_arg('D', @(t)sparse(obj.m, obj.m));
+                default_arg('E', @(t)sparse(obj.m, obj.m));
+                default_arg('S', @(t)sparse(obj.m, 1)    );
 
-            if S == 0
-                obj.C = zeros(2*obj.m,1);
+                if ~isa(D, 'function_handle')
+                    D = @(t)D;
+                end
+                if ~isa(E, 'function_handle')
+                    E = @(t)E;
+                end
+                if ~isa(S, 'function_handle')
+                    S = @(t)S;
+                end
+
+                obj.k = k;
+                obj.t = t0;
+                obj.w = [v0; v0t];
+
+                % Avoid matrix formulation because it is VERY slow
+                obj.F = @(w,t)[
+                    w(obj.m+1:end);
+                    D(t)*w(1:obj.m) + E(t)*w(obj.m+1:end) + S(t);
+                ];
             else
-                obj.C = [zeros(obj.m,1), S];
-            end
+
+                default_arg('D', sparse(obj.m, obj.m));
+                default_arg('E', sparse(obj.m, obj.m));
+                default_arg('S', sparse(obj.m, 1)    );
+
+                I = speye(obj.m);
+                O = sparse(obj.m,obj.m);
 
-            obj.k = k;
-            obj.t = t0;
-            obj.w = [v0; v0t];
+                obj.M = [
+                    O, I;
+                    D, E;
+                ];
+                obj.C = [
+                    zeros(obj.m,1);
+                                 S;
+                ];
 
-            obj.F = @(w,t)(obj.M*w + obj.C);
+                obj.k = k;
+                obj.t = t0;
+                obj.w = [v0; v0t];
+
+                obj.F = @(w,t)(obj.M*w + obj.C);
+            end
         end
 
         function [v,t] = getV(obj)
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/Rungekutta4proper.m
--- a/+time/Rungekutta4proper.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+time/Rungekutta4proper.m	Fri Sep 07 14:40:58 2018 +0200
@@ -10,6 +10,7 @@
 
 
     methods
+        % Timesteps v_t = F(v,t), using RK4 fromt t = t0 with timestep k and initial conditions v = v0
         function obj = Rungekutta4proper(F, k, t0, v0)
             obj.F = F;
             obj.k = k;
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/SBPInTime.m
--- a/+time/SBPInTime.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+time/SBPInTime.m	Fri Sep 07 14:40:58 2018 +0200
@@ -104,6 +104,7 @@
         end
     end
 
+
     methods(Static)
         function N = smallestBlockSize(order,TYPE)
             default_arg('TYPE','gauss')
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/SBPInTimeImplicitFormulation.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/SBPInTimeImplicitFormulation.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,130 @@
+classdef SBPInTimeImplicitFormulation < time.Timestepper
+    % The SBP in time method.
+    % Implemented for A*v_t = B*v + f(t), v(0) = v0
+    properties
+        A,B
+        f
+
+        k % total time step.
+
+        blockSize % number of points in each block
+        N % Number of components
+
+        order
+        nodes
+
+        M,K     % System matrices
+        L,U,p,q % LU factorization of M
+        e_T
+
+        % Time state
+        t
+        v
+        n
+    end
+
+    methods
+        function obj = SBPInTimeImplicitFormulation(A, B, f, k, t0, v0, TYPE, order, blockSize)
+
+            default_arg('TYPE','gauss');
+            default_arg('f',[]);
+
+            if(strcmp(TYPE,'gauss'))
+                default_arg('order',4)
+                default_arg('blockSize',4)
+            else
+                default_arg('order', 8);
+                default_arg('blockSize',time.SBPInTimeImplicitFormulation.smallestBlockSize(order,TYPE));
+            end
+
+            obj.A = A;
+            obj.B = B;
+
+            if ~isempty(f)
+                obj.f = f;
+            else
+                obj.f = @(t)sparse(length(v0),1);
+            end
+
+            obj.k = k;
+            obj.blockSize = blockSize;
+            obj.N = length(v0);
+
+            obj.n = 0;
+            obj.t = t0;
+
+            %==== Build the time discretization matrix =====%
+            switch TYPE
+                case 'equidistant'
+                    ops = sbp.D2Standard(blockSize,{0,obj.k},order);
+                case 'optimal'
+                    ops = sbp.D1Nonequidistant(blockSize,{0,obj.k},order);
+                case 'minimal'
+                    ops = sbp.D1Nonequidistant(blockSize,{0,obj.k},order,'minimal');
+                case 'gauss'
+                    ops = sbp.D1Gauss(blockSize,{0,obj.k});
+            end
+
+            I = speye(size(A));
+            I_t = speye(blockSize,blockSize);
+
+            D1 = kron(ops.D1, I);
+            HI = kron(ops.HI, I);
+            e_0 = kron(ops.e_l, I);
+            e_T = kron(ops.e_r, I);
+            obj.nodes = ops.x;
+
+            % Convert to form M*w = K*v0 + f(t)
+            tau = kron(I_t, A) * e_0;
+            M = kron(I_t, A)*D1 + HI*tau*e_0' - kron(I_t, B);
+
+            K = HI*tau;
+
+            obj.M = M;
+            obj.K = K;
+            obj.e_T = e_T;
+
+            % LU factorization
+            [obj.L,obj.U,obj.p,obj.q] = lu(obj.M, 'vector');
+
+            obj.v = v0;
+        end
+
+        function [v,t] = getV(obj)
+            v = obj.v;
+            t = obj.t;
+        end
+
+        function obj = step(obj)
+            RHS = zeros(obj.blockSize*obj.N,1);
+
+            for i = 1:obj.blockSize
+                RHS((1 + (i-1)*obj.N):(i*obj.N)) = obj.f(obj.t + obj.nodes(i));
+            end
+
+            RHS = RHS + obj.K*obj.v;
+
+            y = obj.L\RHS(obj.p);
+            z = obj.U\y;
+
+            w = zeros(size(z));
+            w(obj.q) = z;
+
+            obj.v = obj.e_T'*w;
+
+            obj.t = obj.t + obj.k;
+            obj.n = obj.n + 1;
+        end
+    end
+
+    methods(Static)
+        function N = smallestBlockSize(order,TYPE)
+            default_arg('TYPE','gauss')
+
+            switch TYPE
+                case 'gauss'
+                    N = 4;
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/SBPInTimeScaled.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/SBPInTimeScaled.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,139 @@
+classdef SBPInTimeScaled < time.Timestepper
+    % The SBP in time method.
+    % Implemented for A*v_t = B*v + f(t), v(0) = v0
+    % The resulting system of equations is
+    %   M*u_next= K*u_prev_end + f
+    properties
+        A,B
+        f
+
+        k % total time step.
+
+        blockSize % number of points in each block
+        N % Number of components
+
+        order
+        nodes
+
+        Mtilde,Ktilde     % System matrices
+        L,U,p,q % LU factorization of M
+        e_T
+
+        scaling
+        S, Sinv % Scaling matrices
+
+        % Time state
+        t
+        vtilde
+        n
+    end
+
+    methods
+        function obj = SBPInTimeScaled(A, B, f, k, t0, v0, scaling, TYPE, order, blockSize)
+            default_arg('TYPE','gauss');
+            default_arg('f',[]);
+
+            if(strcmp(TYPE,'gauss'))
+                default_arg('order',4)
+                default_arg('blockSize',4)
+            else
+                default_arg('order', 8);
+                default_arg('blockSize',time.SBPInTimeImplicitFormulation.smallestBlockSize(order,TYPE));
+            end
+
+            obj.A = A;
+            obj.B = B;
+            obj.scaling = scaling;
+
+            if ~isempty(f)
+                obj.f = f;
+            else
+                obj.f = @(t)sparse(length(v0),1);
+            end
+
+            obj.k = k;
+            obj.blockSize = blockSize;
+            obj.N = length(v0);
+
+            obj.n = 0;
+            obj.t = t0;
+
+            %==== Build the time discretization matrix =====%
+            switch TYPE
+                case 'equidistant'
+                    ops = sbp.D2Standard(blockSize,{0,obj.k},order);
+                case 'optimal'
+                    ops = sbp.D1Nonequidistant(blockSize,{0,obj.k},order);
+                case 'minimal'
+                    ops = sbp.D1Nonequidistant(blockSize,{0,obj.k},order,'minimal');
+                case 'gauss'
+                    ops = sbp.D1Gauss(blockSize,{0,obj.k});
+            end
+
+            I = speye(size(A));
+            I_t = speye(blockSize,blockSize);
+
+            D1 = kron(ops.D1, I);
+            HI = kron(ops.HI, I);
+            e_0 = kron(ops.e_l, I);
+            e_T = kron(ops.e_r, I);
+            obj.nodes = ops.x;
+
+            % Convert to form M*w = K*v0 + f(t)
+            tau = kron(I_t, A) * e_0;
+            M = kron(I_t, A)*D1 + HI*tau*e_0' - kron(I_t, B);
+
+            K = HI*tau;
+
+            obj.S =    kron(I_t, spdiag(scaling));
+            obj.Sinv = kron(I_t, spdiag(1./scaling));
+
+            obj.Mtilde = obj.Sinv*M*obj.S;
+            obj.Ktilde = obj.Sinv*K*spdiag(scaling);
+            obj.e_T = e_T;
+
+
+            % LU factorization
+            [obj.L,obj.U,obj.p,obj.q] = lu(obj.Mtilde, 'vector');
+
+            obj.vtilde = (1./obj.scaling).*v0;
+        end
+
+        function [v,t] = getV(obj)
+            v = obj.scaling.*obj.vtilde;
+            t = obj.t;
+        end
+
+        function obj = step(obj)
+            forcing = zeros(obj.blockSize*obj.N,1);
+
+            for i = 1:obj.blockSize
+                forcing((1 + (i-1)*obj.N):(i*obj.N)) = obj.f(obj.t + obj.nodes(i));
+            end
+
+            RHS = obj.Sinv*forcing + obj.Ktilde*obj.vtilde;
+
+            y = obj.L\RHS(obj.p);
+            z = obj.U\y;
+
+            w = zeros(size(z));
+            w(obj.q) = z;
+
+            obj.vtilde = obj.e_T'*w;
+
+            obj.t = obj.t + obj.k;
+            obj.n = obj.n + 1;
+        end
+    end
+
+    methods(Static)
+        function N = smallestBlockSize(order,TYPE)
+            default_arg('TYPE','gauss')
+
+            switch TYPE
+                case 'gauss'
+                    N = 4;
+            end
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/SBPInTimeSecondOrderFormImplicit.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/SBPInTimeSecondOrderFormImplicit.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,86 @@
+classdef SBPInTimeSecondOrderFormImplicit < time.Timestepper
+    properties
+        A, B, C, f
+        AA, BB, ff
+
+        n
+        t
+        k
+
+        firstOrderTimeStepper
+    end
+
+    methods
+        % Solves A*u_tt + B*u_t + C*u = f(t)
+        % A, B can either both be constants or both be function handles,
+        % They can also be omitted by setting them equal to the empty matrix.
+        function obj = SBPInTimeSecondOrderFormImplicit(A, B, C, f, k, t0, v0, v0t, do_scaling, TYPE, order, blockSize)
+            default_arg('f', []);
+            default_arg('TYPE', []);
+            default_arg('order', []);
+            default_arg('blockSize',[]);
+            default_arg('do_scaling', false);
+
+            m = length(v0);
+
+            default_arg('A', speye(m, m));
+            default_arg('B', sparse(m, m));
+            default_arg('C', sparse(m, m));
+
+            I = speye(m);
+            O = sparse(m,m);
+
+            % Rewrite to
+            % AA*w_t = BB*w + ff(t);
+
+            obj.AA = [
+                 I, O;
+                 O, A;
+            ];
+            obj.BB = [
+                 O,  I;
+                -C, -B;
+            ];
+
+            if ~isempty(f)
+                obj.ff = @(t)[
+                    sparse(m,1);
+                           f(t);
+                ];
+            else
+                obj.ff = @(t) sparse(2*m,1);
+            end
+
+            w0 = [v0; v0t];
+
+            obj.k = k;
+            obj.t = t0;
+            obj.n = 0;
+
+            if do_scaling
+                scaling = [ones(m,1); sqrt(diag(C))];
+                obj.firstOrderTimeStepper = time.SBPInTimeScaled(obj.AA, obj.BB, obj.ff, obj.k, obj.t, w0, scaling, TYPE, order, blockSize);
+            else
+                obj.firstOrderTimeStepper = time.SBPInTimeImplicitFormulation(obj.AA, obj.BB, obj.ff, obj.k, obj.t, w0, TYPE, order, blockSize);
+            end
+        end
+
+        function [v,t] = getV(obj)
+            w = obj.firstOrderTimeStepper.getV();
+            v = w(1:end/2);
+            t = obj.t;
+        end
+
+        function [vt,t] = getVt(obj)
+            w = obj.firstOrderTimeStepper.getV();
+            vt = w(end/2+1:end);
+            t = obj.t;
+        end
+
+        function obj = step(obj)
+            obj.firstOrderTimeStepper.step();
+            obj.t = obj.firstOrderTimeStepper.t;
+            obj.n = obj.firstOrderTimeStepper.n;
+        end
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb +time/Timestepper.m
--- a/+time/Timestepper.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+time/Timestepper.m	Fri Sep 07 14:40:58 2018 +0200
@@ -60,6 +60,14 @@
             s = util.replace_string(s,'');
         end
 
+
+        function [v, t] = stepTo(obj, n, progress_bar)
+            assertScalar(n);
+            default_arg('progress_bar',false);
+
+            [v, t] = obj.stepN(n-obj.n, progress_bar);
+        end
+
         function [v,t] = evolve(obj, tend, progress_bar)
             default_arg('progress_bar',false)
             if ~progress_bar
diff -r fdf0ef9150f4 -r 501750fbbfdb +util/ReplaceableString.m
--- a/+util/ReplaceableString.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+util/ReplaceableString.m	Fri Sep 07 14:40:58 2018 +0200
@@ -34,10 +34,20 @@
             obj.display();
         end
 
+        function show(obj, varargin)
+            obj.param = varargin;
+            obj.display();
+        end
+
+        function remove(obj)
+            obj.update('');
+        end
+
         function display(obj)
             reverseStr = repmat(sprintf('\b'), 1, obj.n);
-            newStr = padStr(sprintf(obj.fmt, obj.param{:}),obj.n);
-            fprintf([reverseStr, newStr]);
+            cleareStr = repmat(sprintf(' '), 1, obj.n);
+            newStr = sprintf(obj.fmt, obj.param{:});
+            fprintf([reverseStr, cleareStr, reverseStr, newStr]);
 
             obj.n = length(newStr);
         end
diff -r fdf0ef9150f4 -r 501750fbbfdb +util/calc_borrowing.m
--- a/+util/calc_borrowing.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/+util/calc_borrowing.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,97 +1,241 @@
+function calc_borrowing(m, h)
+    default_arg('m',100);
+    default_arg('h',1);
 
-m = 100;
-h = 1;
+    operators = {
+        {
+            'd4_lonely', getM4_lonely, {
+                {4, 'min_boundary_points'},
+                {6, 'min_boundary_points'},
+                {6, '2'},
+                {6, '3'},
+                {8, 'min_boundary_points'},
+                {8, 'higher_boundary_order'},
+            }
+        }, {
+            'd4_variable', {
+                {2},
+                {4},
+                {6},
+            }
+        }
+        % BORKEN BAD IDEA
+    }
+
+
+    for i = 1:operators
+        baseName = operators{i}{1};
+        postFixes = operators{i}{2};
+        for pf = postFixes
+            [a2, a3] = borrowFromD4(m, h, l{:});
+        end
+    end
 
 
-%% 4th order non-compatible
-[H, HI, D1, D2, D3, D4, e_1, e_m, M, M4,Q, Q3, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher4(m,h);
-S1 = S_1*S_1'  + S_m*S_m';
-S2 = S2_1*S2_1' + S2_m*S2_m';
-S3 = S3_1*S3_1' + S3_m*S3_m';
+
+    lonely = {
+        {4, 'min_boundary_points'},
+        {6, 'min_boundary_points'},
+        {6, '2'},
+        {6, '3'},
+        {8, 'min_boundary_points'},
+        {8, 'higher_boundary_order'},
+    };
 
-alpha_I  = util.matrixborrow(M4, h^-1*S1  );
-alpha_II  = util.matrixborrow(M4, h*S2  );
-alpha_III = util.matrixborrow(M4, h^3*S3);
-fprintf('4th order non-compatible\n')
-fprintf('alpha_I1:  %.10f\n',alpha_I)
-fprintf('alpha_II:  %.10f\n',alpha_II)
-fprintf('alpha_III: %.10f\n',alpha_III)
-fprintf('\n')
-
+    for i = 1:length(lonely)
+        l = lonely{i};
+        [a2, a3] = d4_lonely(m, h, l{:});
+        fprintf('d4_lonely %d %s\n', l{:})
+        fprintf('\t  alpha_II = %f\n', a2)
+        fprintf('\t alpha_III = %f\n', a3)
+        fprintf('\n')
+    end
 
-%% 6th order non-compatible
-[H, HI, D1, D2, D3, D4, e_1, e_m, M, M4,Q, Q3, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher6(m,h);
-S1 = S_1*S_1'  + S_m*S_m';
-S2 = S2_1*S2_1' + S2_m*S2_m';
-S3 = S3_1*S3_1' + S3_m*S3_m';
+    variable = {
+        {2},
+        {4},
+        {6},
+    };
 
-alpha_II  = util.matrixborrow(M4, h*S2  );
-alpha_III = util.matrixborrow(M4, h^3*S3);
-fprintf('6th order non-compatible\n')
-fprintf('alpha_II:  %.10f\n',alpha_II)
-fprintf('alpha_III: %.10f\n',alpha_III)
-fprintf('\n')
+    for i = 1:length(variable)
+        l = variable{i};
+        [a2, a3] = d4_variable(m, h, l{:});
+        fprintf('d4_variable %d\n', l{:})
+        fprintf('\t  alpha_II = %f\n', a2)
+        fprintf('\t alpha_III = %f\n', a3)
+        fprintf('\n')
+    end
 
 
-%% 2nd order compatible
-[H, HI, D1, D4, e_1, e_m, M4, Q, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher_compatible2(m,h);
-S1 = S_1*S_1'  + S_m*S_m';
-S2 = S2_1*S2_1' + S2_m*S2_m';
-S3 = S3_1*S3_1' + S3_m*S3_m';
+    %% 4th order non-compatible
+    [H, HI, D1, D2, D3, D4, e_1, e_m, M, M4,Q, Q3, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher4(m,h);
+    S1 = S_1*S_1'  + S_m*S_m';
+    S2 = S2_1*S2_1' + S2_m*S2_m';
+    S3 = S3_1*S3_1' + S3_m*S3_m';
 
-alpha_II  = util.matrixborrow(M4, h*S2  );
-alpha_III = util.matrixborrow(M4, h^3*S3);
-fprintf('2nd order compatible\n')
-fprintf('alpha_II:  %.10f\n',alpha_II)
-fprintf('alpha_III: %.10f\n',alpha_III)
-fprintf('\n')
+    alpha_I  = util.matrixborrow(M4, h^-1*S1  );
+    alpha_II  = util.matrixborrow(M4, h*S2  );
+    alpha_III = util.matrixborrow(M4, h^3*S3);
+    fprintf('4th order non-compatible\n')
+    fprintf('alpha_I1:  %.10f\n',alpha_I)
+    fprintf('alpha_II:  %.10f\n',alpha_II)
+    fprintf('alpha_III: %.10f\n',alpha_III)
+    fprintf('\n')
+
+
+    %% 6th order non-compatible
+    [H, HI, D1, D2, D3, D4, e_1, e_m, M, M4,Q, Q3, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher6(m,h);
+    S1 = S_1*S_1'  + S_m*S_m';
+    S2 = S2_1*S2_1' + S2_m*S2_m';
+    S3 = S3_1*S3_1' + S3_m*S3_m';
+
+    alpha_II  = util.matrixborrow(M4, h*S2  );
+    alpha_III = util.matrixborrow(M4, h^3*S3);
+    fprintf('6th order non-compatible\n')
+    fprintf('alpha_II:  %.10f\n',alpha_II)
+    fprintf('alpha_III: %.10f\n',alpha_III)
+    fprintf('\n')
 
 
-%% 4th order compatible
-[H, HI, D1, D4, e_1, e_m, M4, Q, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher_compatible4(m,h);
-S1 = S_1*S_1'  + S_m*S_m';
-S2 = S2_1*S2_1' + S2_m*S2_m';
-S3 = S3_1*S3_1' + S3_m*S3_m';
+    %% 2nd order compatible
+    [H, HI, D1, D4, e_1, e_m, M4, Q, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher_compatible2(m,h);
+    S1 = S_1*S_1'  + S_m*S_m';
+    S2 = S2_1*S2_1' + S2_m*S2_m';
+    S3 = S3_1*S3_1' + S3_m*S3_m';
 
-alpha_II  = util.matrixborrow(M4, h*S2  );
-alpha_III = util.matrixborrow(M4, h^3*S3);
-fprintf('4th order compatible\n')
-fprintf('alpha_II:  %.10f\n',alpha_II)
-fprintf('alpha_III: %.10f\n',alpha_III)
-fprintf('\n')
+    alpha_II  = util.matrixborrow(M4, h*S2  );
+    alpha_III = util.matrixborrow(M4, h^3*S3);
+    fprintf('2nd order compatible\n')
+    fprintf('alpha_II:  %.10f\n',alpha_II)
+    fprintf('alpha_III: %.10f\n',alpha_III)
+    fprintf('\n')
+
+
+    %% 4th order compatible
+    [H, HI, D1, D4, e_1, e_m, M4, Q, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher_compatible4(m,h);
+    S1 = S_1*S_1'  + S_m*S_m';
+    S2 = S2_1*S2_1' + S2_m*S2_m';
+    S3 = S3_1*S3_1' + S3_m*S3_m';
 
-%% 6th order compatible
-[H, HI, D1, D4, e_1, e_m, M4, Q, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher_compatible6(m,h);
-S1 = S_1*S_1'  + S_m*S_m';
-S2 = S2_1*S2_1' + S2_m*S2_m';
-S3 = S3_1*S3_1' + S3_m*S3_m';
+    alpha_II  = util.matrixborrow(M4, h*S2  );
+    alpha_III = util.matrixborrow(M4, h^3*S3);
+    fprintf('4th order compatible\n')
+    fprintf('alpha_II:  %.10f\n',alpha_II)
+    fprintf('alpha_III: %.10f\n',alpha_III)
+    fprintf('\n')
 
-alpha_II  = util.matrixborrow(M4, h*S2  );
-alpha_III = util.matrixborrow(M4, h^3*S3);
-fprintf('6th order compatible\n')
-fprintf('alpha_II:  %.10f\n',alpha_II)
-fprintf('alpha_III: %.10f\n',alpha_III)
-fprintf('\n')
+    %% 6th order compatible
+    [H, HI, D1, D4, e_1, e_m, M4, Q, S2_1, S2_m, S3_1, S3_m, S_1, S_m] = sbp.higher_compatible6(m,h);
+    S1 = S_1*S_1'  + S_m*S_m';
+    S2 = S2_1*S2_1' + S2_m*S2_m';
+    S3 = S3_1*S3_1' + S3_m*S3_m';
+
+    alpha_II  = util.matrixborrow(M4, h*S2  );
+    alpha_III = util.matrixborrow(M4, h^3*S3);
+    fprintf('6th order compatible\n')
+    fprintf('alpha_II:  %.10f\n',alpha_II)
+    fprintf('alpha_III: %.10f\n',alpha_III)
+    fprintf('\n')
 
 
 
 
 
-% Ordinary
+    % Ordinary
+
+    for order = [2 4 6 8 10]
+        op = sbp.Ordinary(m,h, order);
+
+        S_1 = op.boundary.S_1;
+        S_m = op.boundary.S_m;
+
+        M = op.norms.M;
 
-for order = [2 4 6 8 10]
-    op = sbp.Ordinary(m,h, order);
+        S1 = S_1*S_1'  + S_m*S_m';
+        alpha  = util.matrixborrow(M, h*S1);
+        fprintf('%dth order Ordinary\n', order)
+        fprintf('alpha:  %.10f\n', alpha)
+        fprintf('\n')
+    end
 
-    S_1 = op.boundary.S_1;
-    S_m = op.boundary.S_m;
+
+
+
+end
 
-    M = op.norms.M;
+function [alpha_II, alpha_III] = d4_lonely(m, h, order, modifier)
+    default_arg('modifier', [])
+    func = sprintf('sbp.implementations.d4_lonely_%d', order);
+    if ~isempty(modifier)
+        func = sprintf('%s_%s', func, modifier);
+    end
+    funcCall = sprintf('%s(%s,%s)', func, toString(m), toString(h));
+    [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = eval(funcCall);
+
+    d2d2 = d2_l*d2_l' + d2_r*d2_r';
+    alpha_II  = util.matrixborrow(M4, h*d2d2);
+
+    d3d3 = d3_l*d3_l' + d3_r*d3_r';
+    alpha_III = util.matrixborrow(M4, h^3*d3d3);
+end
 
-    S1 = S_1*S_1'  + S_m*S_m';
-    alpha  = util.matrixborrow(M, h*S1);
-    fprintf('%dth order Ordinary\n', order)
-    fprintf('alpha:  %.10f\n', alpha)
-    fprintf('\n')
+function [alpha_II, alpha_III] = d4_variable(m, h, order)
+    default_arg('modifier', [])
+    func = sprintf('sbp.implementations.d4_variable_%d', order);
+
+    funcCall = sprintf('%s(%s,%s)', func, toString(m), toString(h));
+    [H, HI, D1, D2, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = eval(funcCall);
+
+    d2d2 = d2_l*d2_l' + d2_r*d2_r';
+    alpha_II  = util.matrixborrow(M4, h*d2d2);
+
+    d3d3 = d3_l*d3_l' + d3_r*d3_r';
+    alpha_III = util.matrixborrow(M4, h^3*d3d3);
+end
+
+function [d2_l, d2_r, d3_l, d3_r, M4] = getM4_lonely(m, h, order, modifier)
+    fStr = getFunctionCallStr('d4_lonely', {order, modifier}, {m ,h});
+    [H, HI, D4, e_l, e_r, M4, d2_l, d2_r, d3_l, d3_r, d1_l, d1_r] = eval(funcCall);
 end
 
 
+% Calculates the borrowing constants for a D4 operator.
+% getM4 is a function handle on the form
+%  [d2_l, d2_r, d3_l, d3_r, M4] = getM4(m,h)
+function [a2, a3] = borrowFromD4(m, h, getM4)
+    [d2_l, d2_r, d3_l, d3_r, M4] = getM4(m, h);
+
+    d2d2 = d2_l*d2_l' + d2_r*d2_r';
+    a2  = util.matrixborrow(M4, h*d2d2);
+
+    d3d3 = d3_l*d3_l' + d3_r*d3_r';
+    a3 = util.matrixborrow(M4, h^3*d3d3);
+end
+
+
+function funcCallStr = getFunctionCallStr(baseName, postFix, parameters)
+    default_arg('postFix', [])
+    default_arg('parameters', [])
+
+    funcCallStr = sprintf('sbp.implementations.%s', baseName);
+
+    for i = 1:length(postFix)
+        if ischar(postFix{i})
+            funcCallStr = [funcCallStr '_' postFix{i}];
+        else
+            funcCallStr = [funcCallStr '_' toString(postFix{i})];
+        end
+    end
+
+    if isempty(parameters)
+        return
+    end
+
+    funcCallStr = [funcCallStr '(' toString(parameters{1})];
+
+    for i = 2:length(parameters)
+        funcCallStr = [funcCallStr ', ' toString(parameters{i})];
+    end
+
+    funcCallStr = [funcCallStr ')';
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb .hgtags
--- a/.hgtags	Fri Sep 07 14:39:38 2018 +0200
+++ b/.hgtags	Fri Sep 07 14:40:58 2018 +0200
@@ -1,2 +1,4 @@
 18c023aaf3f79cbe2b9b1cf547d80babdaa1637d v0.1
+0776fa4754ff0c1918f6e1278c66f48c62d05736 grids0.1
 b723495cdb2f96314d7b3f0aa79723a7dc088c7d v0.2
+08f3ffe63f484d02abce8df4df61e826f568193f elastic1.0
diff -r fdf0ef9150f4 -r 501750fbbfdb Color.m
--- a/Color.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/Color.m	Fri Sep 07 14:40:58 2018 +0200
@@ -10,6 +10,10 @@
         black     = [0.000 0.000 0.000];
         white     = [1.000 1.000 1.000];
         colors = { Color.blue, Color.red, Color.yellow, Color.green, Color.purple, Color.lightblue, Color.darkred, Color.black, Color.white};
+        markers = {'+', 'o', '*', '.', 'x', 'square', 'diamond', 'v', '^', '>', '<', 'pentagram', 'hexagram'};
+        lineStyles = {'-', '--', ':', '-.'};
+
+        solidMarkers = {'o', 'square', 'diamond', 'v', 'pentagram', '^', '>', '<', 'hexagram'};
 
         notabilityYellow     = [100.0   99.0    22.0    ]/100;
         notabilityOrange     = [97.0    61.0    15.0    ]/100;
@@ -34,13 +38,11 @@
 
     methods(Static)
         function sample()
-            markers ={'+', 'o', '*', '.', 'x', 'square', 'diamond', 'v', '^', '>', '<', 'pentagram', 'hexagram'};
             % Filled and non-filled markers?
-            lineStyles = {'-', '--', ':', '-.'};
 
 
             function showMarkers(x0, y0, lx, ly, color, filled)
-                n = length(markers);
+                n = length(Color.markers);
                 s = ceil(sqrt(n));
 
                 x = linspace(x0, x0 + lx, s);
@@ -50,7 +52,7 @@
 
                 for i = 1:n
                     lh = line(X(i),Y(i));
-                    lh.Marker = markers{i};
+                    lh.Marker = Color.markers{i};
                     lh.MarkerSize = 12;
                     lh.Color = color;
 
@@ -79,13 +81,13 @@
             end
 
             function showLines(y0, ly, A, w)
-                n = length(lineStyles);
+                n = length(Color.lineStyles);
                 x = linspace(0,1,100);
                 y = linspace(y0, y0+ ly, n);
                 for i = 1:n
                     lh = line(x, y(i) + A*sin(pi*x*w));
                     lh.LineWidth = 2;
-                    lh.LineStyle = lineStyles{i};
+                    lh.LineStyle = Color.lineStyles{i};
                 end
             end
 
diff -r fdf0ef9150f4 -r 501750fbbfdb Dictionary.m
--- a/Dictionary.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/Dictionary.m	Fri Sep 07 14:40:58 2018 +0200
@@ -98,14 +98,11 @@
         % Should probably use mat2str with some kind of normalization to make all variables valied fieldname
         %  and make it possible to recover the value
         function fName = getFieldname(obj, val)
-            if isnumeric(val)
-                valStr = num2str(val);
-            elseif ischar(val)
-                valStr = val;
-            else
-                error('Dont know what to do with val!');
+            if ~ischar(val)
+                val = toString(val);
             end
-            fName = sprintf('f%s',valStr);
+
+            fName = matlab.lang.makeValidName(val);
         end
     end
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb TextTable.m
--- a/TextTable.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/TextTable.m	Fri Sep 07 14:40:58 2018 +0200
@@ -4,28 +4,36 @@
         fmtArray
         vertDiv
         horzDiv
-
-        nCols
-        nRows
     end
 
     methods
-        function obj = TextTable(data, vertDiv, horzDiv);
+        function obj = TextTable(data, vertDiv, horzDiv)
             default_arg('vertDiv', []);
             default_arg('horzDiv', []);
 
-
             obj.data = data;
             obj.vertDiv = vertDiv;
             obj.horzDiv = horzDiv;
 
-            [obj.nRows, obj.nCols] = size(data);
             obj.fmtArray = cell(size(data));
             obj.formatAll('%s');
 
         end
 
+        function n = nRows(obj)
+            n = size(obj.data, 1);
+        end
+
+        function n = nCols(obj)
+            n = size(obj.data, 2);
+        end
+
+        function print(obj)
+            disp(obj.toString());
+        end
+
         function formatAll(obj, fmt)
+            obj.fmtArray = cell(size(obj.data));
             obj.fmtArray(:,:) = {fmt};
         end
 
@@ -58,28 +66,31 @@
 
             str = '';
 
+            N = size(strArray, 2);
+
             % First horzDiv
-            if ismember(0, obj.horzDiv)
+            if isDiv(0, obj.horzDiv, N);
                 str = [str, obj.getHorzDiv(widths)];
             end
 
             for i = 1:obj.nRows
-                str = [str, TextTable.rowToString(strArray(i,:), widths, obj.vertDiv, obj.horzDiv)];
+                str = [str, TextTable.rowToString(strArray(i,:), widths, obj.vertDiv)];
 
                 % Interior horzDiv
-                if ismember(i, obj.horzDiv)
+                if isDiv(i, obj.horzDiv, N)
                     str = [str, obj.getHorzDiv(widths)];
                 end
             end
         end
 
         function str = getHorzDiv(obj, widths)
-            str = TextTable.rowToString(cell(1,obj.nCols), widths, obj.vertDiv, obj.horzDiv);
+            str = TextTable.rowToString(cell(1,obj.nCols), widths, obj.vertDiv);
             str(find(' ' == str)) = '-';
             str(find('|' == str)) = '+';
         end
 
         function strArray = getStringArray(obj)
+            assert(all(size(obj.data) == size(obj.fmtArray)), 'Sizes of format matrix and data matrix do not match.')
             strArray = cell(size(obj.data));
 
             for i = 1:obj.nRows
@@ -91,32 +102,42 @@
     end
 
     methods (Static)
-        function str = rowToString(strs, widths, vertDiv, horzDiv)
+        function str = rowToString(strs, widths, vertDiv)
+            N = length(strs);
+
             % First vertDiv
-            if ismember(0, vertDiv)
-                str = '| ';
+            if isDiv(0, vertDiv, N)
+                prefix = '| ';
             else
-                str = ' ';
+                prefix = ' ';
             end
 
-            % Interior cols
-            for j = 1:length(strs) - 1
-                str = [str, sprintf('%*s ', widths(j), strs{j})];
+            % Pad strings
+            for i = 1:N
+                strs{i} = sprintf('%*s', widths(i), strs{i});
+            end
 
-                % Interior vertDiv
-                if ismember(j, vertDiv)
-                    str = [str, '| '];
+            % Column delimiters
+            delims = cell(1,N-1);
+            for i = 1:length(delims)
+                if isDiv(i, vertDiv, N);
+                    delims{i} = '| ';
+                else
+                    delims{i} = ' ';
                 end
             end
 
-            % Last col
-            str = [str, sprintf('%*s ', widths(end), strs{end})];
-
-            if ismember(length(strs), vertDiv)
-                str = [str, '|'];
+            if isDiv(N, vertDiv, N);
+                suffix = '|';
+            else
+                suffix = '';
             end
 
-            str = [str, sprintf('\n')];
+            str = [prefix, strjoin(strs, delims), suffix, sprintf('\n')];
         end
     end
+end
+
+function b = isDiv(i, div, N)
+    b = ismember(i, div) || ismember(i, N+div+1);
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb assertIsMember.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertIsMember.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,3 @@
+function assertIsMember(v, allowed)
+    assert(ismember(v, allowed), 'Expected ''%s'' to be in the set %s', inputname(1), toString(allowed));
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb assertNumberOfArguments.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertNumberOfArguments.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,5 @@
+function assertNumberOfArguments(fun, N)
+    if nargin(fun) ~= N
+        error('sbplib:assertNumberOfArguments:wrongNumberOfArguments', '"%s" must have %d, found %d', inputname(1), N, nargin(fun));
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb assertScalar.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertScalar.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,5 @@
+function assertScalar(obj)
+    if ~isscalar(obj)
+        error('sbplib:assertScalar:notScalar', '"%s" must be scalar, found size "%s"', inputname(1), toString(size(obj)));
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb assertSize.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertSize.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,16 @@
+% Assert that array A has the size s.
+function assertSize(A,varargin)
+    if length(varargin) == 1
+        s = varargin{1};
+        errmsg = sprintf('Expected %s to have size %s, got: %s',inputname(1), toString(s), toString(size(A)));
+        assert(all(size(A) == s), errmsg);
+    elseif length(varargin) == 2
+        dim = varargin{1};
+        s = varargin{2};
+
+        errmsg = sprintf('Expected %s to have size %d along dimension %d, got: %d',inputname(1), s, dim, size(A,dim));
+        assert(size(A,dim) == s, errmsg);
+    else
+        error('Expected 2 or 3 arguments to assertSize()');
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb assertStructFields.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertStructFields.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,12 @@
+% Assert that the struct s has the all the field names in the cell array fns.
+function assertStructFields(s, fns)
+    assertType(s, 'struct');
+    assertType(fns, 'cell');
+
+    ok = ismember(fns, fieldnames(s));
+    if ~all(ok)
+        str1 = sprintf("'%s' must have the fields %s\n", inputname(1), toString(fns));
+        str2 = sprintf("The following fields are missing: %s", toString(fns(~ok)));
+        error(str1 + str2);
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb assertSymbolic.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertSymbolic.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,3 @@
+function assertSymbolic(s)
+    assert(logical(simplify(s)));
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb assertType.m
--- a/assertType.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/assertType.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,5 +1,11 @@
 function assertType(obj, type)
-    if ~isa(obj, type)
-        error('sbplib:assertType:wrongType', '"%s" must have type "%s", found "%s"', inputname(1), type, class(obj));
+    if ~iscell(type)
+        if ~isa(obj, type)
+            error('sbplib:assertType:wrongType', '"%s" must have type "%s", found "%s"', inputname(1), type, class(obj));
+        end
+    else
+        if ~isAnyOf(obj, type)
+            error('sbplib:assertType:wrongType', '"%s" must be one of the types %s, found "%s"', inputname(1), toString(type), class(obj));
+        end
     end
 end
diff -r fdf0ef9150f4 -r 501750fbbfdb assert_size.m
--- a/assert_size.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/assert_size.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,16 +1,5 @@
 % Assert that array A has the size s.
 function assert_size(A,s)
-    errmsg = sprintf('Expected %s to have size %s, got: %s',inputname(1), format_vector(s), format_vector(size(A)));
-    assert(all(size(A) == s),errmsg);
-end
-
-function str = format_vector(a)
-    l = length(a);
-    str = sprintf('[%d',a(1));
-
-    for i = 2:l
-        str = [str sprintf(', %d',a(i))];
-    end
-
-    str = [str ']'];
+    warning('Use assertSize() instead!')
+    assertSize(A,s);
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb cell2sparse.m
--- a/cell2sparse.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,54 +0,0 @@
-function A = cell2sparse(C)
-
-    if isempty(C)
-        A = sparse([]);
-        return
-    end
-
-    n = row_height(C);
-    m = col_width(C);
-
-    N = sum(n);
-    M = sum(m);
-
-    A = sparse(N,M);
-
-    n_ind = [0 cumsum(n)];
-    m_ind = [0 cumsum(m)];
-
-    for i = 1:size(C,1)
-        for j = 1:size(C,2)
-            if ~has_matrix(C{i,j})
-                continue
-            end
-            A(n_ind(i)+1:n_ind(i+1),m_ind(j)+1:m_ind(j+1)) = C{i,j};
-        end
-    end
-
-end
-
-function m = col_width(C)
-    for j = 1:size(C,2)
-        for i = 1:size(C,1)
-            if ~has_matrix(C{i,j})
-                continue
-            end
-            m(j) = size(C{i,j},2);
-        end
-    end
-end
-
-function n = row_height(C)
-    for i = 1:size(C,1)
-        for j = 1:size(C,2)
-            if ~has_matrix(C{i,j})
-                continue
-            end
-            n(i) = size(C{i,j},1);
-        end
-    end
-end
-
-function b = has_matrix(c)
-    b = ~(isempty(c) || (numel(c)==1 && c == 0));
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb cell2vector.m
--- a/cell2vector.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-% cell2vector accepts a column cell array of column vectors and returns a columnvector
-% with the input concatenated. It also returns the number of elements in each vector.
-%   cv -- column cell array with column vectors
-%   v  -- vector of the concatenated vectors
-%   n  -- number of elements in each vector before concatenation. Can be used with vector2cell().
-function [v, n] = cell2vector(cv)
-    v = [];
-    n = zeros(length(cv),1);
-
-    for i = 1:length(cv)
-        n(i) = length(cv{i});
-        v = [v; cv{i}];
-    end
-end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb centerColorbar.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/centerColorbar.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,6 @@
+function centerColorbar(ah)
+    old = ah.CLim;
+
+    l = max(abs(old));
+    ah.CLim = [-l l];
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb convergencePlot.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/convergencePlot.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,55 @@
+function hand = convergencePlot(orders, h, e)
+    N = length(orders);
+
+    fh = figure();
+    ah = axes();
+    ah.XScale = 'log';
+    ah.YScale = 'log';
+    hold on
+    ph = {};
+    phc = {};
+    legends = {};
+    for i = 1:N
+        ph{i} = loglog(h{i}, e{i});
+        phc{i} = plotConvergenceFit(orders{i}, h{i}, e{i});
+
+        ph{i}.LineStyle = 'none';
+        ph{i}.Marker = Color.solidMarkers{i};
+        ph{i}.MarkerSize = 12;
+        ph{i}.Color = Color.colors{i};
+        ph{i}.MarkerFaceColor = Color.colors{i};
+
+        legends{i} = sprintf('$o = %d$', orders{i});
+    end
+    hold off
+
+    lh = legend([ph{:}], legends);
+    lh.Interpreter = 'latex';
+    lh.Location = 'SouthEast';
+
+    for i = 1:N
+        uistack(phc{i}, 'bottom');
+    end
+
+    xlabel('$h$', 'interpreter', 'latex')
+    ylabel('Error', 'interpreter', 'latex')
+
+    % xlim([0.7e-2, 1e-1])
+    % ylim([3e-5, 4])
+
+    grid on
+
+    ah = gca();
+    ah.TickLabelInterpreter = 'latex';
+    setFontSize(fh);
+
+    % if savePngs
+    %     savepng(fh, 'fig/conv/conv',600)
+    % end
+
+    hand = struct();
+    hand.fig = fh;
+    hand.data = ph;
+    hand.fits = phc;
+    hand.legend = lh;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb copyWithDefault.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/copyWithDefault.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,31 @@
+% Copy the struct src to dest with default values from default
+%   dest = copyWithDefault(src, default)
+function dest = copyWithDefault(src, default)
+    % src does not have a value => use default
+    if isempty(src)
+        dest = default;
+        return
+    end
+
+    % src has a value and is not a struct => use src
+    % src has a value and default is not a struct => use src
+    if ~isstruct(src) || ~isstruct(default)
+        dest = src;
+        return
+    end
+
+
+    % src has a value and is a struct => add all default fields
+    dest = src;
+
+    fn = fieldnames(default);
+    for i = 1:length(fn)
+        if isfield(src, fn{i})
+            srcField = src.(fn{i});
+        else
+            srcField = [];
+        end
+
+        dest.(fn{i}) = copyWithDefault(srcField, default.(fn{i}));
+    end
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb default_struct.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/default_struct.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,10 @@
+function default_struct(s, val)
+    if evalin('caller',sprintf('~exist(''%s'',''var'')',s))
+        given = [];
+    else
+        given = evalin('caller', s);
+    end
+
+    final = copyWithDefault(given, val);
+    assignin('caller', s, final);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb findZeros.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/findZeros.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,30 @@
+% findZeros looks for solutions to the equation f(x)==0 within
+% the limits lim with a granularity of h.
+% Returns a sorted list of unique solutions.
+function z = findZeros(f, lim, h)
+    n = ceil((lim(2)-lim(1))/h);
+    z0 = linspace(lim(1), lim(2), n);
+
+    z = zeros(1,n);
+
+    for i = 1:n
+        zt(i) = fzero(f, z0(i));
+    end
+
+    zt = sort(zt);
+
+    z = [];
+    for i = 1:n
+        if zt(i)  < lim(1) || zt(i) > lim(2)
+            continue
+        end
+
+        if ~isempty(z) && abs(z(end) - zt(i)) < 1e-6
+            continue
+        end
+
+        z = [z zt(i)];
+    end
+
+    % z = unique(z);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb four.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/four.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,19 @@
+% four returns the fourier transform u_hat of the function u and the frequencies w
+function [w, u_hat] = four(x, u)
+    u_hat = fft(u);
+
+    N = length(x);
+    L = x(end) - x(1);
+
+    k = shift_k(0:N-1);
+
+    u_hat = fftshift(u_hat);
+
+    dw = 2*pi/L;
+    w = dw*k;
+end
+
+function k_shifted = shift_k(k)
+    N = length(k);
+    k_shifted = [-floor(N/2):-1, 0, 1:ceil(N/2)-1];
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb fourInv.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fourInv.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+function u = ifour(u_hat)
+    u_hat = ifftshift(u_hat);
+    u = ifft(u_hat);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb gaussian.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gaussian.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,3 @@
+function z = gaussian(x,x0,d)
+    z = exp(-sum((x-x0).^2,2)/d^2);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb isAnyOf.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/isAnyOf.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,11 @@
+% Returns true of obj is any of he types in the cell array types
+%    b = isAnyOf(obj, types)
+function b = isAnyOf(obj, types)
+    for i = 1:length(types)
+        if isa(obj, types{i});
+            b = true;
+            return
+        end
+    end
+    b = false;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb kroneckerDelta.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kroneckerDelta.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,6 @@
+function d = kroneckerDelta(i,j)
+
+d = 0;
+if i==j
+	d = 1;
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb matlabFunctionSizePreserving.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/matlabFunctionSizePreserving.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,12 @@
+% Takes a symfun and makes a better anonymous function
+function fun = matlabFunctionSizePreserving(f)
+    mf = matlabFunction(f);
+    args = argnames(f);
+
+    funStr = func2str(mf);
+    for i = 1:length(args)
+        funStr = [funStr sprintf(' + 0*%s', toString(args(i)))];
+    end
+
+    fun = str2func(funStr);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb minors.m
--- a/minors.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/minors.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,4 +1,5 @@
-function [minor, sub] = minors(A)
+function [minor, sub] = minors(A, verbose)
+    default_arg('verbose', true);
     [n, m] = size(A);
 
     if n ~= m
@@ -18,8 +19,10 @@
     end
 
     for i = 1:length(sub)
-        fprintf('%d:\n', ks{i});
-        disp(sub{i})
+        if verbose
+            fprintf('%d:\n', ks{i});
+            disp(sub{i})
+        end
 
         minor(i) = det(sub{i});
     end
diff -r fdf0ef9150f4 -r 501750fbbfdb mononomial.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mononomial.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,17 @@
+% calculate a N-D mononomial with powers k in points x:
+%  z = x(:,1).^k(1) * x(:,2).^k(2) * ...
+function z = mononomial(x, k)
+    assert(size(x,2) == length(k), 'k must have the same length as the width of x');
+
+    if any(k < 0)
+        z = x(:,1)*0;
+        return
+    end
+
+    denom = prod(factorial(k));
+
+    for i = 1:length(k)
+        x(:,i) = x(:,i).^k(i);
+    end
+    z = prod(x,2)/denom;
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb nextColor.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nextColor.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,5 @@
+function c = nextColor(ah)
+    default_arg('ah', gca);
+
+    c = ah.ColorOrder(ah.ColorOrderIndex, :);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb pointIndex.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pointIndex.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+% Get the index of the points p within the tall array of points ps
+function [I, ok] = pointIndex(p, ps)
+    [ok, I] = ismember(p,  ps, 'rows');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb reshapeRowMaj.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reshapeRowMaj.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,12 @@
+% Reshapes a matrix as if it was stored in row major order.
+function B = reshapeRowMaj(A, m)
+    D = length(m);
+
+    if D == 1
+        m = [m 1];
+        D = 2;
+    end
+
+    % Reshape and reverse order of indecies
+    B = permute(reshape(permute(A, ndims(A):-1:1), rot90(m,2)), D:-1:1);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb reshapeRowMajTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reshapeRowMajTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,113 @@
+function tests = reshapeRowMajTest()
+    tests = functiontests(localfunctions);
+end
+
+function test1D(testCase)
+    in = {
+        {5,[1; 2; 3; 4; 5]},
+        {5,[1 2 3 4 5]},
+    };
+    out = {
+        [1; 2; 3; 4; 5],
+        [1; 2; 3; 4; 5],
+    };
+    for i = 1:length(in)
+        testCase.verifyEqual(reshapeRowMaj(in{i}{2}, in{i}{1}),out{i});
+    end
+end
+
+
+function testIdentity(testCase)
+     in = {
+        {[2,2], magic(2)},
+        {[3,3], magic(3)},
+        {[2,3], [1 2 3; 4 5 6]},
+    };
+
+    for i = 1:length(in)
+        testCase.verifyEqual(reshapeRowMaj(in{i}{2}, in{i}{1}),in{i}{2});
+    end
+end
+
+function test2D(testCase)
+    in = {
+        {[2,2],[11; 12; 21; 22]},
+        {[3,2],[1 2 3; 4 5 6]},
+        {[6 1],[1 2 3; 4 5 6]},
+        {[1 6],[1 2 3; 4 5 6]},
+    };
+
+    out{1}(1,1) = 11;
+    out{1}(1,2) = 12;
+    out{1}(2,1) = 21;
+    out{1}(2,2) = 22;
+
+    out{2} = [1 2; 3 4; 5 6];
+    out{3} = [1; 2; 3; 4; 5; 6];
+    out{4} = [1 2 3 4 5 6];
+
+    for i = 1:length(in)
+        testCase.verifyEqual(reshapeRowMaj(in{i}{2}, in{i}{1}),out{i});
+    end
+end
+
+function test3D(testCase)
+    in = {
+        {[2, 2, 2], [111; 112; 121; 122; 211; 212; 221; 222]},
+        {[8 1], cat(3,[1 2; 3 4],[5 6; 7 8])},
+        {[1 8], cat(3,[1 2; 3 4],[5 6; 7 8])},
+        {[2 4], cat(3,[1 2; 3 4],[5 6; 7 8])},
+        {[4 2], cat(3,[1 2; 3 4],[5 6; 7 8])},
+    };
+
+    out{1}(1,1,1) = 111;
+    out{1}(1,1,2) = 112;
+    out{1}(1,2,1) = 121;
+    out{1}(1,2,2) = 122;
+    out{1}(2,1,1) = 211;
+    out{1}(2,1,2) = 212;
+    out{1}(2,2,1) = 221;
+    out{1}(2,2,2) = 222;
+
+    out{2} = [1; 5; 2; 6; 3; 7; 4; 8];
+    out{3} = [1  5  2  6  3  7  4  8];
+    out{4} = [1  5  2  6;  3  7  4  8];
+    out{5} = [1  5;  2  6;  3  7;  4  8];
+
+    for i = 1:length(in)
+        testCase.verifyEqual(reshapeRowMaj(in{i}{2}, in{i}{1}),out{i});
+    end
+end
+
+function testNonSquare(testCase)
+    in = {
+        {[2, 3, 4],[111; 112; 113; 114; 121; 122; 123; 124; 131; 132; 133; 134; 211; 212; 213; 214; 221; 222; 223; 224; 231; 232; 233; 234]},
+    };
+    out{1}(1,1,1) = 111;
+    out{1}(1,1,2) = 112;
+    out{1}(1,1,3) = 113;
+    out{1}(1,1,4) = 114;
+    out{1}(1,2,1) = 121;
+    out{1}(1,2,2) = 122;
+    out{1}(1,2,3) = 123;
+    out{1}(1,2,4) = 124;
+    out{1}(1,3,1) = 131;
+    out{1}(1,3,2) = 132;
+    out{1}(1,3,3) = 133;
+    out{1}(1,3,4) = 134;
+    out{1}(2,1,1) = 211;
+    out{1}(2,1,2) = 212;
+    out{1}(2,1,3) = 213;
+    out{1}(2,1,4) = 214;
+    out{1}(2,2,1) = 221;
+    out{1}(2,2,2) = 222;
+    out{1}(2,2,3) = 223;
+    out{1}(2,2,4) = 224;
+    out{1}(2,3,1) = 231;
+    out{1}(2,3,2) = 232;
+    out{1}(2,3,3) = 233;
+    out{1}(2,3,4) = 234;
+    for i = 1:length(in)
+        testCase.verifyEqual(reshapeRowMaj(in{i}{2}, in{i}{1}),out{i});
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb reshapeToPlotMatrix.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reshapeToPlotMatrix.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,17 @@
+% Takes a grid function and reshapes it into a matrix of shape m for plotting.
+function F = reshapeToPlotMatrix(gf, m)
+    D = length(m);
+
+    switch D
+        case 1
+            F = gf;
+        case 2
+            F = reshape(gf, rot90(m,2));
+        case 3
+            % After the reshape the indecies will be M(z,y,x). Plot need them to be M(y,x,z)
+            p = [2 3 1]; % Permuation
+            F = permute(reshape(gf,rot90(m,2)), p);
+        otherwise
+            error('reshapeToPlotMatrix:NotImplemented','Grid function to matrix is not implemented for dimension = %d', length(m));
+    end
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb reshapeToPlotMatrixTest.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/reshapeToPlotMatrixTest.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,48 @@
+function tests = reshapeToPlotMatrixTest()
+    tests = functiontests(localfunctions);
+end
+
+function test1D(testCase)
+    inGf = [1 2 3 4 5]';
+    inM = 5;
+    out = [1 2 3 4 5]';
+    testCase.verifyEqual(reshapeToPlotMatrix(inGf, inM),out);
+end
+
+function test2D(testCase)
+    x = 1:2;
+    y = 1:3;
+
+    f = @(x,y) x + y*10;
+
+    xx = [1; 1; 1; 2; 2; 2];
+    yy = [1; 2; 3; 1; 2; 3];
+    inGf = f(xx,yy);
+
+    [X,Y] = meshgrid(x,y);
+    out = f(X,Y);
+
+    inM = [2, 3];
+
+    testCase.verifyEqual(reshapeToPlotMatrix(inGf, inM),out);
+end
+
+function test3D(testCase)
+    x = 1:2;
+    y = 1:3;
+    z = 1:4;
+
+    f = @(x,y,z) x + y*10 + z*100;
+
+    xx = [repmat(1, [12, 1]); repmat(2, [12, 1])];
+    yy = repmat([1; 1; 1; 1; 2; 2; 2; 2; 3; 3; 3; 3], [2, 1]);
+    zz = repmat([1; 2; 3; 4], [6, 1]);
+    inGf = f(xx,yy,zz);
+
+    [X,Y,Z] = meshgrid(x,y,z);
+    out = f(X,Y,Z);
+
+    inM = [2, 3, 4];
+
+    testCase.verifyEqual(reshapeToPlotMatrix(inGf, inM),out);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb rickerWavelet.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rickerWavelet.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,3 @@
+function y = rickerWavelet(x, x0, A)
+    y = (1-2*pi^2*A^2*(x-x0).^2).*exp(-pi^2*A^2*(x-x0).^2);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb runtestsPackage.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/runtestsPackage.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+function res = runtestsPackage(pkgName)
+    ts = matlab.unittest.TestSuite.fromPackage(pkgName);
+    res = ts.run();
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb saveFigureSize.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/saveFigureSize.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,6 @@
+function saveFigurePosition()
+    defaultPosition = get(0,'defaultfigureposition');
+    f = gcf;
+    defaultPosition(3:4) = f.Position(3:4);
+    set(0,'defaultfigureposition',defaultPosition);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb sbplibLocation.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbplibLocation.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+function location = sbplibLocation()
+    scriptname  = mfilename('fullpath');
+    [location, ~, ~] = fileparts(scriptname);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb sbplibVersion.m
--- a/sbplibVersion.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/sbplibVersion.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,11 +1,10 @@
 % Prints the version and location of the sbplib currently in use.
 function sbplibVersion()
-    scriptname  = mfilename('fullpath');
-    [folder,~,~] = fileparts(scriptname);
+    location = sbplibLocation();
 
-    name = 'sbplib';
+    name = 'sbplib (feature/grids)';
     ver = '0.0.x';
 
     fprintf('%s %s\n', name, ver);
-    fprintf('Running in:\n%s\n',folder);
+    fprintf('Running in:\n%s\n', location);
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb semiDefIneq.m
--- a/semiDefIneq.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/semiDefIneq.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,5 +1,6 @@
-function ineq = semiDefIneq(A)
-    [m, sub] = minors(A);
+function ineq = semiDefIneq(A, verbose)
+    default_arg('verbose', true);
+    [m, sub] = minors(A, verbose);
 
     ineqsys = true;
     for i = 1:length(m)
diff -r fdf0ef9150f4 -r 501750fbbfdb skewPart.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/skewPart.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+% Returns the skew of A
+function S = skewPart(A, tol)
+    S = 1/2*(A - A');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb spdiag.m
--- a/spdiag.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/spdiag.m	Fri Sep 07 14:40:58 2018 +0200
@@ -5,6 +5,6 @@
         a = a';
     end
 
-    n = length(a)-abs(i);
+    n = length(a)+abs(i);
     A = spdiags(a,i,n,n);
 end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb spdiagsPeriodic.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spdiagsPeriodic.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,60 @@
+function A = spdiagsPeriodic(vals,diags)
+    % Creates an m x m periodic discretization matrix.
+    % vals - m x ndiags matrix of values
+    % diags - 1 x ndiags vector of the 'center diagonals' that vals end up on
+    % vals that are not on main diagonal are going to spill over to
+    % off-diagonal corners.
+
+    default_arg('diags',0);
+
+    [m, ~] = size(vals);
+
+    A = sparse(m,m);
+
+    for i = 1:length(diags)
+
+        d = diags(i);
+        a = vals(:,i);
+
+        % Sub-diagonals
+        if d < 0
+            a_bulk = a(1+abs(d):end);
+            a_corner = a(1:1+abs(d)-1);
+            corner_diag = m-abs(d);
+            A = A + spdiagVariable(a_bulk, d);
+            A = A + spdiagVariable(a_corner, corner_diag);
+
+        % Super-diagonals
+        elseif d > 0
+            a_bulk = a(1:end-d);
+            a_corner = a(end-d+1:end);
+            corner_diag = -m + d;
+            A = A + spdiagVariable(a_bulk, d);
+            A = A + spdiagVariable(a_corner, corner_diag);
+
+        % Main diagonal
+        else
+             A = A + spdiagVariable(a, 0);
+        end
+
+    end
+
+end
+
+function A = spdiagVariable(a,i)
+    default_arg('i',0);
+
+    if isrow(a)
+        a = a';
+    end
+
+    n = length(a)+abs(i);
+
+    if i > 0
+        a = [sparse(i,1); a];
+    elseif i < 0
+        a = [a; sparse(abs(i),1)];
+    end
+
+    A = spdiags(a,i,n,n);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb stencilEquation.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stencilEquation.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,13 @@
+% Find the equation for the stencil for d^k/dx^k
+function [A,b] = stencilEquation(k, offsets, order)
+    q = sym('q', [1, length(offsets)]);
+
+    p = 0:(order-1+k);
+
+    v     = vandermonde(offsets, p);
+    vdiff = vandermonde(      0, p-k);
+
+    eq = q*v == vdiff;
+
+    [A,b] = equationsToMatrix(eq, q);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb stripeMatrixPeriodic.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/stripeMatrixPeriodic.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,8 @@
+% Creates a periodic discretization matrix of size n x n
+%  with the values of val on the diagonals diag.
+%   A = stripeMatrix(val,diags,n)
+function A = stripeMatrixPeriodic(val,diags,n)
+
+    D = ones(n,1)*val;
+    A = spdiagsPeriodic(D,diags);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb subsSymfun.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/subsSymfun.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,14 @@
+% Subs for a symfun
+% f remains a symbolic function. If any of it's arguments is eliminated
+% it is removed from the argument list while preserving the order of the
+% other arguments
+function f = subsSymfun(f, old, new)
+    args = argnames(f);
+
+    newExpr = subs(f, old, new);
+    vars = symvar(subs(args, old, new));
+
+    newArgs = args(ismember(args,vars));
+
+    f = symfun(newExpr, newArgs);
+end
\ No newline at end of file
diff -r fdf0ef9150f4 -r 501750fbbfdb symmetricPart.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symmetricPart.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,4 @@
+% Returns the symmetric of A
+function S = symmetricPart(A, tol)
+    S = 1/2*(A + A');
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb timeTask.m
--- a/timeTask.m	Fri Sep 07 14:39:38 2018 +0200
+++ b/timeTask.m	Fri Sep 07 14:40:58 2018 +0200
@@ -1,5 +1,5 @@
-function done = timeTask(taskName)
-    fprintf('%s', taskName);
+function done = timeTask(fmt, varargin)
+    fprintf(fmt, varargin{:});
     tStart = tic;
 
     function done_fun()
diff -r fdf0ef9150f4 -r 501750fbbfdb vandermonde.m
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vandermonde.m	Fri Sep 07 14:40:58 2018 +0200
@@ -0,0 +1,15 @@
+% Create vandermonde matrix for points x and polynomials of order p
+% x is a list of N points of size [N,dim],
+% p is a list of polynomial orders of size [M, dim].
+% the given mononomials are evaluated and the NxM matrix V is returned.
+function V = vandermonde(x, p)
+    assert(size(x,2) == size(p,2), 'x and p must have the same number of columns')
+    n = size(x,1);
+    m = size(p,1);
+
+    for i = 1:m
+        V(:,i) = mononomial(x, p(i,:));
+    end
+
+    assertSize(V,[n,m]);
+end
diff -r fdf0ef9150f4 -r 501750fbbfdb vector2cell.m
--- a/vector2cell.m	Fri Sep 07 14:39:38 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-% Splits column vector v into segments of length n and returns the result as a column cell array.
-%   v  -- column vector to be split
-%   n  -- number of elements in each part
-%
-%   cv -- cell array of vectors with lenght n(i)
-function cv = vector2cell(v,n)
-    cv = cell(length(n),1);
-
-    ind = [0; cumsum(n)];
-    for i = 1:length(n)
-        ind_i = (ind(i)+1):ind(i+1);
-        cv{i} = v(ind_i);
-    end
-end
\ No newline at end of file