TeXで数値計算をしたくなったら
TeXで数値計算をしたくなったら,この記事の内容を試してみてはいかがでしょうか。TeX&TikZで数値計算と絵の描画の両方ができます。主はプログラミング素人で,ごくたまに趣味でTeXを使います。書き方や変数のネーミングセンスはご容赦ください。
TeXはPDFを作成するところまでの処理ができます。ここまでの処理でパラパラ漫画を作ります。これを動画ファイルにすることで動画作りができます。
たとえばこんな感じ
https://youtu.be/7y507cBemnM
動画作成までの流れ
TeX処理→PDF作成
PDF→PNG画像(poppler cairo)
PNG画像→mp4(aviutl)
TeXで書くこと(概略)
大きく分けると,次のようなパーツで構成します。
- パラメータ・初期値・その他必要な定義
- tikzで描画
- 数値計算
- \newpage
2~4の内容を繰り返し実行させます。4.を忘れてしまうと,パラパラ漫画にならないので注意です。またpreview環境を使って,図の部分の切り抜きを行います。
1~4の順番でTeXに書く内容を書いていきます。
カウンターの設置・パラメータ・初期値(変数の設置)
繰り返し処理(ループ)をするために,カウンターを定義しておく。
%カウンター定義
\newcount\countA%
同時に何回繰り返すかをここで定義しておく。TeXマクロを定義する\def
を使う。
%%%#1 %分割数
\def\stepA{10}%Total Time70
カウンター・loop関係の設定
%カウンター定義
\newcount\countA%.......................
\newcount\countB%..........................
\newcount\countC%..........................
%%%#1 %分割数
\def\stepC{3}%内部計算3
\def\stepB{10}%フレーム数 10 予定
\def\stepA{140}%Total Time70
補助的なカウンター
\newcount\InnerCount%多粒子系用
\global\edef\TrajCount{1}%軌道残像よう カウンターではない
パラメータ設定
%%%%%%%%%%%%%%%%%%%%%%%%%
%物理パラメータ 定数
%粒子数の設定
%%%%%%%%%%%%%%%%%%%%%%%%%
\tikzmath{
real \PI;
\PI = 3.1415;
real \grav;
\grav = 0.02;
real \MASS;
\MASS = 10;
\freqS = 2*\PI/ 32;
int \ParNum ;
\ParNum=5; %粒子数
}
tikzにはpi
という定数関数が存在します。知らないときにつくったコードなので,その名残りです。
初期値・変数の設定
\tikzmath{
real
\NqiXMonkey \NqiYMonkey \NviXMonkey \NviYMonkey;
\NqiXMonkey = ...;
\NqiYMonkey = ...;
\NviXMonkey = ...;
\NviYMonkey = ...;
}
%サルの初期位置
\global\edef\variXCdMonkey{\NqiXMonkey}%初期値を定める
\global\edef\variYCdMonkey{\NqiYMonkey}%初期値を定める
%サルの初速度
\def\variXVelocityMonkey{\NviXMonkey}
\def\variYVelocityMonkey{\NviYMonkey}
微分方程式に登場する関数の定義
%力・加速度関数
\def\funcAccelMX#1#2#3#4{....}
\def\funcAccelMY#1#2#3#4{....}
loop
\countA = 0 \loop\ifnum\countA < \stepA
{
\countB = 0 \loop\ifnum\countB < \stepB
{
%tikzの描画
\begin{tikzpicture}
\end{tikzpicture}
%ルンゲクッタ計算パート
\countC = 0 \loop\ifnum\countC < \stepC
{
}
\advance\countB by1\repeat % end for
\newpage
}\advance\countB by1\repeat % end for
}\advance\countA by1\repeat % end for
通常3つのカウンターを用いて,3つのループを入れ子にして使用しています。PDFのページはstepA×stepBページ生成されます。\countCによるloopは,計算精度を上げるために使用したりします。必要ない場合は\def\stepC{1}
とします。
tikzpicture
\begin{tikzpicture}
%背景
\draw[gray] (0,0,0) -- (20,0,0) (0,0,0) -- (-20,0,0) (0,0,0) -- (0,20,0) (0,0,0) -- (0,-20,0);
\foreach \x in {1,...,20}
{
\draw[gray] (0,0,0) circle (\x*\DiscR cm);
}
%いろいろ書きます
\end{tikzpicture}
ルンゲクッタ計算部分
初期値を代入
%ルンゲクッタ開始
%サル用 初期値代入
\tikzmath{
\NqtXTako = \variXCdMonkey;
\NqtYTako = \variYCdMonkey;
\NvtXTako = \variXVelocityMonkey;
\NvtYTako = \variYVelocityMonkey;
}
計算パート(運動方程式を積分・2次のルンゲクッタの方法に基づく)
\tikzmath{
%半ステップ後の速度を計算するよ
real \variFuji;
\variFuji1=\NqtXTako;
\variFuji2=\NqtYTako;
\variFuji3=\NvtXTako;
\variFuji4=\NvtYTako;
\NatXTako = \funcAccelMX{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
\NatYTako = \funcAccelMY{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
%
\variFuji1=\NqtXTako + 0.25 * \NvtXTako *\dT /\stepC;
\variFuji2=\NqtYTako + 0.25 * \NvtYTako *\dT /\stepC;
\variFuji3=\NvtXTako + 0.25 * \NatXTako * \dT /\stepC;
\variFuji4=\NvtYTako + 0.25 * \NatYTako * \dT /\stepC;
\NatXTako = \funcAccelMX{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
\NatYTako = \funcAccelMY{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
%
\NvthXTako = \NvtXTako + 0.5 * \dT / \stepC * \NatXTako;
\NvthYTako = \NvtYTako + 0.5 * \dT / \stepC * \NatYTako;
%
%
%%1ステップ後の速度を計算するよ
\variFuji1=\NqtXTako;
\variFuji2=\NqtYTako;
\variFuji3=\NvtXTako;
\variFuji4=\NvtYTako;
\NatXTako = \funcAccelMX{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
\NatYTako = \funcAccelMY{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
%
\variFuji1=\NqtXTako + 0.5 * \NvtXTako *\dT /\stepC;
\variFuji2=\NqtYTako + 0.5 * \NvtYTako *\dT /\stepC;
\variFuji3=\NvtXTako + 0.5 * \NatXTako * \dT /\stepC;
\variFuji4=\NvtYTako + 0.5 * \NatYTako * \dT /\stepC;
%%
\NatXTako = \funcAccelMX{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
\NatYTako = \funcAccelMY{\variFuji1}{\variFuji2}{\variFuji3}{\variFuji4};
%%
\NvtXTako = \NvtXTako + \dT / \stepC * \NatXTako;
\NvtYTako = \NvtYTako + \dT / \stepC * \NatYTako;
%%位置座標の計算をするよ。
\NqtXTako = \NqtXTako + \NvthXTako * \dT / \stepC;
\NqtYTako = \NqtYTako + \NvthYTako * \dT / \stepC;
}
計算結果代入
%サルの位置
\global\edef\variXCdMonkey{\NqtXTako}%次の初期値を定める
\global\edef\variYCdMonkey{\NqtYTako}%次の初期値を定める
%サルの速度
\global\edef\variXVelocityMonkey{\NvtXTako}
\global\edef\variYVelocityMonkey{\NvtYTako}
繰り返し計算(ループ)について
カウンターを設置し,カウンターの値を参照して繰り返しを実現します。カウンターの設置とループ部分の2つで構成します。
カウンターの設置
\newcount\countA
ループ部分
\def\stepA{140}%Total Time70
\countA = 0 \loop\ifnum\countA < \stepA%ループ開始
{
%
%ここに繰り返す部分を書く
%
}\advance\countA by1\repeat %ループ終了
\loop``\repeat
の組み合わせで使います。上の例の場合,まず\countA=0
でカウンターにゼロが代入されます。\ifnum\countA < \stepA
では\countA
が\stepA
よりも小さい(条件分岐)ときにして実行されます。この条件を満たさないとき,\loop
ないの処理が終了します。
\advance\countA by1
で,カウンター\countA
に1を足します。\repeat
から\loop
に戻り,再び分岐のふるいにかけます。
このループの中には,\begin{tikzpicture}
による描画と数値計算,\newpage
を入れておきます。
カウンターについてはこちら
https://qiita.com/hironarin/items/2e40bac56a9fee727ed1
パラメータの設置・計算について
数値の代入・計算には\tikzmath
を使います。例えば,
\tikzmath{
real \grav;
\grav = 0.02;
real \MASS;
\MASS = 10;
int \ParNum ;
\ParNum=5; %粒子数
}
real
で実数,int
で整数の変数を設定できます。実数は小数点付きの数値,整数はそのまま。何も宣言しないまま
\tikzmath{ \a = 10;}
と書くと,実数と認識されます。
注意:\tikzmath
の中に空行を入れてはいけません。エラーが出ます。行の最後に;
を書きます。
変数の設置について
初期値を入れたり,計算結果の入出力をするための変数を設置します。設置の方法は,TeXのマクロ作成でおなじみの\def
を使います。\def
は,既にあるマクロを上書きしてくれる性質があるのでちょうどよのです。ただし,ちょっと工夫が必要で,バカの一つ覚えで,次の形で使います。名前のつけ方についてはご容赦ください。
\global\edef\variXCdMonkey{10}%初期値を定める
\global\edef\variYCdMonkey{20}%初期値を定める
もしくは,
\tikzmath{
\NqiXMonkey = 10;
\NqiYMonkey = 20;
}
\global\edef\variXCdMonkey{\NqiXMonkey}%初期値を定める
\global\edef\variYCdMonkey{\NqiYMonkey}%初期値を定める
上の例では2つの変数を定義しています。
ちょっと説明
\def\variable{100}
通常,マクロはコマンドの列として実行されます。数値計算では「数値」を覚えさせたいものです。数値を覚えさせるために\edef
を使用します。たとえば,
\tikzmath{
\Monkey = 10;
}
\edef\variable{\Monkey}
変数を定義するとき,\tikzmath
を使ってもできそうな気がしますが注意が必要です。\loop
内で計算した結果,定義しなおした値は,1回の\loop
内でのみ有効で,1回終わるごとにその数値を忘れてしまいます(たぶんローカル変数)。数値を全体で有効にするために\global
をつけます。
\tikzmath{
\Monkey = 10;
}
\global\edef\variable{\Monkey}
これで,\variable
が上書きされない限りその数値が有効です。
条件分岐について
\ifthenelse
を使います。スタイルファイルの宣言が必要です。
\usepackage{ifthen}
こっちで書いてます
https://qiita.com/hironarin/items/ae62b386dc921cdf38f4
エラーが出たとき疑うこと
Undefined control sequence
と言われた場合は,定義されていないトークンがある
\tikzmath
内に空行がある
\tikzmath
内で;
を書いていない。