changeset 713:348d5bcf7daf feature/quantumTriangles

Merge with feature/frids
author Ylva Rydin <ylva.rydin@telia.com>
date Tue, 20 Feb 2018 15:00:30 +0100
parents c9147e05d228 (diff) facb8ffb5c34 (current diff)
children
files
diffstat 19 files changed, 1114 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+multiblock/DiffOpTimeDep.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,212 @@
+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{1,1}(0));
+                    %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*sparse(n,m);
+                            penalty{j,i} = @(t)0*sparse(n,1);
+                        end
+                    end
+                    
+                    
+                    for i = 1:length(boundary)
+                        boundaryPart = boundary{i};
+                        block = boundaryPart{1};
+                        [closurePart, penaltyPart] = obj.boundary_condition(boundaryPart, type);
+                        closure{block,block} = @(t)closure{block,block}(t) + closurePart(t);
+                        penalty{block,block} = @(t)penalty{block,block}(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
--- a/+multiblock/stitchSchemes.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+multiblock/stitchSchemes.m	Tue Feb 20 15:00:30 2018 +0100
@@ -11,9 +11,9 @@
 % Output parameters are cell arrays and cell matrices.
 %
 % Ex: [schms, D, H] = stitchSchemes(schmHand, order, schmParam, blocks, ms, conn, bound)
-function [schms, D, H] = stitchSchemes(schmHand, order, schmParam, grids, conn, bound)
+function [schms, D, H,penalty,J] = stitchSchemes(schmHand, order, schmParam, grids, conn, bound,timeDep)
     default_arg('schmParam',[]);
-
+    default_arg('timeDep','N');
     n_blocks = numel(grids);
 
     % Creating Schemes
@@ -49,44 +49,84 @@
     end
 
     %% Total system matrix
-
+    
     % Differentiation terms
     D = cell(n_blocks,n_blocks);
+    penalty = cell(n_blocks,n_blocks);
+    
+    
     for i = 1:n_blocks
+        penalty{i,i}= @(t)0;
         D{i,i} = schms{i}.D;
     end
-
+    
     % Boundary penalty terms
-    for i = 1:n_blocks
-        if ~isstruct(bound{i})
-            continue
-        end
-
-        fn = fieldnames(bound{i});
-        for j = 1:length(fn);
-            bc = bound{i}.(fn{j});
-            if isempty(bc)
-                continue
+    switch timeDep
+        case {'n','no','N','No'}
+            for i = 1:n_blocks
+                if ~isstruct(bound{i})
+                    continue
+                end
+                
+                fn = fieldnames(bound{i});
+                for j = 1:length(fn)
+                    bc = bound{i}.(fn{j});
+                    if isempty(bc)
+                        continue
+                    end
+                    
+                    [closure, ~] = schms{i}.boundary_condition(fn{j},bc{:});
+                    D{i,i} = D{i,i}+closure;
+                end
+            end
+            
+            % Interface penalty terms
+            for i = 1:n_blocks
+                for j = 1:n_blocks
+                    intf = conn{i,j};
+                    if isempty(intf)
+                        continue
+                    end
+                    
+                    [uu,uv,vv,vu] = schms{i}.interface_coupling(schms{i},intf{1},schms{j},intf{2});
+                    D{i,i} = D{i,i} + uu;
+                    D{i,j} = uv;
+                    D{j,j} = D{j,j} + vv;
+                    D{j,i} = vu;
+                end
             end
-
-            [closure, ~] = schms{i}.boundary_condition(fn{j},bc{:});
-            D{i,i} = D{i,i}+closure;
-        end
-    end
-
-    % Interface penalty terms
-    for i = 1:n_blocks
-        for j = 1:n_blocks
-            intf = conn{i,j};
-            if isempty(intf)
-                continue
+        case {'y','yes','Y','Yes'}
+            for i = 1:n_blocks
+                if ~isstruct(bound{i})
+                    continue
+                end
+                
+                fn = fieldnames(bound{i});
+                for j = 1:length(fn)
+                    bc = bound{i}.(fn{j});
+                    if isempty(bc)
+                        continue
+                    end
+                    
+                    [closure, penaltyi] = schms{i}.boundary_condition(fn{j},bc{:});
+                    D{i,i} =@(t) D{i,i}(t) + closure(t);
+                    penalty{i,i} = @(t)  penalty{i,i}(t) + penaltyi(t);
+                end
             end
-
-            [uu,uv,vv,vu] = schms{i}.interface_coupling(schms{i},intf{1},schms{j},intf{2});
-            D{i,i} = D{i,i} + uu;
-            D{i,j} = uv;
-            D{j,j} = D{j,j} + vv;
-            D{j,i} = vu;
-        end
-    end
-end
\ No newline at end of file
+            
+            % Interface penalty terms
+            for i = 1:n_blocks
+                for j = 1:n_blocks
+                    intf = conn{i,j};
+                    if isempty(intf)
+                        continue
+                    end
+                    
+                    [uu,uv,vv,vu] = schms{i}.interface_coupling(schms{i},intf{1},schms{j},intf{2});
+                    D{i,i} = @(t) D{i,i}(t) + uu(t);
+                    D{i,j} = uv;
+                    D{j,j} = @(t)D{j,j}(t) + vv(t);
+                    D{j,i} = vu;
+                end
+            end
+    end
\ No newline at end of file
--- a/+noname/animate.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+noname/animate.m	Tue Feb 20 15:00:30 2018 +0100
@@ -84,7 +84,7 @@
 
 
     if ~do_step
-        pause
+  %      pause
         anim.animate(@G, Tstart, Tend, time_modifier);
     else
         pause
--- a/+sbp/D1Upwind.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+sbp/D1Upwind.m	Tue Feb 20 15:00:30 2018 +0100
@@ -53,7 +53,7 @@
         	obj.borrowing = [];
 
         end
-
+        
         function str = string(obj)
             str = [class(obj) '_' num2str(obj.order)];
         end
--- a/+sbp/D2Standard.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+sbp/D2Standard.m	Tue Feb 20 15:00:30 2018 +0100
@@ -14,7 +14,6 @@
         h % Step size
         x % grid
         borrowing % Struct with borrowing limits for different norm matrices
-
     end
 
     methods
@@ -68,6 +67,5 @@
         function str = string(obj)
             str = [class(obj) '_' num2str(obj.order)];
         end
-
     end
 end
--- a/+scheme/Hypsyst3d.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+scheme/Hypsyst3d.m	Tue Feb 20 15:00:30 2018 +0100
@@ -7,6 +7,7 @@
         X, Y, Z% Values of x and y for each grid point
         Yx, Zx, Xy, Zy, Xz, Yz %Grid values for boundary surfaces
         order % Order accuracy for the approximation
+        grid
         
         D % non-stabalized scheme operator
         A, B, C, E % Symbolic coefficient matrices
--- a/+scheme/Hypsyst3dCurve.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+scheme/Hypsyst3dCurve.m	Tue Feb 20 15:00:30 2018 +0100
@@ -28,6 +28,7 @@
         I_xi,I_eta,I_zeta, I_N,onesN
         e_w, e_e, e_s, e_n, e_b, e_t
         index_w, index_e,index_s,index_n, index_b, index_t
+        grid
         params %parameters for the coeficient matrice
     end
     
@@ -215,6 +216,8 @@
             obj.Hxii = kr(I_n, ops_xi.HI, I_eta,I_zeta);
             obj.Hetai = kr(I_n, I_xi, ops_eta.HI,I_zeta);
             obj.Hzetai = kr(I_n, I_xi,I_eta, ops_zeta.HI);
+            Hi = obj.Hxii*obj.Hetai*obj.Hzetai;
+            obj.H = inv(Hi);
             
             obj.index_w = (kr(ops_xi.e_l, O_eta,O_zeta)==1);
             obj.index_e = (kr(ops_xi.e_r, O_eta,O_zeta)==1);
--- a/+scheme/Schrodinger.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+scheme/Schrodinger.m	Tue Feb 20 15:00:30 2018 +0100
@@ -4,7 +4,8 @@
         h % Grid spacing
         x % Grid
         order % Order accuracy for the approximation
-
+        grid
+        
         D % non-stabalized scheme operator
         H % Discrete norm
         M % Derivative norm
@@ -21,27 +22,29 @@
 
     methods
         % Solving SE in the form u_t = i*u_xx -i*V;
-        function obj = Schrodinger(m,xlim,order,V)
+        function obj = Schrodinger(g,order,V)
             default_arg('V',0);
-
-            [x, h] = util.get_grid(xlim{:},m);
-
-            ops = sbp.Ordinary(m,h,order);
-
-            obj.D2 = sparse(ops.derivatives.D2);
-            obj.H =  sparse(ops.norms.H);
-            obj.Hi = sparse(ops.norms.HI);
-            obj.M =  sparse(ops.norms.M);
-            obj.e_l = sparse(ops.boundary.e_1);
-            obj.e_r = sparse(ops.boundary.e_m);
-            obj.d1_l = sparse(ops.boundary.S_1);
-            obj.d1_r = sparse(ops.boundary.S_m);
+            obj.grid = g;
+            m = N(obj.grid);
+            obj.x =  points(obj.grid);
+            ops = sbp.D2Standard(m,{obj.x(1) obj.x(end)},order);
+            
+           
+            obj.h = ops.h;
+            obj.D2 = ops.D2;
+            obj.H =  ops.H;
+            obj.Hi = ops.HI;
+            obj.M =  ops.M;
+            obj.e_l = ops.e_l;
+            obj.e_r = ops.e_r;
+            obj.d1_l = ops.d1_l;
+            obj.d1_r = ops.d1_r;
 
 
             if isa(V,'function_handle')
-                V_vec = V(x);
+                V_vec = V(obj.x);
             else
-                V_vec = x*0 + V;
+                V_vec = obj.x*0 + V;
             end
 
             V_mat = spdiags(V_vec,0,m,m);
@@ -49,10 +52,7 @@
             obj.D = 1i * obj.D2 - 1i * V_mat;
 
             obj.m = m;
-            obj.h = h;
             obj.order = order;
-
-            obj.x = x;
         end
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/Schrodinger1dCurve.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,183 @@
+classdef Schrodinger1dCurve < scheme.Scheme
+    properties
+        m % Number of points in each direction, possibly a vector
+        h % Grid spacing
+        xi % Grid
+        order % Order accuracy for the approximation
+        grid
+        
+        D % non-stabalized scheme operator
+        H % Discrete norm
+        M % Derivative norm
+        alpha
+        x_r
+        x_l
+        ddt_x_r
+        ddt_x_l
+        a
+        a_xi
+        Ji
+        J
+        t_up
+        x
+        
+        V_mat
+        D1
+        D2
+        Hi
+        e_l
+        e_r
+        d1_l
+        d1_r
+        gamm
+    end
+    
+    methods
+        % Solving SE in the form u_t = i*u_xx +i*V on deforming 1D domain;
+        function obj = Schrodinger1dCurve(g,order,boundaries,V,constJi)
+            default_arg('V',0);
+            default_arg('constJi',false)
+            xilim={0 1};
+            m = N(g);
+            if constJi
+                ops = sbp.D2Standard(m,xilim,order);
+            else
+                ops = sbp.D4Variable(m,xilim,order);
+            end
+            
+            obj.x_l = boundaries{1};
+            obj.x_r = boundaries{2};
+            obj.ddt_x_l = boundaries{3};
+            obj.ddt_x_r = boundaries{4};
+            
+            obj.xi=ops.x;
+            obj.h=ops.h;
+            obj.D2 = ops.D2;
+            obj.D1 = ops.D1;
+            obj.H =  ops.H;
+            obj.Hi = ops.HI;
+            obj.M =  ops.M;
+            obj.e_l = ops.e_l;
+            obj.e_r = ops.e_r;
+            obj.d1_l = ops.d1_l;
+            obj.d1_r = ops.d1_r;
+            obj.grid = g;
+            
+            if isa(V,'function_handle')
+                V_vec = V(obj.x);
+            else
+                V_vec = obj.xi*0 + V;
+            end
+            
+            obj.V_mat = spdiags(V_vec,0,m,m);
+            obj.D = @(t) obj.d_fun(t);
+            obj.m = m;
+            obj.order = order;
+        end
+        
+        
+        % Closure functions return the opertors appliedo 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 [D] = d_fun(obj,t)
+            obj.variable_update(t); % In driscretization?
+             D = sqrt(obj.Ji)*(-0.5*(obj.D1*obj.a + obj.a*obj.D1) + 1i*obj.D2(diag(obj.Ji)) + 1i*obj.V_mat)*sqrt(obj.Ji);
+%             D = (-0.5*(obj.D1*obj.a -obj.a_xi+ obj.a*obj.D1) + 1i*obj.D2(diag(obj.Ji)) + 1i*obj.V_mat);
+          %   D= obj.Ji*(-sqrt(obj.a)*obj.D1*sqrt(obj.a) + 0.5*obj.a_xi + 1i*obj.D2(diag(obj.Ji)) + 1i*obj.V_mat);
+        end
+        
+        
+        function [] = variable_update(obj,t)
+            if (t == obj.t_up)
+                return
+            else
+                x_r = obj.x_r(t);
+                x_l = obj.x_l(t);
+                ddt_x_r = obj. ddt_x_r(t);
+                ddt_x_l = obj.ddt_x_l(t);
+                obj.x = obj.xi*(x_r -x_l) + x_l;
+                obj.a = sparse(diag((-ddt_x_l*( x_r - x_l) - (obj.x-x_l)*(ddt_x_r-ddt_x_l))/(x_r-x_l)));            
+                
+                obj.Ji = sparse(diag(1./(x_r - x_l + 0*obj.x)));
+                obj.J = sparse(x_r -x_l);
+                obj.a_xi = sparse(diag(-1*(ddt_x_r - ddt_x_l + 0*obj.x)));
+                obj.t_up = t;
+            end
+        end
+        
+        function [closure, penalty] = boundary_condition(obj,boundary,type,data)
+            default_arg('type','dirichlet');
+            default_arg('data',0);
+            
+            [e,d,s,p] = obj.get_boundary_ops(boundary);
+            
+            switch type
+                % Dirichlet boundary condition
+                case {'D','d','dirichlet'}
+                    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);
+                    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);
+            end
+        end
+        
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            [e_u,d_u,s_u,p_u] = obj.get_boundary_ops(boundary);
+            [e_v,d_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary);
+            
+            a1 =   s_u* 1/2 * 1i ;
+            b1 =   -s_u* 1/2 * 1i;
+            gamma = @(a) s_u*a(p_u,p_u)/2*e_u;
+            
+            tau = @(t) a1*obj.Ji(p_u,p_u)^2*d_u;
+            sig = b1*e_u;
+            
+            closure = @(t) obj.Hi * (tau(t)*e_u' + sig*obj.Ji(p_u,p_u)^2*d_u' + obj.Ji(p_u,p_u)*gamma(obj.a)*e_u');
+            penalty = @(t) obj.Hi * (-tau(t)*e_v' - sig*obj.Ji(p_u,p_u)^2*d_v' - obj.Ji(p_u,p_u)*gamma(obj.a)*e_v');
+        end
+        
+        % Ruturns the boundary ops and sign for the boundary specified by the string boundary.
+        % The right boundary is considered the positive boundary
+        function [e,d,s,p] = get_boundary_ops(obj,boundary)
+            switch boundary
+                case 'l'
+                    e = obj.e_l;
+                    d = obj.d1_l;
+                    s = -1;
+                    p=1;
+                case 'r'
+                    e = obj.e_r;
+                    d = obj.d1_r;
+                    s = 1;
+                    p=obj.m;
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+        end
+        
+        function N = size(obj)
+            N = obj.m;
+        end
+        
+    end
+    
+    methods(Static)
+        % Calculates the matrcis need for the inteface coupling between boundary bound_u of scheme schm_u
+        % and bound_v of scheme schm_v.
+        %   [uu, uv, vv, vu] = inteface_couplong(A,'r',B,'l')
+        function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v)
+            [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v);
+            [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u);
+        end
+    end
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+scheme/Schrodinger2dCurve.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,345 @@
+classdef Schrodinger2dCurve < scheme.Scheme
+    properties
+        m % Number of points in each direction, possibly a vector
+        h % Grid spacing
+
+        grid
+        xm, ym
+
+        order % Order accuracy for the approximation
+
+        D % non-stabalized scheme operator
+        M % Derivative norm
+        H % Discrete norm
+        Hi
+        H_u, H_v % Norms in the x and y directions
+        Hu,Hv % Kroneckerd norms. 1'*Hx*v corresponds to integration in the x dir.
+        Hi_u, Hi_v
+        Hiu, Hiv
+        D1_v, D1_u
+        D2_v, D2_u
+        Du, Dv
+        x,y
+        b1, b2
+        b1_u,b2_v
+        DU, DV, DUU, DUV, DVU, DVV 
+        
+        e_w, e_e, e_s, e_n
+        du_w, dv_w
+        du_e, dv_e
+        du_s, dv_s
+        du_n, dv_n
+        g_1, g_2
+        c
+        ind
+        t_up
+        
+        a11, a12, a22
+        m_tot, m_u, m_v
+        p
+        Ji, J
+        Hamiltonian
+    end
+
+    methods
+        function obj = Schrodinger2dCurve(g ,order, opSet,p)
+            default_arg('opSet',@sbp.D2Variable);
+            default_arg('c', 1);
+
+            obj.p=p;
+            obj.c=1;
+            
+            m = g.size();
+            obj.m_u = m(1);
+            obj.m_v = m(2);
+            obj.m_tot = g.N();
+            obj.grid=g;
+            
+            h = g.scaling();
+            h_u = h(1);
+            h_v = h(2);
+
+            % Operators
+            ops_u = opSet(obj.m_u, {0, 1}, order);
+            ops_v = opSet(obj.m_v, {0, 1}, order);
+
+            I_u = speye(obj.m_u);
+            I_v = speye(obj.m_v);
+
+            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;
+            e_r_u = ops_u.e_r;
+            d1_l_u = ops_u.d1_l;
+            d1_r_u = ops_u.d1_r;
+
+            obj.D1_v = ops_v.D1;
+            obj.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;
+
+            obj.Du = kr(obj.D1_u,I_v);
+            obj.Dv = kr(I_u,obj.D1_v);
+            
+            obj.H = kr(H_u,H_v);
+            obj.Hi = kr(Hi_u,Hi_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);
+            
+            obj.e_w  = kr(e_l_u,I_v);
+            obj.e_e  = kr(e_r_u,I_v);
+            obj.e_s  = kr(I_u,e_l_v);
+            obj.e_n  = kr(I_u,e_r_v);
+            obj.du_w = kr(d1_l_u,I_v);
+            obj.dv_w = (obj.e_w'*obj.Dv)';
+            obj.du_e = kr(d1_r_u,I_v);   
+            obj.dv_e = (obj.e_e'*obj.Dv)';
+            obj.du_s = (obj.e_s'*obj.Du)';
+            obj.dv_s = kr(I_u,d1_l_v);
+            obj.du_n = (obj.e_n'*obj.Du)';
+            obj.dv_n = kr(I_u,d1_r_v);
+            
+            obj.DUU = sparse(obj.m_tot);
+            obj.DVV = sparse(obj.m_tot);
+            obj.ind = grid.funcToMatrix(obj.grid, 1:obj.m_tot);
+            
+            obj.m = m;
+            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,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) +
+            %  1i*obj.c^2*(obj.DUU + obj.DUV + obj.DVU + obj.DVV)); (ols
+            %  not skew sym disc
+            
+            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
+            if(obj.t_up == t)
+                return
+            else
+                ti = parametrization.Ti.points(obj.p{1}(t),obj.p{2}(t),obj.p{3}(t),obj.p{4}(t));
+                ti_tau = parametrization.Ti.points(obj.p{5}(t),obj.p{6}(t),obj.p{7}(t),obj.p{8}(t));
+                lcoords=points(obj.grid);
+                [obj.xm,obj.ym]= ti.map(lcoords(1:obj.m_v:end,1),lcoords(1:obj.m_v,2));
+                [x_tau,y_tau]= ti_tau.map(lcoords(1:obj.m_v:end,1),lcoords(1:obj.m_v,2));
+                x = reshape(obj.xm,obj.m_tot,1);
+                y = reshape(obj.ym,obj.m_tot,1);
+                obj.x = x;
+                obj.y = y;
+                
+                x_tau = reshape(x_tau,obj.m_tot,1);
+                y_tau = reshape(y_tau,obj.m_tot,1);
+                
+                x_u = obj.Du*x;
+                x_v = obj.Dv*x;
+                y_u = obj.Du*y;
+                y_v = obj.Dv*y;
+                
+                J = (x_u.*y_v - x_v.*y_u);
+                obj.J = spdiags(J, 0, obj.m_tot, obj.m_tot);
+                
+                Ji = spdiags(1./J, 0, obj.m_tot, obj.m_tot);
+                obj.Ji = Ji;
+                
+                a11 =  Ji* (x_v.^2  + y_v.^2);
+                a12 = -Ji* (x_u.*x_v + y_u.*y_v);
+                a22 =  Ji* (x_u.^2  + y_u.^2);
+                
+                obj.a11 = a11;
+                obj.a12 = a12;
+                obj.a22 = a22;
+                
+                % Assemble full operators
+                L_12 = spdiags(a12, 0, obj.m_tot, obj.m_tot);
+                obj.DUV = obj.Du*L_12*obj.Dv;
+                obj.DVU = obj.Dv*L_12*obj.Du;
+                
+                
+                for i = 1:obj.m_v
+                    D = obj.D2_u(a11(obj.ind(:,i)));
+                    p = obj.ind(:,i);
+                    obj.DUU(p,p) = D;
+                end
+                
+                for i = 1:obj.m_u
+                    D = obj.D2_v(a22(obj.ind(i,:)));
+                    p = obj.ind(i,:);
+                    obj.DVV(p,p) = D;
+                end
+                
+                obj.g_1 = x_v.*y_tau-x_tau.*y_v;
+                obj.g_2 = x_tau.*y_u - y_tau.*x_u;
+                
+                obj.b1 = spdiags(obj.g_1, 0, obj.m_tot, obj.m_tot);
+                obj.b2 = spdiags(obj.g_2, 0, obj.m_tot, obj.m_tot);
+                
+                obj.b1_u = spdiags(obj.Du*obj.g_1, 0, obj.m_tot, obj.m_tot);
+                obj.b2_v = spdiags(obj.Dv*obj.g_2, 0, obj.m_tot, obj.m_tot);
+                obj.t_up=t;
+            end
+        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,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));
+                    a_n = @(t) spdiag(coeff_n(t));
+                    
+                    F = @(t)(s * a_n(t)*d_n' + s * a_t(t)  *d_t')';
+                    tau1  = 1;       
+                    a  = @(t)spdiag(g(t));
+                    tau2 = @(t) (1*s*a(t))/2;
+
+                    penalty_parameter_1 = @(t) 1*1i*halfnorm_inv_n*halfnorm_inv_t*F(t)*e'*halfnorm_t*e;
+                    penalty_parameter_2 = @(t) halfnorm_inv_n*e*tau2(t);
+
+                    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
+        
+        function [closure, penalty] = interface(obj,boundary,neighbour_scheme,neighbour_boundary)
+            % u denotes the solution in the own domain
+            % v denotes the solution in the neighbour domain
+            [e_u, d_n_u, d_t_u,  coeff_t_u, coeff_n_u,s_u, halfnorm_inv_u_n, halfnorm_inv_u_t, halfnorm_u_t,gamm_u,Ji_u] = obj.get_boundary_ops(boundary);
+            [e_v, d_n_v, d_t_v,  coeff_t_v, coeff_n_v s_v, halfnorm_inv_v_n, halfnorm_inv_v_t, halfnorm_v_t,gamm_v,Ji_v] = neighbour_scheme.get_boundary_ops(neighbour_boundary);
+
+            a_n_u = @(t) spdiag(coeff_n_u(t));
+            a_t_u = @(t) spdiag(coeff_t_u(t));
+            a_n_v = @(t) spdiag(coeff_n_v(t));
+            a_t_v = @(t) spdiag(coeff_t_v(t));
+           
+
+            F_u = @(t)(a_n_u(t)*d_n_u' + a_t_u(t)*d_t_u')';
+            F_v = @(t)(a_n_v(t)*d_n_v' + a_t_v(t)*d_t_v')';
+            
+            a = @(t)spdiag(gamm_u(t));
+       
+            tau =  s_u*1*1i/2;            
+            sig =  -s_u*1*1i/2;
+            gamm = @(t) (s_u*a(t))/2;
+            
+            penalty_parameter_1 = @(t) halfnorm_inv_u_n*(tau*halfnorm_inv_u_t*F_u(t)*e_u'*halfnorm_u_t*e_u);
+            penalty_parameter_2 = @(t) halfnorm_inv_u_n * e_u  * (sig );
+            penalty_parameter_3 = @(t) halfnorm_inv_u_n * e_u  * (gamm(t) );
+
+
+            closure =@(t) sqrt(Ji_u)*obj.c^2 * ( penalty_parameter_1(t)*e_u'...
+                        + penalty_parameter_2(t)*F_u(t)' + penalty_parameter_3(t)*e_u')*sqrt(Ji_u);
+            penalty =@(t) sqrt(Ji_u)*obj.c^2 * ( -penalty_parameter_1(t)*e_v'...
+                        - penalty_parameter_2(t)*F_v(t)' - penalty_parameter_3(t)*e_v')*sqrt(Ji_v);
+        end
+
+
+        function [e, d_n, d_t, coeff_t,coeff_n, s,  halfnorm_inv_n, halfnorm_inv_t, halfnorm_t,g,Ji] = 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_n = obj.du_w;
+                    d_t = obj.dv_w;
+                    s = -1;
+
+                    I = ind(1,:);
+                    coeff_t = @(t)obj.a12(I);
+                    coeff_n =@(t) obj.a11(I);
+                    g = @(t)obj.g_1(I);
+                case 'e'
+                    e = obj.e_e;
+                    d_n = obj.du_e;
+                    d_t = obj.dv_e;
+                    s = 1;
+
+                    I = ind(end,:);
+                    coeff_t = @(t)obj.a12(I);
+                    coeff_n = @(t)obj.a11(I);
+                    g = @(t)obj.g_1(I);
+                case 's'
+                    e = obj.e_s;
+                    d_n = obj.dv_s;
+                    d_t = obj.du_s;
+                    s = -1;
+
+                    I = ind(:,1)';
+                    coeff_t = @(t)obj.a12(I);
+                    coeff_n = @(t)obj.a22(I);
+                    g = @(t)obj.g_2(I);
+                case 'n'
+                    e = obj.e_n;
+                    d_n = obj.dv_n;
+                    d_t = obj.du_n;
+                    s = 1;
+
+                    I = ind(:,end)';
+                    coeff_t = @(t)obj.a12(I);
+                    coeff_n = @(t)obj.a22(I);
+                    g = @(t)obj.g_2(I);
+                otherwise
+                    error('No such boundary: boundary = %s',boundary);
+            end
+
+            switch boundary
+                case {'w','e'}
+                    halfnorm_inv_n = obj.Hiu;
+                    halfnorm_inv_t = obj.Hiv;
+                    halfnorm_t = obj.Hv;
+                   
+                case {'s','n'}
+                    halfnorm_inv_n = obj.Hiv;
+                    halfnorm_inv_t = obj.Hiu;
+                    halfnorm_t = obj.Hu;
+            end
+             Ji = obj.Ji;
+        end
+
+        function N = size(obj)
+            N = prod(obj.m);
+        end
+    end
+    methods(Static)
+        % Calculates the matrcis need for the inteface coupling between boundary bound_u of scheme schm_u
+        % and bound_v of scheme schm_v.
+        %   [uu, uv, vv, vu] = inteface_couplong(A,'r',B,'l')
+        function [uu, uv, vv, vu] = interface_coupling(schm_u,bound_u,schm_v,bound_v)
+            [uu,uv] = schm_u.interface(bound_u,schm_v,bound_v);
+            [vv,vu] = schm_v.interface(bound_v,schm_u,bound_u);
+        end
+    end
+end
\ No newline at end of file
--- a/+scheme/Utux.m	Tue Dec 19 17:07:07 2017 +0100
+++ b/+scheme/Utux.m	Tue Feb 20 15:00:30 2018 +0100
@@ -12,6 +12,7 @@
         Hi
         e_l
         e_r
+        grid
         v0
     end
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/+expint/Arnoldi.m	Tue Feb 20 15:00:30 2018 +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);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/+expint/Magnus_4.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,29 @@
+% Takes one time step of size k using a fourth order magnus integrator
+% starting from v_0 and where the function F(v,t) gives the
+% time derivatives.
+function v = Magnus_4(v, D, t , k , matrixexp ,tol)
+
+
+
+if isa(D,'function_handle')
+    c1 = 1/2 - sqrt(3)/6;
+    c2 = 1/2 + sqrt(3)/6;
+    
+    A1 = D(t +c1*k);
+    A2 = D(t + c2*k);
+    Omega = 1/2*(A1 + A2) + sqrt(3)*k/12*(A1*A2-A2*A1);
+else
+    Omega = D;
+end
+
+
+switch matrixexp
+    case 'expm'
+        v = expm(k*Omega)*v;
+    case 'Arnoldi'
+        v = time.expint.expm_Arnoldi(-Omega,v,k,tol,100);
+    otherwise
+        error('No such matrix exponential evaluation')
+        
+end
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/+expint/Magnus_mp.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,21 @@
+% Takes one time step of size k using the magnus midpoinr
+% starting from v_0 and where the function F(v,t) gives the
+% time derivatives.
+function v = Magnus_mp(v,D, t , k,matrixexp,tol)
+
+if isa(D,'function_handle')
+    Omega = D(t +k/2);
+else
+    Omega = D;
+end
+
+switch matrixexp
+    case 'expm'
+        v = expm(k*Omega)*v;
+    case 'Arnoldi'
+        v = time.expint.expm_Arnoldi(-Omega,v,k,tol,1000);
+    otherwise
+        error('No such matrix exponential evaluation')
+        
+end
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/+expint/Magnus_mp.m~	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,21 @@
+% Takes one time step of size k using the magnus midpoinr
+% starting from v_0 and where the function F(v,t) gives the
+% time derivatives.
+function v = Magnus_mp(v,D, t , k,matrixexp,tol)
+
+if isa(D,'function_handle')
+    Omega = D(t +k/2);
+else
+    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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/+expint/expm_Arnoldi.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,59 @@
+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$
+% input: A (n x n)-matrix, v n-vector, t>0 time interval,
+%        toler>0 tolerance, m maximal Krylov dimension
+%
+% Copyright (c) 2012 by M.A. Botchev
+% Permission to copy all or part of this work is granted,
+% provided that the copies are not made or distributed
+% for resale, and that the copyright notice and this
+% notice are retained.
+%
+% THIS WORK IS PROVIDED ON AN "AS IS" BASIS.  THE AUTHOR
+% PROVIDES NO WARRANTY WHATSOEVER, EITHER EXPRESSED OR IMPLIED,
+% REGARDING THE WORK, INCLUDING WARRANTIES WITH RESPECT TO ITS
+% MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE.
+%
+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;
+iter = 0;
+
+
+while resnorm > toler
+    iter = iter +1;
+    j = j+1;
+    w = A*V(:,j);
+    for i=1:j
+        H(i,j) = w'*V(:,i);
+	w      = w - H(i,j)*V(:,i);
+    end
+    H(j+1,j) = norm(w);
+    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) = w/H(j+1,j);
+end
+y = V(:,1:j)*(beta*u);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/Magnus4.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,49 @@
+classdef Magnus4 < time.Timestepper
+    properties
+        D
+        S
+        F
+        k
+        t
+        v
+        m
+        n
+        matrixexp
+        tol
+    end
+
+
+    methods
+        function obj = Magnus4(D, k, t0, v0,matrixexp,tol)
+            default_arg('matrixexp','expm')
+            default_arg('tol',1e-6)
+            obj.D = D;
+            obj.k = k;
+            obj.t = t0;
+            obj.v = v0;
+            obj.m = length(v0);
+            obj.n = 0;
+            obj.matrixexp = matrixexp;
+            obj.tol = tol;
+        end
+
+        function [v,t] = getV(obj)
+            v = obj.v;
+            t = obj.t;
+        end
+
+        function obj = step(obj)
+            obj.v = time.expint.Magnus_4(obj.v,obj.D, obj.t, obj.k, obj.matrixexp, obj.tol);
+            obj.t = obj.t + obj.k;
+            obj.n = obj.n + 1;
+        end
+    end
+
+
+    methods (Static)
+        function k = getTimeStep(lambda)
+            k = rk4.get_rk4_time_step(lambda);
+        end
+    end
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+time/MagnusMP.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,49 @@
+classdef MagnusMP < time.Timestepper
+    properties
+        D
+        S
+        F
+        k
+        t
+        v
+        m
+        n
+        matrixexp
+        tol
+    end
+
+
+    methods
+        function obj = MagnusMP(D, k ,t0,v0, matrixexp,tol)
+            default_arg('matrixexp','expm')
+            default_arg('tol',1e-6)
+            obj.D = D;
+            obj.k = k;
+            obj.t = t0;
+            obj.v = v0;
+            obj.m = length(v0);
+            obj.n = 0;
+            obj.matrixexp = matrixexp;
+            obj.tol = tol;
+        end
+
+        function [v,t] = getV(obj)
+            v = obj.v;
+            t = obj.t;
+        end
+
+        function obj = step(obj)
+            obj.v = time.expint.Magnus_mp(obj.v,obj.D, obj.t, obj.k,obj.matrixexp,obj.tol);
+            obj.t = obj.t + obj.k;
+            obj.n = obj.n + 1;
+        end
+    end
+
+
+    methods (Static)
+        function k = getTimeStep(lambda)
+            k = rk4.get_rk4_time_step(lambda);
+        end
+    end
+
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/diffSymfun.m	Tue Feb 20 15:00:30 2018 +0100
@@ -0,0 +1,7 @@
+% Differentiates a symbolic function like diff does, but keeps the function as a symfun
+function g = diffSymfun(f, varargin)
+    assertType(f, 'symfun');
+
+    args = argnames(f);
+    g = symfun(diff(f,varargin{:}), args);
+end