changeset 707:0de70ec8bf60 feature/quantumTriangles

merge with feature/optim
author Ylva Rydin <ylva.rydin@telia.com>
date Fri, 10 Nov 2017 14:22:56 +0100
parents 7c16b5af8d98 (current diff) a95c89436916 (diff)
children acb58769610e
files +grid/Ti3D.m +multiblock/BoundaryGroupTest.m
diffstat 72 files changed, 2186 insertions(+), 526 deletions(-) [+]
line wrap: on
line diff
--- a/+blockmatrix/fromMatrixTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/fromMatrixTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -46,6 +46,20 @@
                 [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}{:}));
--- a/+blockmatrix/getDivision.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/getDivision.m	Fri Nov 10 14:22:56 2017 +0100
@@ -16,7 +16,7 @@
     m = zeros(1,size(C,2));
     for j = 1:size(C,2)
         for i = 1:size(C,1)
-            if isempty(C{i,j})
+            if isNullMatrix(C{i,j})
                 continue
             end
             m(j) = size(C{i,j},2);
@@ -28,10 +28,15 @@
     n = zeros(1,size(C,1));
     for i = 1:size(C,1)
         for j = 1:size(C,2)
-            if isempty(C{i,j})
+            if isNullMatrix(C{i,j})
                 continue
             end
             n(i) = size(C{i,j},1);
         end
     end
-end
\ No newline at end of file
+end
+
+function b = isNullMatrix(A)
+    [n, m] = size(A);
+    b = n == 0 && m == 0;
+end
--- a/+blockmatrix/getDivisionTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/getDivisionTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -56,6 +56,18 @@
             },
             {[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)
--- a/+blockmatrix/isBlockmatrix.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/isBlockmatrix.m	Fri Nov 10 14:22:56 2017 +0100
@@ -4,7 +4,7 @@
         return
     end
 
-    % Make sure all blocks are numerica matrices
+    % Make sure all blocks are numerical matrices
     for i = 1:length(bm)
         if ~isnumeric(bm{i})
             b = false;
--- a/+blockmatrix/isDivision.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/isDivision.m	Fri Nov 10 14:22:56 2017 +0100
@@ -21,11 +21,11 @@
 
 function b = isDivisionVector(v)
     if isempty(v)
-        b = false;
+        b = true;
         return
     end
 
-    if any(v <= 0)
+    if any(v < 0)
         b = false;
         return
     end
--- a/+blockmatrix/isDivisionTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/isDivisionTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -4,14 +4,16 @@
 
 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]} ,false},
-        {{[0 2],[1 1]} ,false},
-        {{[1 2],[]} ,false},
+        {{[1 2],[1 0]} ,true},
+        {{[0 2],[1 1]} ,true},
         {{[1 2],[1]} ,true},
         {{[1 2],[1], [1 2 3]} ,false},
-        {{[1 2 3]} ,false},
-        {[1 2] ,false},
     };
 
     for i = 1:length(cases)
--- a/+blockmatrix/toMatrix.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/toMatrix.m	Fri Nov 10 14:22:56 2017 +0100
@@ -12,16 +12,12 @@
 
     A = sparse(N,M);
 
-    n_ind = [0 cumsum(n)];
-    m_ind = [0 cumsum(m)];
-
     for i = 1:size(bm,1)
         for j = 1:size(bm,2)
             if isempty(bm{i,j})
-                continue
+                bm{i,j} = sparse(n(i),m(j));
             end
-            % TODO: If this ever fails for large matrices. Try cell2mat instead.
-            A(n_ind(i)+1:n_ind(i+1),m_ind(j)+1:m_ind(j+1)) = bm{i,j};
         end
     end
+    A = cell2mat(bm);
 end
--- a/+blockmatrix/toMatrixTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/toMatrixTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -51,6 +51,22 @@
             [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)
--- a/+blockmatrix/zero.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/zero.m	Fri Nov 10 14:22:56 2017 +0100
@@ -1,6 +1,6 @@
 % Creates a block matrix according to the division with zeros everywhere.
 function bm = zero(div)
-    if ~blockmatrix.isDivision(div);
+    if ~blockmatrix.isDivision(div)
         error('div is not a valid division');
     end
 
--- a/+blockmatrix/zeroTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+blockmatrix/zeroTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -32,6 +32,22 @@
             {[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)
--- a/+grid/Cartesian.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+grid/Cartesian.m	Fri Nov 10 14:22:56 2017 +0100
@@ -15,6 +15,8 @@
             obj.d = length(varargin);
 
             for i = 1:obj.d
+                assert(isvector(varargin{i}), 'Coordinate inputs must be a vectors.')
+
                 obj.x{i} = varargin{i};
                 obj.m(i) = length(varargin{i});
             end
--- a/+grid/Curvilinear.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+grid/Curvilinear.m	Fri Nov 10 14:22:56 2017 +0100
@@ -19,6 +19,9 @@
 
             % 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
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/Empty.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- a/+grid/Grid.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+grid/Grid.m	Fri Nov 10 14:22:56 2017 +0100
@@ -16,7 +16,7 @@
         % Projects the grid function gf on obj to the grid g.
         gf = projectFunc(obj, gf, g)
 
-        % Return the names of all boundaries in this grid.
+        % Return the grid.boundaryIdentifiers of all boundaries in a cell array.
         bs = getBoundaryNames(obj)
 
         % Return coordinates for the given boundary
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/TODO.txt	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,1 @@
+% TODO: Rename grid package. name conflicts with built in function
--- a/+grid/Ti3D.m	Thu Oct 05 18:04:23 2017 +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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/boundaryIdentifier.txt	Fri Nov 10 14:22:56 2017 +0100
@@ -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.
--- a/+grid/evalOn.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+grid/evalOn.m	Fri Nov 10 14:22:56 2017 +0100
@@ -7,39 +7,34 @@
 function gf = evalOn(g, func)
     if ~isa(func, 'function_handle')
         % We should have a constant.
-        if size(func,2) ~= 1
-            error('grid:evalOn:VectorValuedWrongDim', 'A vector valued function must be given as a column vector')
-        end
+        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),'grid:evalOn:WrongNumberOfInputs', 'The number of inputs of the function must match the dimension of the domain.')
 
-    if g.D ~= nargin(func)
-        g.D
-        nargin(func)
-        error('grid:evalOn:WrongNumberOfInputs', 'The number of inputs of the function must match the dimension of the domain.')
-    end
+    x = num2cell(g.points(),1);
+    k = numberOfComponents(func);
 
+    gf = func(x{:});
+    gf = reorderComponents(gf, k);
+end
 
-    % Get coordinates and convert to cell array for easier use as a parameter
-    x = num2cell(g.points());
-
-    % Find the number of components
-    x0 = x(1,:);
+% Find the number of vector components of func
+function k = numberOfComponents(func)
+    x0 = num2cell(ones(1,nargin(func)));
     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);
-
-    if size(f0,2) ~= 1
-        error('grid:evalOn:VectorValuedWrongDim', 'A vector valued function must be given as a column vector')
-    end
+end
 
-    gf = zeros(g.N*k, 1);
-    % keyboard
-    for i = 1:g.N
-        % (1 + (i-1)*k):(i*k)
-        % func(x{i,:})
-        gf((1 + (i-1)*k):(i*k)) = func(x{i,:});
+% 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
\ No newline at end of file
+end
--- a/+grid/evalOnTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+grid/evalOnTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -31,7 +31,7 @@
     cases = {
         {getTestGrid('1d'), @(x,y)x-y},
         {getTestGrid('2d'), @(x)x    },
-    }
+    };
 
     for i = 1:length(cases)
         g = cases{i}{1};
@@ -111,9 +111,9 @@
 
 
 function testInputErrorVectorValued(testCase)
-     in  = {
+    in  = {
         [1,2,3],
-        @(x,y)[x,-y];
+        @(x,y)[x,-y],
     };
 
     g = getTestGrid('2d');
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+grid/gridFunction.txt	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,1 @@
+TODO: Add documentation for gridfunctions here
\ No newline at end of file
--- a/+multiblock/BoundaryGroup.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+multiblock/BoundaryGroup.m	Fri Nov 10 14:22:56 2017 +0100
@@ -1,30 +1,10 @@
 % BoundaryGroup defines a boundary grouping in a multiblock grid.
-classdef BoundaryGroup
-    properties
-        blockIDs
-        names
-    end
-
+% 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(varargin)
-            % Input arguemnts are arbitrary number or 1x2 cell arrays
-            % representing each boundary in the group.
-            % The 1st element of the cell array is an integer defining which grid it belongs to.
-            % The 2nd element of the cell array is the name of the boundary within the block.
-            %
-            % Ex:
-            %   bg = multiblock.BoundaryGroup({1,'n'},{1,'s'},{2,'s'})
-
-
-            obj.blockIDs = [];
-            obj.names = {};
-            for i = 1:length(varargin)
-                if ~iscell(varargin{i}) || ~all(size(varargin{i}) == [1 2])
-                    error('multiblock:BoundaryGroup:BoundaryGroup:InvalidInput', 'Inputs must be 1x2 cell arrays');
-                end
-                obj.blockIDs(i) = varargin{i}{1};
-                obj.names{i} = varargin{i}{2};
-            end
+        function obj = BoundaryGroup(data)
+            obj = obj@Cell(data);
         end
 
         function display(obj, name)
@@ -33,19 +13,7 @@
             disp([name, ' ='])
             disp(' ')
 
-            if length(obj.names) == 1
-                fprintf('    {}\n\n')
-                return
-            end
-
-            fprintf('    {')
-
-            fprintf('%d:%s', obj.blockIDs(1), obj.names{1})
-            for i = 2:length(obj.names)
-                fprintf(', %d:%s', obj.blockIDs(i), obj.names{i});
-            end
-
-            fprintf('}\n\n')
+            fprintf('    BoundaryGroup%s\n\n', toString(obj.data));
         end
     end
-end
\ No newline at end of file
+end
--- a/+multiblock/BoundaryGroupTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,30 +0,0 @@
-function tests = BoundaryGroupTest()
-    tests = functiontests(localfunctions);
-end
-
-function testCreation(testCase)
-    in = {{3,'n'},{2,'hoho'},{1,'s'}};
-
-    blockIDs = [3 2 1];
-    names = {'n', 'hoho', 's'};
-
-    bg = multiblock.BoundaryGroup(in{:});
-    testCase.verifyEqual(bg.blockIDs, blockIDs);
-    testCase.verifyEqual(bg.names, names);
-end
-
-function testInputError(testCase)
-    in = {
-        {'n', 's'},
-        {{3,'n'},{2,2,'hoho'},{1,'s'}},
-    };
-
-    out = {
-        'multiblock:BoundaryGroup:BoundaryGroup:InvalidInput',
-        'multiblock:BoundaryGroup:BoundaryGroup:InvalidInput',
-    };
-
-    for i = 1:length(in)
-        testCase.verifyError(@()multiblock.BoundaryGroup(in{i}{:}), out{i});
-    end
-end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Contour.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Def.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,101 @@
+classdef Def
+    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 = Def(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 show(obj, label, gridLines, varargin)
+            default_arg('label', 'name')
+            default_arg('gridLines', false);
+
+            if isempty('label') && ~gridLines
+                for i = 1:obj.nBlocks
+                    obj.blockMaps{i}.show(2,2);
+                end
+                axis equal
+                return
+            end
+
+            if gridLines
+                ms = obj.getGridSizes(varargin{:});
+                for i = 1:obj.nBlocks
+                    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
+                otherwise
+                    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
+
+
--- a/+multiblock/DiffOp.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+multiblock/DiffOp.m	Fri Nov 10 14:22:56 2017 +0100
@@ -5,12 +5,12 @@
         diffOps
         D
         H
-        
+
         blockmatrixDiv
     end
-    
+
     methods
-        function obj = DiffOp(doHand, grid, order, doParam,timeDep)
+        function obj = DiffOp(doHand, grid, 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, ...)
@@ -25,13 +25,13 @@
             %            doHand(..., doParam{i}{:}) Otherwise doParam is sent as
             %            extra parameters to all doHand: doHand(..., doParam{:})
             default_arg('doParam', [])
-            
+
             [getHand, getParam] = parseInput(doHand, grid, doParam);
-            
+
             nBlocks = grid.nBlocks();
-            
+
             obj.order = order;
-            
+
             % Create the diffOps for each block
             obj.diffOps = cell(1, nBlocks);
             for i = 1:nBlocks
@@ -42,73 +42,48 @@
                 end
                 obj.diffOps{i} = h(grid.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
-            switch timeDep
-                case {'n','no','N','No'}
-                    obj.blockmatrixDiv = {grid.Ns, grid.Ns};
-                    D = blockmatrix.zero(obj.blockmatrixDiv);
-                    for i = 1:nBlocks
-                        D{i,i} = obj.diffOps{i}.D;
+            obj.blockmatrixDiv = {grid.Ns, grid.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 = grid.connections{i,j};
+                    if isempty(intf)
+                        continue
                     end
-                    
-                    for i = 1:nBlocks
-                        for j = 1:nBlocks
-                            intf = grid.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);
-                case {'y','yes','Y','Yes'}
-                    for i = 1:nBlocks
-                        D{i,i} = @(t)obj.diffOps{i}.D(t);
-                    end
-                    
-                    for i = 1:nBlocks
-                        for j = 1:nBlocks
-                            intf = grid.connections{i,j};
-                            if isempty(intf)
-                                continue
-                            end
-                            
-                            [ii, ij] = obj.diffOps{i}.interface(intf{1}, obj.diffOps{j}, intf{2});
-                            D{i,i} = @(t)D{i,i}(t) + ii(t);
-                            D{i,j} = ij;
-                            
-                            [jj, ji] = obj.diffOps{j}.interface(intf{2}, obj.diffOps{i}, intf{1});
-                            D{j,j} = @(t)D{j,j}(t) + jj(t);
-                            D{j,i} = ji;
-                        end
-                    end
-                obj.D = D;   
+
+
+                    [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);
+
+
             function [getHand, getParam] = parseInput(doHand, grid, doParam)
                 if ~isa(grid, 'multiblock.Grid')
                     error('multiblock:DiffOp:DiffOp:InvalidGrid', 'Requires a multiblock grid.');
                 end
-                
+
                 if iscell(doHand) && length(doHand) == grid.nBlocks()
                     getHand = @(i)doHand{i};
                 elseif isa(doHand, 'function_handle')
@@ -116,62 +91,89 @@
                 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) == grid.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
-        
-        function op = getBoundaryOperator(obj, op, boundary)
-            if iscell(boundary)
-                localOpName = [op '_' 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
-            else
-                % Boundary är en sträng med en boundary group i.
+
+        % 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
-        
+
         % 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'}
+        %                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)
@@ -185,25 +187,27 @@
                     closure{i} = blockmatrix.toMatrix(temp);
                 end
             end
-            
-            div{2} = size(blockPenalty, 2); % Penalty is a column vector
+
             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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/DiffOpTimeDep.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,210 @@
+classdef DiffOpTimeDep < scheme.Scheme
+    properties
+        grid
+        order
+        diffOps
+        D
+        H
+
+        blockmatrixDiv
+    end
+
+    methods
+        function obj = DiffOpTimeDep(doHand, grid, 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.
+            %    grid -- 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, grid, doParam);
+            obj.grid = grid;
+            nBlocks = grid.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(grid.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
+            obj.blockmatrixDiv = {grid.Ns, grid.Ns};
+            %      D = blockmatrix.zero(obj.blockmatrixDiv);
+            
+            for i = 1:nBlocks
+                for j = 1:nBlocks
+                    D{i,j} = @(t) 0;
+                    D{j,i} = @(t) 0;
+                end
+            end
+            
+            
+            for i = 1:nBlocks
+                D{i,i} = @(t)obj.diffOps{i}.D(t);
+            end
+            
+            for i = 1:nBlocks
+                for j = 1:nBlocks
+                    intf = grid.connections{i,j};
+                    if isempty(intf)
+                        continue
+                    end
+                    
+                    
+                    [ii, ij] = obj.diffOps{i}.interface(intf{1}, obj.diffOps{j}, intf{2});
+                    D{i,i} = @(t) D{i,i}(t) + ii(t);
+                    D{i,j} = @(t) D{i,j}(t) + ij(t);
+                    
+                    [jj, ji] = obj.diffOps{j}.interface(intf{2}, obj.diffOps{i}, intf{1});
+                    D{j,j} = @(t) D{j,j}(t) + jj(t);
+                    D{j,i} = @(t) D{j,i}(t) + ji(t);
+                end
+            end
+            obj.D = D;
+
+
+            function [getHand, getParam] = parseInput(doHand, grid, doParam)
+                if ~isa(grid, 'multiblock.Grid')
+                    error('multiblock:DiffOp:DiffOp:InvalidGrid', 'Requires a multiblock grid.');
+                end
+
+                if iscell(doHand) && length(doHand) == grid.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) == grid.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
+
+        % 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'
+                    nBlocks = obj.grid.nBlocks();
+                    %[n,m] = size(obj.D);
+                    %closure = sparse(n,m);
+                    %penalty = sparse(n,0);
+                    % closure =@(t)0;
+                    % penalty = @(t)0;
+                    for i = 1:nBlocks
+                        for j = 1:nBlocks
+                            closure{j,i} = @(t)0;
+                            penalty{j,i} = @(t)0;
+                        end
+                    end
+                    
+                    
+                    for i = 1:length(boundary)
+                        [closurePart, penaltyPart] = obj.boundary_condition(boundary{i}, type);
+                        closure{i,i} = @(t)closure{i,i}(t) + closurePart(t);
+                        penalty{i,i} = @(t)penalty{i,i}(t) + penaltyPart(t);
+                    end
+                otherwise
+                    error('Unknown boundary indentifier')
+            end
+
+        end
+
+        function [blockClosure, blockPenalty] = 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);
+              
+        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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/EmptyGrid.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- a/+multiblock/Grid.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+multiblock/Grid.m	Fri Nov 10 14:22:56 2017 +0100
@@ -9,16 +9,20 @@
 
     % 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?)
-        %% Should we have boundary groups at all? maybe it can be handled in a
-        %% cleaner way outside of the class.
+        % 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;
 
@@ -27,7 +31,7 @@
                 obj.nPoints = obj.nPoints + grids{i}.N();
             end
 
-            % if iscell(boundaryGroups)
+            obj.boundaryGroups = boundaryGroups;
         end
 
         function n = size(obj)
@@ -42,7 +46,7 @@
         % 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;
+            for i = 1:obj.nBlocks
                 ns(i) = obj.grids{i}.N();
             end
             o = ns;
@@ -59,7 +63,7 @@
 
         % points returns a n x d matrix containing the coordinates for all points.
         function X = points(obj)
-            X = [];
+            X = sparse(0,obj.D());
             for i = 1:length(obj.grids)
                 X = [X; obj.grids{i}.points];
             end
@@ -76,9 +80,29 @@
                 N(i) = obj.grids{i}.N();
             end
 
-            gfs = mat2cell(gf, N, 1);
+            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);
@@ -108,13 +132,43 @@
 
         end
 
+        % Find all non interface boundaries of all blocks.
+        % Return their grid.boundaryIdentifiers in a cell array.
         function bs = getBoundaryNames(obj)
-            bs = [];
+            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
-        function b = getBoundary(obj, name)
-            b = [];
+        % 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Line.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/Surface.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+noname/Animation.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- a/+noname/animate.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+noname/animate.m	Fri Nov 10 14:22:56 2017 +0100
@@ -1,10 +1,10 @@
-% 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)
+function animate(discretization, time_modifier, Tend, dirname, opt)
     default_arg('time_modifier', 1);
     default_arg('Tend', Inf);
     default_arg('dirname', '');
@@ -87,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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+noname/calculateErrors.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,40 @@
+% [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
+function e = calculateErrors(schemeFactory, T, m, N, errorFun, timeOpt)
+    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');
+    assertNumberOfArguments(errorFun, 2);
+    default_arg('timeOpt');
+
+    e = [];
+    for i = 1:length(m)
+        done = timeTask('m = %3d ', m(i));
+
+        [discr, trueSolution] = schemeFactory(m(i));
+
+        timeOpt.k = T/N(i);
+        ts = discr.getTimestepper(timeOpt);
+        ts.stepTo(N(i), true);
+        approxSolution = discr.getTimeSnapshot(ts);
+
+        e(i) = errorFun(trueSolution, approxSolution);
+
+        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));
--- a/+parametrization/Ti.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+parametrization/Ti.m	Fri Nov 10 14:22:56 2017 +0100
@@ -21,16 +21,29 @@
             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,:));
+                    -((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,:));
+                    -((1-u).*(1-v).*A(2,:) + u.*(1-v).*B(2,:) + u.*v.*C(2,:) + (1-u).*v.*D(2,:));
 
-                o = [o1;o2];
+                if ~flipped
+                    o = [o1;o2];
+                else
+                    o = [o1'; o2'];
+                end
             end
 
             obj.S = @S_fun;
@@ -182,6 +195,15 @@
             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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/Ti3D.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+parametrization/TiTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- a/+sbp/D1Gauss.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+sbp/D1Gauss.m	Fri Nov 10 14:22:56 2017 +0100
@@ -37,5 +37,9 @@
 
             obj.borrowing = [];
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
     end
 end
--- a/+sbp/D2BlockNorm.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+sbp/D2BlockNorm.m	Fri Nov 10 14:22:56 2017 +0100
@@ -50,6 +50,10 @@
             obj.m = m;
 
         end
+
+        function str = string(obj)
+            str = [class(obj) '_' num2str(obj.order)];
+        end
     end
 
 
--- a/+sbp/D4Compatible.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+sbp/D4Compatible.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
 
 
--- a/+sbp/D4Standard.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+sbp/D4Standard.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
 
 
--- a/+scheme/Beam.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+scheme/Beam.m	Fri Nov 10 14:22:56 2017 +0100
@@ -90,6 +90,9 @@
             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;
@@ -123,6 +126,44 @@
                     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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/LaplaceCurvilinear.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- a/+scheme/Scheme.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+scheme/Scheme.m	Fri Nov 10 14:22:56 2017 +0100
@@ -25,9 +25,12 @@
         %       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)
+        [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
--- a/+scheme/Schrodinger1dCurve.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+scheme/Schrodinger1dCurve.m	Fri Nov 10 14:22:56 2017 +0100
@@ -122,14 +122,7 @@
                     tau1 = @(t) s * 1i*obj.Ji(p,p)*d;
                     tau2 = @(t) (1*s*obj.a(p,p))/2*e;
                     closure = @(t)obj.Hi*sqrt(obj.Ji)*(tau1(t)*e' + tau2(obj.a)*e')*sqrt(obj.Ji);
-                    
-                    switch class(data)
-                        case 'double'
-                            penalty = @(t) -obj.Hi*sqrt(obj.Ji)*(tau1*data+tau2(obj.a)*data)*sqrt(obj.Ji);
-
-                        otherwise
-                            error('Weird data argument!')
-                    end               
+                    penalty = @(t) -obj.Hi*sqrt(obj.Ji)*(tau1(t)*e' + tau2(obj.a)*e')*sqrt(obj.Ji);                    
                     % Unknown, boundary condition
                 otherwise
                     error('No such boundary condition: type = %s',type);
--- a/+scheme/Schrodinger2dCurve.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+scheme/Schrodinger2dCurve.m	Fri Nov 10 14:22:56 2017 +0100
@@ -38,6 +38,7 @@
         m_tot, m_u, m_v
         p
         Ji, J
+        Hamiltonian
     end
 
     methods
@@ -67,7 +68,7 @@
 
             obj.D1_u = ops_u.D1;
             obj.D2_u = ops_u.D2;
-            
+
             H_u =  ops_u.H;
             Hi_u = ops_u.HI;
             e_l_u = ops_u.e_l;
@@ -115,10 +116,11 @@
             obj.h = [h_u h_v];
             obj.order = order;
             obj.D = @(t)obj.d_fun(t);
+            obj.Hamiltonian = @(t)obj.h_fun(t);
             obj.variable_update(0);
         end
         
-        function [D] = d_fun(obj,t)
+        function [D,n] = d_fun(obj,t)
             %         obj.update_vairables(t); In driscretization?
             %  D = obj.Ji*(-1/2*(obj.b1*obj.Du-obj.b1_u+obj.Du*obj.b1) -
             %  1/2*(obj.b2*obj.Dv - obj.b2_v +obj.Dv*obj.b2) +
@@ -128,6 +130,9 @@
             D = sqrt(obj.Ji)*(-1/2*(obj.b1*obj.Du + obj.Du*obj.b1) - 1/2*(obj.b2*obj.Dv + obj.Dv*obj.b2) + 1i*obj.c^2*(obj.DUU + obj.DUV + obj.DVU + obj.DVV))*sqrt(obj.Ji); 
         end
         
+         function [Hamiltonian] = h_fun(obj,t)
+              Hamiltonian =  -sqrt(obj.Ji)*(obj.c^2*(obj.DUU + obj.DUV + obj.DVU + obj.DVV))*sqrt(obj.Ji);
+         end    
         
         function [D ]= variable_update(obj,t)
             % Metric derivatives
@@ -204,7 +209,7 @@
         %       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,~)
+        function [closure, penalty,closureHamiltonian,penaltyHamiltonian] = boundary_condition(obj, boundary,~)
                     [e, d_n, d_t, coeff_t, coeff_n s, halfnorm_inv_n, halfnorm_inv_t, halfnorm_t,g] = obj.get_boundary_ops(boundary);
                  
                     a_t =  @(t) spdiag(coeff_t(t));
@@ -221,6 +226,9 @@
 
                     closure = @(t)  sqrt(obj.Ji)*(obj.c^2 * penalty_parameter_1(t)*e' +  penalty_parameter_2(t)*e')*sqrt(obj.Ji);
                     penalty = @(t) -sqrt(obj.Ji)*(obj.c^2 * penalty_parameter_1(t)*e' +  penalty_parameter_2(t)*e')*sqrt(obj.Ji);
+                    
+                    closureHamiltonian = @(t)  1i*sqrt(obj.Ji)*(obj.c^2 * penalty_parameter_1(t)*e')*sqrt(obj.Ji);
+                    penaltyHamiltonian = @(t) -1i*sqrt(obj.Ji)*(obj.c^2 * penalty_parameter_1(t)*e')*sqrt(obj.Ji);
                 
         end
         
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/TODO.txt	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,1 @@
+% TODO: Rename package and abstract class to diffOp
--- a/+scheme/Wave2dCurve.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+scheme/Wave2dCurve.m	Fri Nov 10 14:22:56 2017 +0100
@@ -27,6 +27,8 @@
         gamm_u, gamm_v
         lambda
 
+        Dx, Dy % Physical derivatives
+
         x_u
         x_v
         y_u
@@ -38,6 +40,8 @@
             default_arg('opSet',@sbp.D2Variable);
             default_arg('c', 1);
 
+            warning('Use LaplaceCruveilinear instead')
+
             assert(isa(g, 'grid.Curvilinear'))
 
             m = g.size();
@@ -153,6 +157,9 @@
             obj.D = obj.Ji*c^2*(Duu + Duv + Dvu + Dvv);
             obj.lambda = lambda;
 
+            obj.Dx = spdiag( y_v./J)*Du + spdiag(-y_u./J)*Dv;
+            obj.Dy = spdiag(-x_v./J)*Du + spdiag( x_u./J)*Dv;
+
             obj.gamm_u = h_u*ops_u.borrowing.M.d1;
             obj.gamm_v = h_v*ops_v.borrowing.M.d1;
         end
@@ -225,6 +232,7 @@
 
                     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;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/bcSetup.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,48 @@
+% 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 with time and space coordinates as a parameters, for example f(t,x,y) for a 2D problem
+% Also takes S_sign which modifies the sign of S, [-1,1]
+% Returns a closure matrix and a forcing function S
+function [closure, S] = bcSetup(diffOp, bc, S_sign)
+    default_arg('S_sign', 1);
+    assertType(bc, 'cell');
+    assert(S_sign == 1 || S_sign == -1, 'S_sign must be either 1 or -1');
+
+
+    closure = spzeros(size(diffOp));
+    penalties = {};
+    dataFunctions = {};
+    dataParams = {};
+
+    for i = 1:length(bc)
+        assertType(bc{i}, 'struct');
+        [localClosure, penalty] = diffOp.boundary_condition(bc{i}.boundary, bc{i}.type);
+        closure = closure + localClosure;
+
+        if isempty(bc{i}.data)
+            continue
+        end
+        assertType(bc{i}.data, 'function_handle');
+
+        coord = diffOp.grid.getBoundary(bc{i}.boundary);
+        assertNumberOfArguments(bc{i}.data, 1+size(coord,2));
+
+        penalties{end+1} = penalty;
+        dataFunctions{end+1} = bc{i}.data;
+        dataParams{end+1} = num2cell(coord ,1);
+    end
+
+    O = spzeros(size(diffOp),1);
+    function v = S_fun(t)
+        v = O;
+        for i = 1:length(dataFunctions)
+            v = v + penalties{i}*dataFunctions{i}(t, dataParams{i}{:});
+        end
+
+        v = S_sign * v;
+    end
+    S = @S_fun;
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/+expint/Arnoldi.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,37 @@
+function y = Arnoldi(A,v,t,tol,m)
+
+n = size (v,1);
+V = zeros(n  ,m+1);
+H = zeros(m+1,m);
+
+beta = norm(v);
+V(:,1) = v/beta;
+resnorm = inf;
+
+j=0;
+
+while resnorm > tol
+    j = j+1;
+    z = A*V(:,j);
+    for i=1:j
+        H(i,j) = z'*V(:,i);
+        z  = z - H(i,j)*V(:,i);
+    end
+    H(j+1,j) = norm(z);
+    e1 = zeros(j,1); e1(1) = 1;
+    ej = zeros(j,1); ej(j) = 1;
+    s  = [0.01, 1/3, 2/3, 1]*t;
+    for q=1:length(s)
+        u         = expm(-s(q)*H(1:j,1:j))*e1;
+        beta_j(q) = -H(j+1,j)* (ej'*u);
+    end
+    resnorm = norm(beta_j,'inf');
+    fprintf('j = %d, resnorm = %.2e\n',j,resnorm);
+    if resnorm<=toler
+       break
+    elseif j==m
+       disp('warning: no convergence within m steps');
+    end
+    V(:,j+1) = z/H(j+1,j);
+end
+y = V(:,1:j)*(beta*u);
--- a/+time/+expint/Magnus_mp.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+time/+expint/Magnus_mp.m	Fri Nov 10 14:22:56 2017 +0100
@@ -13,7 +13,7 @@
     case 'expm'
         v = expm(k*Omega)*v;
     case 'Arnoldi'
-        v = time.expint.expm_Arnoldi(-Omega,v,k,tol,100);
+        v = time.expint.expm_Arnoldi(-Omega,v,k,tol,1000);
     otherwise
         error('No such matrix exponential evaluation')
         
--- a/+time/+expint/Magnus_mp.m~	Thu Oct 05 18:04:23 2017 +0200
+++ b/+time/+expint/Magnus_mp.m~	Fri Nov 10 14:22:56 2017 +0100
@@ -4,14 +4,18 @@
 function v = Magnus_mp(v,D, t , k,matrixexp,tol)
 
 if isa(D,'function_handle')
- switch matrixexp
-     case 'expm'
-        v = expm(k*D(t +k/2))*v;
-     case 'Arnol'
-    v = time.expint.expm_Arnoldi(-D(t +k/2),v,k,toler,100);
+    Omega = D(t +k/2);
 else
-   %v = krylov(k*D,v);
-   % v = expm(k*D)*v;
+    Omega = D;
 end
 
+switch matrixexp
+    case 'expm'
+        v = expm(k*Omega)*v;
+    case 'Arnoldi'
+        [v, i] = time.expint.expm_Arnoldi(-Omega,v,k,tol,1000);
+    otherwise
+        error('No such matrix exponential evaluation')
+        
+end
 end
\ No newline at end of file
--- a/+time/+expint/expm_Arnoldi.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+time/+expint/expm_Arnoldi.m	Fri Nov 10 14:22:56 2017 +0100
@@ -1,5 +1,7 @@
 function y = expm_Arnoldi(A,v,t,toler,m)
-%
+
+global iter 
+
 % y = expm_Arnoldi(A,v,t,toler,m)
 %
 % computes $y = \exp(-t A) v$
@@ -26,8 +28,11 @@
 resnorm = inf;
 
 j=0;
+iter = 0;
+
 
 while resnorm > toler
+    iter = iter +1;
     j = j+1;
     w = A*V(:,j);
     for i=1:j
--- a/+time/CdiffImplicit.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+time/CdiffImplicit.m	Fri Nov 10 14:22:56 2017 +0100
@@ -63,7 +63,9 @@
 
             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 = (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.')
--- a/+time/Rungekutta4SecondOrder.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+time/Rungekutta4SecondOrder.m	Fri Nov 10 14:22:56 2017 +0100
@@ -15,7 +15,19 @@
 
 
     methods
-        % Solves u_tt = Du + Eu_t + S
+        % 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)
@@ -41,23 +53,15 @@
                     S = @(t)S;
                 end
 
-                I = speye(obj.m);
-                O = sparse(obj.m,obj.m);
-
-                obj.M = @(t)[
-                       O,    I;
-                    D(t), E(t);
-                ];
-                obj.C = @(t)[
-                    zeros(obj.m,1);
-                              S(t);
-                ];
-
                 obj.k = k;
                 obj.t = t0;
                 obj.w = [v0; v0t];
 
-                obj.F = @(w,t)(obj.M(t)*w + obj.C(t));
+                % 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
 
                 default_arg('D', sparse(obj.m, obj.m));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/SBPInTimeImplicitFormulation.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/SBPInTimeSecondOrderFormImplicit.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,80 @@
+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, TYPE, order, blockSize)
+            default_arg('f', []);
+            default_arg('TYPE', []);
+            default_arg('order', []);
+            default_arg('blockSize',[]);
+
+            m = length(v0);
+
+            default_arg('A', sparse(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;
+
+            obj.firstOrderTimeStepper = time.SBPInTimeImplicitFormulation(obj.AA, obj.BB, obj.ff, obj.k, obj.t, w0, TYPE, order, blockSize);
+        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
--- a/+time/Timestepper.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/+time/Timestepper.m	Fri Nov 10 14:22:56 2017 +0100
@@ -62,6 +62,7 @@
 
 
         function [v, t] = stepTo(obj, n, progress_bar)
+            assertScalar(n);
             default_arg('progress_bar',false);
 
             [v, t] = obj.stepN(n-obj.n, progress_bar);
--- a/Cell.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/Cell.m	Fri Nov 10 14:22:56 2017 +0100
@@ -23,6 +23,10 @@
             s = size(A.data);
         end
 
+        function b = isempty(A)
+            b = prod(size(A)) == 0;
+        end
+
         function l = length(A)
             l = length(A.data);
         end
--- a/CellTest.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/CellTest.m	Fri Nov 10 14:22:56 2017 +0100
@@ -36,6 +36,21 @@
     end
 end
 
+function testIsEmpty(testCase)
+    cases = {
+        {cell(0,0), true},
+        {cell(1,0), true},
+        {cell(0,1), true},
+        {cell(1,1), false},
+    };
+
+    for i = 1:length(cases)
+        A = Cell(cases{i}{1});
+        expected = cases{i}{2};
+        testCase.verifyEqual(isempty(A),expected);
+    end
+end
+
 function testTranspose(testCase)
     testCase.verifyEqual(Cell({1i, 2}).', Cell({1i; 2}));
     testCase.verifyEqual(Cell({1i; 2}).', Cell({1i, 2}));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertNumberOfArguments.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertScalar.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/assertSymbolic.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,3 @@
+function assertSymbolic(s)
+    assert(logical(simplify(s)));
+end
--- a/assertType.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/assertType.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/four.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fourInv.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,4 @@
+function u = ifour(u_hat)
+    u_hat = ifftshift(u_hat);
+    u = ifft(u_hat);
+end
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gaussian.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,3 @@
+function z = gaussian(x,x0,d)
+    z = exp(-norm(x-x0).^2/d^2);
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/isAnyOf.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sbplibLocation.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,4 @@
+function location = sbplibLocation()
+    scriptname  = mfilename('fullpath');
+    [location, ~, ~] = fileparts(scriptname);
+end
--- a/sbplibVersion.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/sbplibVersion.m	Fri Nov 10 14:22:56 2017 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/skewPart.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,4 @@
+% Returns the skew of A
+function S = skewPart(A, tol)
+    S = 1/2*(A - A');
+end
--- a/spdiag.m	Thu Oct 05 18:04:23 2017 +0200
+++ b/spdiag.m	Fri Nov 10 14:22:56 2017 +0100
@@ -1,5 +1,10 @@
 function A = spdiag(a,i)
     default_arg('i',0);
+
+    if isrow(a)
+        a = a';
+    end
+
     n = length(a)-abs(i);
     A = spdiags(a,i,n,n);
 end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/symmetricPart.m	Fri Nov 10 14:22:56 2017 +0100
@@ -0,0 +1,4 @@
+% Returns the symmetric of A
+function S = symmetricPart(A, tol)
+    S = 1/2*(A + A');
+end