TikZ 中具有奇点的流图

TikZ 中具有奇点的流图

F(x,y)=[F1(x,y),F2(x,y)]我有定义为的矢量场

F1(x,y)= -(2*y/x^2)*(2*ln(cosh(x)) + (y-2*x)*tanh(x) - x*y*(1-(tanh(x))^2))
F2(x,y)= -(4/x)*(x*y-ln(cosh(x)) - y*tanh(x))

在 Mathematica 中,我可以通过指令轻松绘制相应的流图

StreamPlot[{F1[a, c], F2[a, c]}, {a, -10, 10}, {c, -10, 10}, AspectRatio -> 1/GoldenRatio]

产生

流图

我一直在尝试使用 Tikz 生成类似的东西。事实上,我尝试使用和\addplot3规范化quiver,但奇点破坏了代码(例如,在 [-10,10]x[-10,10] 域中)。此外,我尝试将所有内容拆分为非奇异子域,但尽管可以编译,但由于“直箭头”,外观很糟糕。下面是一段没有中断的相应代码及其输出:

\documentclass{standalone}

\usepackage{amsmath, tikz, pgfplots}
\pgfplotsset{compat = newest}
\usepgfplotslibrary{colormaps}

\begin{document}
    \begin{tikzpicture}
        \begin{axis}[
            zmin = 0, zmax = 1,
            axis equal image,
            xtick distance = 1,
            ytick distance = 1,
            view = {0}{90},
            scale = 1.25,
            title = {$F$},
            height=7cm,
            xlabel = {$x$},
            ylabel = {$y$},
            colormap/viridis,
            colorbar,
            colorbar style = {
                ylabel = {Vector Length}
            }
        ]
            \addplot3 [
                point meta = {sqrt(( (2*y / x^2)*( 2*ln(cosh(x)) + (y-2*x)*tanh(x) - x*y*(1-(tanh(x))^2) ) )^2 + ( (4 / x)*( x*y - ln(cosh(x)) - y*tanh(x) )^2)},
                quiver = {
                    u = {-(2*y / x^2)*( 2*ln(cosh(x)) + (y-2*x)*tanh(x) - x*y*(1-(tanh(x))^2) ) / sqrt(( (2*y / x^2)*( 2*ln(cosh(x)) + (y-2*x)*tanh(x) - x*y*(1-(tanh(x))^2) ) )^2 + ( (4 / x)*( x*y - ln(cosh(x)) - y*tanh(x) )^2)},
                    v = {-(4 / x)*( x*y - ln(cosh(x)) - y*tanh(x) ) / sqrt(( (2*y / x^2)*( 2*ln(cosh(x)) + (y-2*x)*tanh(x) - x*y*(1-(tanh(x))^2) ) )^2 + ( (4 / x)*( x*y - ln(cosh(x)) - y*tanh(x) )^2)},
                    scale arrows = 0.15,
                },
                quiver/colored = {mapped color},
                -stealth,
                domain = 0:5,
                domain y = 0:5,
            ] {0};
            
        \end{axis}
    \end{tikzpicture}
\end{document}

Tikz 与箭筒尝试

请注意,上述代码通过F1=u, F2=v规范化箭头的长度(随后通过 颜色刻度图例指示point meta)来规范化中的 que 向量场。

我想在 Tikz 中获得类似于第一种情况的东西(带箭头的曲线,而不是许多直箭头),能够处理“奇点”。

先感谢您 ;)。

答案1

流线图

我尝试使用基本 TikZ 获得“流图”。每条轨迹(或轨道)都是从一个点开始构建的,并分别在时间上向前和向后移动。考虑到您的具体问题,我的代码不包括封闭轨道的情况。必须在命令中添加不同的分支\streamPlot

stream plot by name上图使用了由和构成的轨道集stream plot TB(顶部 底部)。请注意,这些是pic对象,因此如果全局使用缩放,则应小心处理它们。它们基于\streamPlot

我需要两者,因为我认为需要更接近矢量场的奇点才能获得良好的图像。例如,使用 Mathematica 构建的图像并没有真正显示原点附近发生的事情。

关于所考虑的矢量场的一些注释:一些重写是为了得到一种可能用于 TikZ 的形式(计算精度较低,但足以用于绘图)。下面是查看这两个组件的一种方式。我在X需要理解小值的行为X矢量场分量

评论

  1. 查看第一幅图中的流图,可以注意到在轨迹“相遇”的地方发生了一些事情。为了理解这个问题,我们可以将矢量场与曲线一起绘制U(x,y)= 0(蓝色)和V(x,y)= 0(红色的)。 在此处输入图片描述 另请参阅下面用 Python 构建的最后一张图片(这就是它位于我的答案末尾的原因)。

  2. 向量场的奇点并不完全遵循蓝色曲线(假设)。但我们在流图(图 1)中看不到这一点。这就是为什么我为某个初始条件添加了红色相应微分方程的解。它使用函数ode-trajectory

  3. 所有计算背后的算法都是按照 风格开发的经典龙格-库塔算法runge-kutta

代码 代码相当长,主要是因为矢量场分量各定义了三次(不同上下文所需),并且图形元素有三种类型:矢量场、流图、柯西问题的轨迹。

\documentclass[11pt, margin=17pt]{standalone} 
\usepackage{amsmath, amssymb}
\usepackage{ifthen}

\usepackage{tikz}
\usetikzlibrary{math, calc, arrows.meta}
\usetikzlibrary{decorations.markings}


\pgfkeys{/tikz/.cd,
  x bound start/.store in=\xBoundStart,
  x bound end/.store in=\xBoundEnd,
  y bound start/.store in=\yBoundStart,
  y bound end/.store in=\yBoundEnd
}

\makeatletter
\tikzset{%
  bounds/.style n args={4}{%
    evaluate={%
      \xBoundStart = #1;
      \xBoundEnd = #2;
      \yBoundStart = #3;
      \yBoundEnd = #4;
    }
  },
  pics/vector field background/.style={% axes + grid for a vector field
    code={%
      \begin{scope}[every node/.style={scale=.8},
        evaluate={%
          \iIni = {int(\xBoundStart)};
          \iEnd = {int(\xBoundEnd)};
          \jIni = {int(\yBoundStart)};
          \jEnd = {int(\yBoundEnd)};
        }]
        \draw[gray!50] (\xBoundStart, \yBoundStart)
        grid (\xBoundEnd, \yBoundEnd);
        \fill[black] (0, 0) circle (1pt);
        \foreach \i in {\iIni, ..., \iEnd}{%
          \path (\i, \yBoundStart) node[below=1ex] {$\i$};
        }
        \foreach \j in {\jIni, ..., \jEnd}{%
          \path (\xBoundStart, \j) node[left=1ex] {$\j$};
        }           
      \end{scope}
    }
  },
  flow/.style={%  create a directional arrow along a trajectory
    decoration={
      markings,% switch on markings
      mark=at position .5 with {\arrow[#1]{Latex}}
    }, postaction=decorate
  },
  -flow/.style={%
    decoration={
      markings,% switch on markings
      mark=at position .5 with {\arrowreversed[#1]{Latex}}
    }, postaction=decorate
  },
  runge-kutta/.style={%  to be invoked before using ode-trajectory, ...
    evaluate={%
      int \N@ode, \i, \j;
      \N@ode = 4;
      for \i in {1, ..., \N@ode}{%
        for \j in {1, ..., \N@ode}{%
          \a@ode{\i,\j} = 0;
        };
      };
      \a@ode{2,1} = 1/2; \a@ode{3,2} = 1/2; \a@ode{4,3} = 1;
      \c@ode{1} = 0; \c@ode{2} = 1/2; \c@ode{3} = 1/2; \c@ode{4} = 1;
      \b@ode{1} = 1/6; \b@ode{2} = 1/3; \b@ode{3} = 1/3; \b@ode{4} = 1/6;
    }
  },
  % for ode in two dimensions
  ode-trajectory/.style args={RHTx=#1, RHTy=#2, from=#3, to=#4, steps=#5}{%
    insert path={coordinate (tmp) let \p1 = (tmp) in},
    evaluate={%
      real \showpointr, \testTmp;
      \showpointr = 1;
      int \steps@ode, \i, \j, \k, \s;
      \t@ode{0} = #3;
      \u@ode{0} = \x1*0.0352778;  % converts pt to cm
      \v@ode{0} = \y1*0.0352778;
      \steps@ode = int(#5);
      \t@ode{\steps@ode} = #4;
      \h = (\t@ode{\steps@ode} -\t@ode{0})/\steps@ode;
      for \s in {1, 2, ..., \steps@ode}{
        \k = int(\s -1);
        \t@ode{0,1} = \t@ode{\k};
        \x@ode{0,1} = \u@ode{\k};
        \y@ode{0,1} = \v@ode{\k};
        \qx@ode{0,1} = #1(\t@ode{0,1}, \x@ode{0,1}, \y@ode{0,1});
        \qy@ode{0,1} = #2(\t@ode{0,1}, \x@ode{0,1}, \y@ode{0,1});
        for \i in {2, ..., \N@ode}{%
          \t@ode{0,\i} = \t@ode{\k} +\h*\c@ode{\i};
          \x@ode{0,\i} = \u@ode{\k};
          \y@ode{0,\i} = \v@ode{\k};
          for \j in {1, ..., {int(\i -1)}}{%
            \x@ode{0,\i} = \x@ode{0,\i} +\h*\a@ode{\i,\j}*\qx@ode{0,\j};
            \y@ode{0,\i} = \y@ode{0,\i} +\h*\a@ode{\i,\j}*\qy@ode{0,\j};
          };
          \qx@ode{0,\i} = #1(\t@ode{0,\i}, \x@ode{0,\i}, \y@ode{0,\i});
          \qy@ode{0,\i} = #2(\t@ode{0,\i}, \x@ode{0,\i}, \y@ode{0,\i});
        };
        \t@ode{\s} = \t@ode{\k} +\h;
        \u@ode{\s} = \u@ode{\k};
        \v@ode{\s} = \v@ode{\k};
        for \i in {1, 2, ..., \N@ode}{%
          \u@ode{\s} = \u@ode{\s} +\h*\b@ode{\i}*\qx@ode{0,\i};
          \v@ode{\s} = \v@ode{\s} +\h*\b@ode{\i}*\qy@ode{0,\i};
        };
      };
      \k = \steps@ode-1;
      \testTmp = pow(pow(\u@ode{\steps@ode} -\u@ode{\k}, 2)
      +pow(\v@ode{\steps@ode} -\v@ode{\k}, 2), .5);
    },
    insert path={%
      \foreach \s in {1, ..., \steps@ode}{
        -- (\u@ode{\s}, \v@ode{\s})
      }
    }
  },
  m vector field/.style n args={5}{% u / v / Nx / Ny / arrow scale
    insert path = {%
      \pgfextra{%
        \let\tikz@mode@save=\tikz@mode
        \let\tikz@options@save=\tikz@options%
      }
    },
    evaluate={%
      coordinate \tmp@P, \tmp@V;
      integer \Nx, \Ny;
      \Nx = #3;
      \Ny = #4;
      real \dx, \dy, \tmp, \uVF, \vVF, \nVF, \s@cst;
      \s@cst = .49;
      \dx = (\xBoundEnd -\xBoundStart)/\Nx;
      \dy = (\yBoundEnd -\yBoundStart)/\Ny;
      for \i in {1, ..., \Nx}{%
        for \j in {1, ..., \Ny}{%
          \uVF = #1(\xBoundStart -\dx/2 +\i*\dx, \yBoundStart -\dy/2 +\j*\dy);
          \vVF = #2(\xBoundStart -\dx/2 +\i*\dx, \yBoundStart -\dy/2 +\j*\dy);
          \nVF = pow(\uVF*\uVF +\vVF*\vVF, .5);
          if  \nVF > \s@cst then {%
            \uVF = \uVF/\nVF*.5;
            \vVF = \vVF/\nVF*.5;
          };
          \tmp@P = (\xBoundStart +\i*\dx, \yBoundStart +\j*\dy);
          \tmp@V = (#5*\uVF, #5*\vVF);
          {
            \draw[arrows={-Latex[width=2.5pt, length=2pt]}]
            \pgfextra{\let\tikz@mode=\tikz@mode@save
              \let\tikz@options=\tikz@options@save}
            ($(\tmp@P) -.5*(\tmp@V)$) -- ++(\tmp@V);
          };          
        };
      };
    }
  }
}
\newcommand{\streamPlot}[7]{% RHTx, RHTy, h, px, py, min, color
  \tikzmath{%
    integer \steps@ode, \i, \j, \k, \s\, flag;
    real \h, \nor;
    \flag = 0;
    \s = 0;
    \k = 0;
    \h = #3;    
    \u@ode{0} = #4;
    \v@ode{0} = #5;
    \t@ode{0} = 0;
  },
  \whiledo{\equal{\flag}{0}}{%
    \tikzmath{
      \s = \s +1;
      \t@ode{0,1} = 0;
      \x@ode{0,1} = \u@ode{\k};
      \y@ode{0,1} = \v@ode{\k};
      \qx@ode{0,1} = #1(\t@ode{0,1}, \x@ode{0,1}, \y@ode{0,1});
      \qy@ode{0,1} = #2(\t@ode{0,1}, \x@ode{0,1}, \y@ode{0,1});
      for \i in {2, ..., \N@ode}{%
        \t@ode{0,\i} = \t@ode{\k} +\h*\c@ode{\i};
        \x@ode{0,\i} = \u@ode{\k};
        \y@ode{0,\i} = \v@ode{\k};
        for \j in {1, ..., {int(\i -1)}}{%
          \x@ode{0,\i} = \x@ode{0,\i} +\h*\a@ode{\i,\j}*\qx@ode{0,\j};
          \y@ode{0,\i} = \y@ode{0,\i} +\h*\a@ode{\i,\j}*\qy@ode{0,\j};
        };
        \qx@ode{0,\i} = #1(\t@ode{0,\i}, \x@ode{0,\i}, \y@ode{0,\i});
        \qy@ode{0,\i} = #2(\t@ode{0,\i}, \x@ode{0,\i}, \y@ode{0,\i});
      };
      \t@ode{\s} = \t@ode{\k} +\h;
      \u@ode{\s} = \u@ode{\k};
      \v@ode{\s} = \v@ode{\k};
      for \i in {1, 2, ..., \N@ode}{%
        \u@ode{\s} = \u@ode{\s} +\h*\b@ode{\i}*\qx@ode{0,\i};
        \v@ode{\s} = \v@ode{\s} +\h*\b@ode{\i}*\qy@ode{0,\i};
      };
      \nor = pow(%
        pow(\u@ode{\s} -\u@ode{\k}, 2) +pow(\v@ode{\s} -\v@ode{\k}, 2),
      .5);
      if \nor<#6 then {\flag = 1;};
      if \u@ode{\s}<\xBoundStart then {\flag = 1;};
      if \u@ode{\s}>\xBoundEnd then {\flag = 1;};
      if \v@ode{\s}<\yBoundStart then {\flag = 1;};
      if \v@ode{\s}>\yBoundEnd then {\flag = 1;};
      \k = \k +1;
    }
  },
  \tikzmath{%
    if \s>1 then {%
      if #3>0 then {%
        {%
          \draw[#7, flow={#7}]  (\u@ode{0}, \v@ode{0})
          \foreach \i [parse=true] in {1, ..., \s-1}{
            -- (\u@ode{\i}, \v@ode{\i})
          };
        };
      } else {%
        {%
          \draw[#7, -flow={#7}]  (\u@ode{0}, \v@ode{0})
          \foreach \i [parse=true] in {1, ..., \s-1}{
            -- (\u@ode{\i}, \v@ode{\i})
          };
        };
      };
    };
  }
}
\makeatother

\tikzset{
  pics/stream plot by name/.style args={RHTx=#1, RHTy=#2, dT=#3, pName=#4,
    pNumber=#5, min=#6, color=#7}{%
    code={
      \foreach \i in {1, ..., #5}{%
        \tikzmath{%
          coordinate \P;
          \P = (#4-\i);
          \px = \Px*1pt/1cm;  % converts pt to cm
          \py = \Py*1pt/1cm;
        }
        % \draw (\px, \py) circle (2pt);
        \streamPlot{#1}{#2}{#3}{\px}{\py}{#6}{#7};
        \streamPlot{#1}{#2}{-#3}{\px}{\py}{#6}{#7};
      }
    }
  },
  pics/stream plot TB/.style args={%
    RHTx=#1, RHTy=#2, dT=#3, uSteps=#4, min=#5, color=#6}{%
    code={
      \tikzmath{%
        real \px, \py, \dx;
        \dx = (\xBoundEnd -\xBoundStart)/#4;
      }
      \foreach \i in {0, ..., #4}{%
        \tikzmath{%
          \px = \xBoundStart +\i*\dx;
          \py = \yBoundStart;
        }
        \streamPlot{#1}{#2}{#3}{\px}{\py}{#5}{#6};
        \streamPlot{#1}{#2}{-#3}{\px}{\py}{#5}{#6};
      }
      \foreach \i in {0, ..., #4}{%
        \tikzmath{%
          \px = \xBoundStart +\i*\dx;
          \py = \yBoundEnd;
        }
        \streamPlot{#1}{#2}{#3}{\px}{\py}{#5}{#6};
        \streamPlot{#1}{#2}{-#3}{\px}{\py}{#5}{#6};
      }
    }
  }
}


\begin{document}

%\iffalse
\begin{tikzpicture}[every node/.style={%
    right, align=left, inner sep=3ex
  }]
  \path (-1.3, 0) node {$U(x, y)$}
  (0, 0) node[] {$\displaystyle
    = y\left[
      -2\,\frac{\ln(\cosh x)}{x^2}
      +\frac{x -\tanh x}{x^2}\,y
      +\frac{\tanh x}{x}\,(2 -y\,\tanh x)
    \right]$}
  ++(0, -1) node[] {$\displaystyle
    = y\left[
      1 +\frac{2}{9}\,x^4
      -\bigg(\frac{2}{3}\,x -\frac{8}{15}\,x^3\bigg)y
    \right] +[5]$};

  \path (-1.3, -3) node {$V(x, y)$}
  (0, -3) node[] {$\displaystyle
    = 2\,\frac{\ln(\cosh x)}{x} +2\,\frac{\tanh x -x}{x}\,y$}
  ++(0, -1) node[] {$\displaystyle
    = x\left[
      1 -\frac{1}{3}\,x^2
      -\bigg( \frac{2}{3}\,x -\frac{4}{15}\,x^3 \bigg)y
    \right] +[5]$};
\end{tikzpicture}
%\fi


\tikzmath{%
  function Ux(\t, \u, \v) {%
    real \a, \b, \c;
    if abs(\u)>.05 then {%
      \a = -2*ln(cosh(\u))/(\u*\u);
      \b = (\u -tanh(\u))/(\u*\u)*\v;
      \c = (tanh(\u)/\u)*(2 - tanh(\u)*\v);
    } else {%
      \a = 1 -2/3*\u*\v;
      \b = 8/15*pow(\u, 3)*\v;
      \c = 2/9*pow(\u, 4);
    };
    return {(\a +\b +\c)*\v};
  };
  function Uy(\t, \u, \v) {%
    real \a, \b;
    if abs(\u)>.05 then {%
      \a = ln(cosh(\u))/\u;
      \b = (tanh(\u) -\u)/\u;
      return {2*\a +2*\b*\v};
    } else {
      \a = 1 -pow(\u, 2)/3;
      \b = -(2/3)*\u +(4/15)*pow(\u, 3);
      return {\u*(\a +\b*\v)};
    };
  };
  function fUy(\u) {%
    real \a, \b;
    \a = ln(cosh(\u))/\u;
    \b = (\u -tanh(\u))/\u;
    return \a/\b;
  };
  function UxVF(\u, \v) {%
    real \a, \b, \c;
    if abs(\u)>.05 then {%
      \a = -2*ln(cosh(\u))/(\u*\u);
      \b = (\u -tanh(\u))/(\u*\u)*\v;
      \c = (tanh(\u)/\u)*(2 - tanh(\u)*\v);
    } else {%
      \a = 1 -2/3*\u*\v;
      \b = 8/15*pow(\u, 3)*\v;
      \c = 2/9*pow(\u, 4);
    };
    return {(\a +\b +\c)*\v};
  };
  function fUx(\u) {%
    real \a, \b;
    \a = 2*(tanh(\u)/\u) -2*ln(cosh(\u))/(\u*\u);
    \b = -(\u -tanh(\u))/(\u*\u) +(tanh(\u)/\u)*tanh(\u);
    return \a/\b;
  };
  function UyVF(\u, \v) {%
    real \a, \b;
    if abs(\u)>.05 then {%
      \a = ln(cosh(\u))/\u;
      \b = (tanh(\u) -\u)/\u;
      return {2*\a +2*\b*\v};
    } else {
      \a = 1 -pow(\u, 2)/3;
      \b = -(2/3)*\u +(4/15)*pow(\u, 3);
      return {\u*(\a +\b*\v)};
    };
  };
}

\iffalse
\begin{tikzpicture}
  \draw[gray!50, very thin] (-3.5, -3.25) grid (3.5, 3.25);
  \draw[->] (-3.5, 0) -- (3.5, 0) node[above right] {$x$};
  \draw[->] (0,-3.5) -- (0, 3.5) node[left] {$y$};
  
  \draw[blue!70!black, thick, variable=\t, domain=.5:3.25, samples=200]
  plot (\t, {fUx(\t)});
  \draw[blue!70!black, thick] (-3.25, 0) -- (3.25, 0);
  \draw[blue!70!black, thick, variable=\t, domain=-3.25:-.5, samples=200]
  plot (\t, {fUx(\t)});
  \draw[red, thin, variable=\t, domain=.5:3.25, samples=200]
  plot (\t, {fUy(\t)});
  \draw[red] (-0, -3.25) -- (0, 3.25);
  \draw[red, thin, variable=\t, domain=-3.25:-.5, samples=200]
  plot (\t, {fUy(\t)});
\end{tikzpicture}
\fi

\iffalse
\begin{tikzpicture}[runge-kutta, bounds={-4}{4}{-4}{4}, scale=1.2]
  \path pic[scale=1.2] {vector field background};

  \draw[blue!70!black, thick,
  variable=\t, domain=.35:\xBoundEnd, samples=200]
  plot (\t, {fUx(\t)});
  \draw[blue!70!black, thick] (\xBoundStart, 0) -- (\xBoundEnd, 0);
  \draw[blue!70!black, thick,
  variable=\t, domain=\xBoundStart:-.35, samples=200]
  plot (\t, {fUx(\t)});
  \draw[red, thin, variable=\t, domain=.35:\xBoundEnd, samples=200]
  plot (\t, {fUy(\t)});
  \draw[red] (-0, \xBoundStart) -- (0, \xBoundEnd);
  \draw[red, thin, variable=\t, domain=\xBoundStart:-.35, samples=200]
  plot (\t, {fUy(\t)});
  \draw[green!50!black, thick, m vector field={UxVF}{UyVF}{35}{35}{.4}];
\end{tikzpicture}
\fi

\iffalse
\begin{tikzpicture}[runge-kutta, bounds={-4}{4}{-3.5}{3.5}]
  \path pic {vector field background};

  % A points
  \path (0, 1.5) coordinate (A-1);
  \path (0, -1.5) coordinate (A-2);
  \path (2.2, \yBoundEnd) coordinate (A-3);
  \path (-2.2, \yBoundStart) coordinate (A-4);

  % B points
  \tikzmath{
    integer \N;
    \N = 4;
  }
  \foreach \i in {1, ..., \N}{%
    \path (\i*360/\N: .5) coordinate (B-\i);
  }

  \path pic {stream plot by name={RHTx=Ux, RHTy=Uy, dT=.05,
      pName=A, pNumber=4, min=.005, color=blue!60!black}};
  \path pic {stream plot by name={RHTx=Ux, RHTy=Uy, dT=.05,
      pName=B, pNumber=\N, min=.005, color=blue!60!black}};

  \path pic {stream plot TB={RHTx=Ux, RHTy=Uy, dT=.05,
      uSteps=11, min=.005, color=blue!60!black}};

  \draw[red, very thick] (2.7, -3)
  [ode-trajectory={RHTx=Ux, RHTy=Uy, from=0, to=15, steps=1500}];  
\end{tikzpicture}
\fi

\end{document}

的水平曲线矢量场的分量。图 1 中的红色曲线是此处的黑色轨迹! U 的水平曲线

相关内容