Mercurial > octave
view scripts/plot/draw/stream2.m @ 27759:992e702ef0d7
Add stream* functions (patch #9859).
* libinterp/corefcn/stream-euler.cc: New file.
* libinterp/corefcn/module.mk: Add new file to list of source files.
* stream2.m, stream3.m, streamline.m, streamtube.m: New functions.
* plot.txi: Add documentation of new functions to manual.
* __unimplemented__.m: Remove implemented functions from list.
* NEWS: Announce new functions.
author | Markus Meisinger <chloros2@gmx.de> |
---|---|
date | Sat, 23 Nov 2019 11:47:16 +0100 |
parents | |
children | 45ad2127582b |
line wrap: on
line source
## Copyright (C) 2019 Markus Meisinger ## ## This file is part of Octave. ## ## Octave is free software: you can redistribute it and/or modify it ## under the terms of the GNU General Public License as published by ## the Free Software Foundation, either version 3 of the License, or ## (at your option) any later version. ## ## Octave is distributed in the hope that it will be useful, but ## WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with Octave; see the file COPYING. If not, see ## <https://www.gnu.org/licenses/>. ## -*- texinfo -*- ## @deftypefn {} {@var{xy} =} stream2 (@var{x}, @var{y}, @var{u}, @var{v}, @var{sx}, @var{sy}) ## @deftypefnx {} {@var{xy} =} stream2 (@var{u}, @var{v}, @var{sx}, @var{sy}) ## @deftypefnx {} {@var{xy} =} stream2 (@dots{}, "@var{options}") ## Compute 2D streamline data. ## ## Calculates streamlines of a vector field given by [@var{u}, @var{v}]. ## The vector field is defined over a rectangular grid given by ## [@var{x}, @var{y}]. The streamlines start at the seed points ## [@var{sx}, @var{sy}]. The returned value @var{xy} contains a cell array ## of vertex arrays. If the starting point is outside the vector field, ## [] is returned. ## ## The input parameter @var{options} is a 2D vector of the form ## [@var{stepsize}, @var{maxnumbervertices}]. The first parameter specifies ## the step size used for trajectory integration (default 0.1). It is ## allowed to set a negative value to control the direction of integration. ## The second parameter specifies the maximum number of segments used to ## create a streamline (default 10000). ## ## The return value @var{xy} is a @nospell{nverts x 2} matrix containing the ## coordinates of the field line segments. ## ## Example: ## ## @example ## @group ## [x, y] = meshgrid (0:3); ## u = 2 * x; ## v = y; ## xy = stream2 (x, y, u, v, 1.0, 0.5); ## @end group ## @end example ## ## @seealso{streamline, stream3} ## ## @end deftypefn ## References: ## ## @article{ ## title = {Particle Tracing Algorithms for 3D Curvilinear Grids}, ## year = {2000}, ## author = {Nielson, Gregory and Uller, H. and Sadarjoen, I. and Walsum, Theo and Hin, Andrea and Post, Frits} ## } ## ## @article{ ## title = {Sources of error in the graphical analysis of CFD results}, ## publisher = {Journal of Scientific Computing}, ## year = {1988}, ## volume = {3}, ## number = {2}, ## pages = {149--164}, ## author = {Buning, Pieter G.}, ## } function xy = stream2 (varargin) options = []; switch (length (varargin)) case (0) print_usage (); case {4,5} if (length (varargin) == 4) [u, v, spx, spy] = varargin{:}; else [u, v, spx, spy, options] = varargin{:}; endif [m, n] = size (u); [x, y] = meshgrid (1:n, 1:m); case (6) [x, y, u, v, spx, spy] = varargin{:}; case (7) [x, y, u, v, spx, spy, options] = varargin{:}; otherwise error ("stream2: unknown input parameter count"); endswitch h = 0.1; maxnverts = 10000; if (! isempty (options)) switch (length (options)) case (1) h = options(1); case (2) h = options(1); maxnverts = options(2); otherwise error ("stream2: wrong options length"); endswitch endif if ((! isnumeric (h)) || (h == 0)) error ("stream2: step size error"); endif if ((! isnumeric (maxnverts)) || (maxnverts < 1)) error ("stream2: max num vertices error"); endif if (! (isequal (size (u), size (v), size (x), size (y)) && ... isequal (size (spx), size (spy))) ) error ("stream2: matrix dimensions must match"); endif if (iscomplex (u) || iscomplex (v) || iscomplex (x) || ... iscomplex (y) || iscomplex (spx) || iscomplex (spy)) error ("stream2: input must be real valued"); endif gx = x(1,:); gy = y(:,1).'; ## Jacobian Matrix dx = diff (gx); dy = diff (gy); ## "<" used to check if the mesh is ascending if (any (dx <= 0) || any (dy <= 0) || ... any (isnan (dx)) || any (isnan (dy))) error ("stream2: ill shaped elements in mesh"); endif tx = 1./dx; ty = 1./dy; ## "Don't cares" used for handling points located on the border tx(end + 1) = 0; ty(end + 1) = 0; dx(end + 1) = 0; dy(end + 1) = 0; px = spx(:); py = spy(:); for nseed = 1:length (px) xp = px(nseed); yp = py(nseed); idx = find (logical (diff (gx <= xp)), 1); if (gx(end) == xp) idx = numel (gx); endif idy = find (logical (diff (gy <= yp)), 1); if (gy(end) == yp) idy = numel (gy); endif if (isempty (idx) || isempty (idy)) xy{nseed} = []; else ## Transform seed from P coordinates to C coordinates zeta = (idx - 1) + (xp - gx(idx)) * tx(idx); xi = (idy - 1) + (yp - gy(idy)) * ty(idy); C = streameuler2d (u, v, tx, ty, zeta, xi, h, maxnverts); ## Transform from C coordinates to P coordinates idu = floor (C(:,1)); idv = floor (C(:,2)); xy{nseed} = [gx(idu + 1).' + (C(:,1) - idu).*(dx(idu + 1).'), ... gy(idv + 1).' + (C(:,2) - idv).*(dy(idv + 1).')]; endif endfor endfunction %!demo %! clf; %! [x, y] = meshgrid (-5:5, -4:4); %! u = x - 2 * y; %! v = 2 * x - 3 * y; %! sx = [3, 0, -1, -2, -3, 0, 1, 2]; %! sy = [3, 3, 3, 3, -3, -3, -3, -3]; %! h = streamline (x, y, u, v, sx, sy, 0.05); %! set (h, "color", "r"); %! hold on; %! quiver (x, y, u, v); %! scatter (sx(:), sy(:), 20, "filled", "o", "markerfacecolor", "r"); %! grid on; %! title ("Asymptotically Stable Equilibrium"); %! axis equal; %!test %! xy = stream2([1,1,1;2,2,2;3,3,3], [1,1,1;2,2,2;3,3,3], 1, 1, [0.01,5]); %! assert (numel (xy{:}), 10);