changeset 97:33dba20b4b9d feature/arclen-param

Merged with deafult.
author Martin Almquist <martin.almquist@it.uu.se>
date Wed, 02 Dec 2015 16:29:54 +0100
parents 7b092f0fd620 (diff) 19d0c9325a3e (current diff)
children b30f3d8845f4
files +multiblock/equal_step_size.m
diffstat 4 files changed, 224 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/+grid/Curve.m	Wed Dec 02 16:21:16 2015 +0100
+++ b/+grid/Curve.m	Wed Dec 02 16:29:54 2015 +0100
@@ -3,32 +3,60 @@
         g
         gp
         transformation
+        arc_length_fun 
+        
+        % arc_length_fun: 
+        % function handle. arc_length(s)=distance 
+        % between t=0 and t=s.
     end
     methods
         %TODO:
         % Errors or FD if there is no derivative function added.
+        % -semi-done
 
         % Concatenation of curves
         % Subsections of curves
-        % Stretching of curve paramter
+        % Stretching of curve paramter - semi-done
         % Curve to cell array of linesegments
 
-        % Should accept derivative of curve.
-        function obj = Curve(g,gp,transformation)
+        % Should supply either derivative or a difference operator D1
+        function obj = Curve(g,gp,transformation,D1,arc_length_fun)
             default_arg('gp',[]);
             default_arg('transformation',[]);
+            default_arg('D1',[]);
+            default_arg('arc_length_fun',[]);
             p_test = g(0);
             assert(all(size(p_test) == [2,1]), 'A curve parametrization must return a 2x1 vector.');
 
+            if(isempty(gp) && isempty(D1));
+                % Should be error instead of disp.
+                disp(['You really should supply either the exact derivative ',...
+                'or a suitable difference operator to compute an approximation.']);
+            elseif(isempty(gp))
+                gp = grid.Curve.numerical_derivative(g,D1);
+            end
+            
             if ~isempty(transformation)
                 transformation.base_g = g;
                 transformation.base_gp = gp;
                 [g,gp] = grid.Curve.transform_g(g,gp,transformation);
             end
 
+            if(isempty(arc_length_fun))
+                if(~isempty(D1)); N = length(D1); % Same accuracy as for deriv.
+                else N = 101; % Best way to let user choose?
+                end
+                tvec = linspace(0,1,N);
+                arc_vec = grid.Curve.arc_length(gp,0,tvec);
+                arc_length_fun = grid.Curve.spline(tvec,arc_vec);
+            end
+            
             obj.g = g;
             obj.gp = gp;
             obj.transformation = transformation;
+            obj.arc_length_fun = arc_length_fun;
+            
+
         end
 
         % Made up length calculation!! Science this before actual use!!
@@ -82,16 +110,40 @@
         end
 
 
-        % Plots a curve g(t) for 0<t<1, using n points. Retruns a handle h to the plotted curve.
+        % Plots a curve g(t) for 0<t<1, using n points. Returns a handle h to the plotted curve.
         %   h = plot_curve(g,n)
-        function h = plot(obj,n)
+        function h = plot(obj,n,marker)
             default_arg('n',100);
+            default_arg('marker','line')
 
             t = linspace(0,1,n);
 
             p = obj.g(t);
 
-            h = line(p(1,:),p(2,:));
+            switch marker
+                case 'line'
+                    h = line(p(1,:),p(2,:));
+                otherwise
+                    h = plot(p(1,:),p(2,:),marker);
+            end
+        end
+        
+        % Plots the derivative gp(t) for 0<t<1, using n points. Returns a handle h to the plotted curve.
+        %   h = plot_curve(gp,n)
+        function h = plot_derivative(obj,n,marker)
+            default_arg('n',100);
+            default_arg('marker','line')
+
+            t = linspace(0,1,n);
+
+            p = obj.gp(t);
+
+            switch marker
+                case 'line'
+                    h = line(p(1,:),p(2,:));
+                otherwise
+                    h = plot(p(1,:),p(2,:),marker);
+            end
         end
 
         function h= plot_normals(obj,l,n,m)
@@ -125,7 +177,27 @@
         end
             % Shows curve with name and arrow for direction.
 
-
+        
+        function curve = stretch_parameter(obj,type)
+            default_arg('type','arc_length');
+            switch type
+                % Arc length parameterization.
+                case 'arc_length'
+                    arcLength = obj.arc_length_fun;
+                    arcPar = @(t) util.fzero_vec(@(s)arcLength(s) - t*arcLength(1),[0-10*eps,1+10*eps]);
+                    g_new = @(t)obj.g(arcPar(t));
+                    gp_old = obj.gp;
+                    gp_new = @(t) normalize(gp_old(arcPar(t)));
+                    
+                    arc_len_new = @(t) t;
+                    curve = grid.Curve(g_new,gp_new,[],[],arc_len_new);
+                    
+                otherwise
+                    error('That stretching is not implemented.');
+            end
+            
+        end
+            
         % how to make it work for methods without returns
         function p = subsref(obj,S)
             %Should i add error checking here?
@@ -265,6 +337,46 @@
     end
 
     methods (Static)
+        
+        % Length of arc from parameter t0 to t1 (which may be vectors).
+        % Computed using derivative.
+        function L = arc_length(deriv,t0,t1)
+            speed = @(t) sp(deriv(t));
+            
+            function s = sp(deriv)
+                s = sqrt(sum(deriv.^2,1));
+            end
+            L =  util.integral_vec(speed,t0,t1);
+        end
+        
+        function gp_out = numerical_derivative(g,D1)
+            m = length(D1); L = 1; % Assume curve parameter from 0 to 1.
+            t = linspace(0,L,m); 
+            g = g(t)';
+            gp = (D1*g)';
+
+            gp1_fun = grid.Curve.spline(t,gp(1,:));
+            gp2_fun = grid.Curve.spline(t,gp(2,:));
+            gp_out = @(t) [gp1_fun(t);gp2_fun(t)];
+            
+        end
+        
+        % Returns a function handle to the spline.
+        function f = spline(tval,fval,spline_order)
+            default_arg('spline_order',4);
+            [m,~] = size(tval);
+            assert(m==1,'Need row vectors.');
+            
+            % make vectors longer to be safe slightly beyond edges.
+            dt0 = tval(2)-tval(1); dt1 = tval(end)-tval(end-1);
+            df0 = fval(2)-fval(1); df1 = fval(end)-fval(end-1);
+            tval = [tval(1)-dt0, tval, tval(end)+dt1];
+            fval = [fval(1)-df0, fval, fval(end)+df1];
+            
+            f_spline = spapi( optknt(tval,spline_order), tval, fval );
+            f = @(t) fnval(f_spline,t);
+        end
+        
         function obj = line(p1, p2)
 
             function v = g_fun(t)
@@ -343,5 +455,14 @@
             end
         end
 
-    end
+    end 
 end
+
+function g_norm = normalize(g0)
+    g1 = g0(1,:); g2 = g0(2,:);
+    normalization = sqrt(sum(g0.^2,1));
+    g_norm = [g1./normalization; g2./normalization];
+end
+
+    
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+util/fzero_vec.m	Wed Dec 02 16:29:54 2015 +0100
@@ -0,0 +1,14 @@
+function I = fzero_vec(f,lim)
+% Wrapper around the built-in function fzero that
+% handles multiple functions (vector-valued f).
+
+    fval = f(lim(1));
+    I = zeros(size(fval));
+    
+    for i = 1:length(fval)
+        e = zeros(size(fval));
+        e(i) = 1;
+        I(i) = fzero(@(t) sum(e.*f(t)),lim);
+    end
+    
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/+util/integral_vec.m	Wed Dec 02 16:29:54 2015 +0100
@@ -0,0 +1,26 @@
+function I = integral_vec(f,a,b)
+% Wrapper around the built-in function integral that
+% handles multiple limits.
+
+    Na = length(a);
+    Nb = length(b);
+    assert(Na == 1 || Nb == 1 || Na==Nb,...
+        'a and b must have same length, unless one is a scalar.');
+    
+    if(Na>Nb);
+        I = zeros(size(a));
+        for i = 1:Na
+            I(i) = integral(f,a(i),b);
+        end
+    elseif(Nb>Na)
+        I = zeros(size(b));
+        for i = 1:Nb
+            I(i) = integral(f,a,b(i));
+        end
+    else
+        I = zeros(size(b));
+        for i = 1:Nb
+            I(i) = integral(f,a(i),b(i));
+        end
+    end
+end
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testArcLength.m	Wed Dec 02 16:29:54 2015 +0100
@@ -0,0 +1,55 @@
+m = 201; L = 1; order = 4;
+close all;
+tic
+
+g1 = @(t) 2*pi*t.*sin(2*pi*t);
+g2 = @(t) 2*pi*t.*cos(2*pi*t);
+g = @(t) [g1(t);g2(t)];
+
+t = linspace(0,L,m)'; dt = L/(m-1);
+ops = sbp.Ordinary(m,dt,order);
+D = ops.derivatives.D1;
+
+C = grid.Curve(g,[],[],D);
+
+% Function
+figure;
+C.plot([],'bo');
+hold on
+plot(g1(t),g2(t),'r-');
+drawnow
+
+% Derivative
+figure
+C.plot_derivative([],'bo');
+hold on;
+plot(2*pi*sin(2*pi*t) + (2*pi)^2*t.*cos(2*pi*t),...
+    2*pi*cos(2*pi*t) - (2*pi)^2*t.*sin(2*pi*t),'r-')
+drawnow
+
+% Arc length
+L = C.arc_length_fun(t);
+figure;
+plot(t,L)
+drawnow
+
+% Stretch curve
+C2 = C.stretch_parameter();
+z = linspace(0,1,m);
+gnew = C2.g(z);
+gpnew = C2.gp(z);
+
+% Compare stretched and unstretched curves.
+figure
+plot(g1(t),g2(t),'b*',gnew(1,:),gnew(2,:),'ro');
+
+% Compare stretched and unstretched derivatives. 
+figure
+theta = linspace(0,2*pi,100);
+plot(cos(theta),sin(theta),'-b',gpnew(1,:),gpnew(2,:),'rx');
+
+toc
+
+
+
+