dynamicsoar's log

主に研究関係のメモ

mintty (Cygwin) + tmux で、Ctrl-Tab, Ctrl-Shift-Tab で cycle windows する

Stack Overflow のエントリとか、いろいろ探したけど、結局 mintty 公式の wiki に書いてあった…:

要するに、

  1. mintty 上で右クリックして Options... > Keys で、Switch window を untick する(Ctrl-Tab, Ctrl-Shift-Tab がこれを使っているため。知らなかった…)。
  2. ~/.tmux.conf に、上のリンク先に書いてあるとおりのコードをコピペして保存する。
  3. tmux を起動する。Window をいくつか開くと、Ctrl-Tab, Ctrl-Shift-Tab で cycle できるようになっている。便利!

いちおうコードをコピペしておくと、

set -s user-keys[0] "\e[1;5I"
set -s user-keys[1] "\e[1;6I"
bind-key -n User0 next-window
bind-key -n User1 previous-window

Measurement of time-varying kinematics of a dolphin in burst accelerating swimming

基本情報

内容のまとめ

Introduciton

イルカの遊泳は、巡航の速度計測はけっこうあったが、瞬間的な加速の計測は少なく、とくに尾ビレによるストロークごとの詳細の計測はあまりなかった。

Methods

Smoothing

The time series of the obtained 3-D coordinates were smoothed using a weighted 91-point weighted moving average with Hamming window designed to impose a 15 Hz cut-off frequency to eliminate noise due to the manual tracking.

前に加賀屋さんと少し議論したけれど、ここでは「マニュアルトラッキング(特徴点を時系列にポチポチとマウスでクリックする)によるノイズの除去のためにまずスムージングをしている。それから、1階と2階の2次中心差分(中央差分)を使って速度と加速度をそれぞれ求めている。ただし、時系列点の水増しはしていないのと、中心差分に普通は i-1, i+1 を使うところ敢えて i-2, i+2 を使っている(さらにスムースにするため、とされている)。

3D geometry

Fig. 4 のあたりで、正直に「スキャンした形状はこんなグニャグニャだったので、こうやって整形しました」ということを説明している。実際にはCTしたものそのままなんてCFDできるわけはなく*1、必ず整形が入るのに、その過程を詳細に記述している論文は非常に少なく感じられる。個人的な印象に過ぎないと言われればそうかもしれないが…。

Results

Discussion

コメント

*1:FEMならまだ良いのかもだが。

Standalone ANSYS Fluent launched directly from Windows is (slightly?) different from Fluent launched from WorkBench

English

I've been thinking they are identical and have never launched the standalone Fluent, but no, they are not. At least in a few ways.

I was doing a tutorial on VOF + dynamics + dynamic mesh (fl00392). And I stumbled upon that in Autosave I could not find the File Name entry field at all. I googled and found out this page: https://www.eureka.im/4622.html . I know obviously this is one of the fishy web sites, but that doesn't matter this time. What matters here is:

In the stand alone FLUENT 12, we will see the file name option.

What!? Is it different from the Fluent launched from WorkBench (WB)? Oh it must be simply because it was ancient version 12, whereas we now live in the version 18, 19, or 2019. Let me see... (closed the WorkBench launched the Fluent 19.1 from Windows Start Menu...) Oh, dear, this is different!

  • You can specify the root-name for Autosave. If you're familiar with standalone Fluent, you may think "Oh, even in the WB Fluent, you should be able to specify the root-name via TUI." NO. Even in the TUI, the /file/auto-save shows only four commands and "root-name" is missing in the WB Fluent. So obviously what we usually use on clusters (supercomputers) are standalone Fluent as they allow us to specify root-name.
  • If you're familiar with WB Fluent, you know that it's not Read/Write from File menu but it's Import/Export which are the commands for case and data files, even though the journal file commands are read-case-data and write-case-data. However, in the standalone Fluent, they indeed are called Read/Write. Wow.
  • I'm pretty sure there will be many other differences, some of which might be important.
  • I still cannot find the "Specific Dissipation Rate (omega)" in the Data File Quantities even in the standalone Fluent. Probably a bug?

So... be careful guys.

Japanese

WorkBench (WB) から立ち上げた Fluent と Windows から直接立ち上げた Fluent は同じものだと思っていたが、実は少し違った。たとえば、autosave するときの root-name(foo-001.dat みたいなやつの foo の部分)を WB Fluent ではなぜか指定できない(TUIから行ってもコマンド自体がない)のに対して、standalone Fluent では指定できる。他にも一部メニューが違ったりするのは確認した。なんかいろいろと違うことが他にもありそうで、やめてほしい…

ANSYS Fluent の UDF についての自分用メモ

NB! Dynamic meshing については別の記事に分けている: Dynamic meshing in Fluent - dynamicsoar's log

UDFマニュアル*1は基本的に version 19.2 を参照しているが、たまに18.1も見ている(あまり変わらないと思うが…)

定義の確認

macro

個別の関数のことを function と呼ばず macro と呼んでいるようだ(とくに説明はない…)。

thread とは何か?

CPUとかそういう thread とは関係ない。 GUIでは一度も thread という言葉が出てこないので、UDFを始めて「これは何???」となった。UDFマニュアルの 1.6. Mesh Terminology によると、

A thread is a data structure in ANSYS Fluent that is used to store information about a boundary or cell zone. Cell threads are groupings of cells, and face threads are groupings of faces. Pointers to thread data structures are often passed to functions and manipulated in ANSYS Fluent to access the information about the boundary or cell zones represented by each thread. Each boundary or cell zone that you define in your ANSYS Fluent model in a boundary conditions dialog box has an integer Zone ID that is associated with the data contained within the zone. You will not see the term "thread" in a dialog box in ANSYS Fluent so you can think of a "zone" as being the same as a "thread" data structure when programming UDFs.

ゾーンと思っておけばいい、とある。具体的な例を挙げないとわからないよなぁ…。たとえば、翼まわりの流れ場の計算をするとする。そういうとき、翼表面には名前を付けて、すべりなし境界条件の設定をしたり、揚力・抗力等の算出対象として指定したりするだろう。この場合、「名前がついた翼表面」こそが face zone であり、thread となる。表面ではなく体積を対象とする場合は cell zone であり、やっぱり thread である…ということ。UDFのソースコードで thread にアクセスするときはポインタを使う。Thread の ID は、Fluent の Boundary Conditions と Cell Zone のところにあるIDというやつ…だと思う。ところでこれは Surface の ID とは違うようだ…。

Thread へのポインタは、DEFINE_GRID_MOTIONの場合は、Fluent側から渡される dt というポインタを使って、Thread *thread_pointer = DT_THREAD(dt); で得ることができる。一方で、thread ID はわかっているが dt のようなポインタが Fluent 側から渡されない場合(DEFINE_ON_DEMANDのように)は、Thread *thread_pointer = Lookup_Thread(domain_pointer, zone_ID); とすればよい。

その他によく出てくるのは、

  • Domain: 2相流では2つ、単相流なら1つとあるので、単相流だけやってる間は「ぜんぶ」と思っておけば良さそう。Domain へのポインタは Domain *domain_pointer = Get_Domain(domain_id); で得ることができるが、domain の ID はなにかというと、

    In the case of single-phase flows, domain_id is 1 and Get_Domain(1) will return the fluid domain pointer.

    とあるので、単相流だと1固定らしい。

  • SVar: まだよくわかってない

また、

Note that a face ID or cell ID by itself does not uniquely identify the face or cell. A thread pointer is always required along with the ID to identify the thread to which the face (or cell) belongs.

とのことで、あらゆる face, cell へのアクセスは thread ポインタも指定しないと行えないということのようだ。たとえば、「入口境界threadを指定して、さらにface IDを指定する」というように使うと思われる。

thread_loop_c, thread_loop_f

Domain 内のすべての cell/face をループするという便利な関数。 Section 1.7 には thread_c_loop, thread_f_loop というのがあるが、これらはここにしか出てこないのでおそらく間違い…?

SET_DEFORMING_THREAD_FLAG

UDF マニュアルにも User's Guide にも明確な記述がない。ひどい。かろうじて、マニュアル内のサンプルコードに下記の記述がある:

/* set deforming flag on adjacent cell zone */
    SET_DEFORMING_THREAD_FLAG(THREAD_T0(tf));
/**
* Set/activate the deforming flag on adjacent cell zone, which
* means that the cells adjacent to the deforming wall will also be
* deformed, in order to avoid skewness.
*/
SET_DEFORMING_THREAD_FLAG (THREAD_T0 (thread));

というわけで、どうやら「隣接するセルゾーンを自動的に Deforming に変更する」ようだ。こんな重要そうなフラグのセットをする関数なのに独立した説明がなくてサンプルコード内のコメントが唯一の情報って…。

dt と dtime

UDFの世界では、dt は「時間刻み」ではない。それは dtime と呼ばれる。dt は dynamic thread を意味する。なんて紛らわしいんだ…。

DEFINE_GEOM と DEFINE_GRID_MOTION は何が違うのか

Dynamic meshing in Fluent - dynamicsoar's log

NV_S, NV_V, NV_D など

とんでもないことに、これらいくつか(たくさん)のマクロはマニュアルに定義の説明がない。オープンソースだったとしてもそれはないでしょというところ、これ商用ソルバだよねと思うと、ちょっとどうなってんのという…。以下のマクロは、ほとんどがサンプルコードの中にだけ存在を確認できる*2。したがってここに記す説明はほぼ全て「たぶんこうだろう」と推測したもの。

  • NV_VEC(foo) は演算ではなくて宣言用で、「foo という vector 変数を宣言する」。ここでいう vector とは一般的な数学的なベクトルではなくて、3次元のベクトル(位置や速度など)。
  • NV_S は「vector 変数に対して1つの scalar でなにかの演算をする」。
  • NV_V は「vector 変数に対して1つの vector(成分指定でない)でなにかの演算をする」。
  • NV_D は「vector 変数に対して1つの vector(3成分を全て指定する)でなにかの演算をする」。
  • NV_VS は「vector 変数に対して1つの vector(成分指定でない)と1つの scalar でなにかの演算をする」。
  • NV_VV は「vector 変数に対して2つの vector でなにかの演算をする」。
  • NV_DS は「vector 変数に対して1つの vector(3成分を全て指定する)と1つの scalar でなにかの演算をする」。
  • NV_DD は「vector 変数に対して2つの vector(3成分を全て指定する)でなにかの演算をする」*3
  • NV_V_VS は「vector 変数に対して2つの vector(成分指定でない)でなにかの演算をする。ただし後者の vector には scalar 演算を先にする」*4
  • NV_VS_VS は「vector 変数に対して2つの vector(成分指定でない)でなにかの演算をする。それぞれの vector には scalar 演算を先にする」*5

このうち、NV_V, NV_VV, NV_V_VS, NV_VS_VS の4つだけは 3.4.3 で説明されている。どうやら NV_VD だとか、NV_V_DS といったものはないか、少なくともマニュアルには出てきていないようだ。

こうしてみるとどうやら傾向がわかってくる。Sはスカラー・Vはベクトルというのはいいとして、Dは「ベクトルだが3成分を(関数呼び出し時に)指定する」ということのようだ。D は direction だろうか?実際には単位ベクトル以外も使われているので違うかな…。「なにかの演算をする」というのは、基本的には単なる代入(=)が多いようだが、+=とか/=とかもされていることはあるので、要するにそういうのができるってこと。

THREAD_N_ELEMENTS_INT も定義ないなぁ…明らかに、「スレッドのポインタを引数にとって、そのスレッドの要素数を返す」だけなんだけど、おそらくセルのスレッドを食わせたらセルの個数を、表面を食わせたら face の個数を返す…のだと思う。いやいや、こんな、「だと思う」とか推測しなきゃいけないのおかしいだろ。商用ソフトが。⇒ 実際やってみたら、やはりそのとおり(セルならセルの個数、表面なら face の個数)だった。

マクロ(関数)の引数の単位

どうやら自動的に単位系は SI であると解釈するようなので、必ずSIにしてから渡さないといけない、っぽい。特に自分はミリメートルの世界を扱う事が多い(昆虫とか)ので、メートルに直すのを忘れそうで注意しないと。

I/O

UDF manual の A. 13.3. Standard I/O Functions に書いてある。fopen などが使えるが scanf は使えない、とか。また、stdio.hudf.h に含まれているので、#include "udf.h" のみで十分で、#include "stdio.h" は不要らしい。

書き方

Section 2.1 の Important というコラム:

You must place all of the arguments to a DEFINE macro on the same line in your source code. Splitting the DEFINE statement onto several lines will result in a compilation error.

こんなことするやついるの?って思うかもしれないが、自分は Fortran のときにこれをやるので、「ダメだよ」って書いてなかったらハマったかもしれない。

Make sure that there are no spaces between the macro (such as DEFINE_PROFILE) and the first parenthesis of the arguments, as this will cause an error in Windows.

マクロ名はいいとして、「マクロ名直後の最初のカッコの前にも半角スペースを置いてはいけない」のは割とハマりそう。

Do not include a DEFINE macro statement (such as DEFINE_PROFILE) within a comment in your source code. This will cause a compilation error.

コメントでも書いてはいけないとか普通思わないだろ…まじか…。

DEFINE_ON_DEMAND を使う

おそらくこれが最もプレーンというか一般的なマクロと思われる。Compile → Load までは他のマクロの場合と同じだが、メニューの Execute on Demand... から直接(1回だけ)実行する点が他と違う。したがって、テストなどに便利と思われる。ただし注意事項として、Fluent 側から何も情報が渡されない。多くのマクロでは domain のポインタや、場合によっては現在時刻・スレッド(たとえば「翼表面」とか)などが渡されることが多いが、DEFINE_ON_DEMAND は何も渡されないので、全部自分で取得する必要がある。具体的には、ドメインのポインタを取得するには Get_Domain(domain_ID) を使い、スレッドのポインタを取得するには Lookup_Thread(domain_pointer, zone_ID) を使う。たとえば、コードの冒頭はこんな感じになる:

#include "udf.h"

DEFINE_ON_DEMAND(this_is_udf_name)
{
  int domain_ID = 1; // Always 1 for single phase domain
  Domain *domain_pointer; // Declare domain pointer
  domain_pointer = Get_Domain(domain_ID); // Get the pointer to the domain

  int zone_ID = 6; // or whatever you want to use. Happened to be 6 is the wing surface in my case.
  Thread *thread_pointer; // Declare thread pointer
  thread_pointer = Lookup_Thread(domain_pointer, zone_ID); // Get the pointer to the thread
  //---------------------------------------

  Message0 ("Test DEFINE_ON_DEMAND\n");
  Message0 ("domain_ID      = %i\n", domain_ID);
  Message0 ("domain_pointer = %p\n", domain_pointer);
  Message0 ("zone_ID        = %i\n", zone_ID);
  Message0 ("thread_pointer = %p\n", thread_pointer);
}

…というわけでこれ便利だな、と思っていた時期がおれにもありました。しかし致命的な欠点が… NODE_POS_NEED_UPDATE(node_pointer)DEFINE_GRID_MOTION でしか使えない!(と思われる。他にも使えないマクロがありそう)。結局、メッシュ関係の作業をする場合は DEFINE_GRID_MOTION を使った方がいいですねという結論。まぁこういうのを使わないなら ON_DEMAND でいいんだけど。

Journal での実行
  • /define/user-defined/execute-on-demand コマンドを実行すると、Execute on demand function name ["none"] と聞かれるので…
  • "udf name::library name" と入力する。ダブルクォートとコロン2つは必須。
    • udf name は、自分でつけたUDF名。具体的には、Cコードの DEFINE_ON_DEMAND(ここ) ←ここに書いた名前。
    • library name は、コンパイル後のディレクトリ名。デフォルトでは libudf になっている。
  • すると DEFINE_ON_DEMAND の内容が1度だけ実行される。

*1:正式には ANSYS Fluent Customization Manual だが、長いので個人的に勝手にUDFマニュアルと呼んでいる。まぁわかるでしょ…。

*2:というか、サンプルコードにすらなかったらユーザとしては存在すら知れないわけで、実はそういう「仕様上は存在するけどアンシスの人しか知らないマクロ」がたくさんあっても、もう驚かないわ…。

*3:なんと704ページあるPDFの中で、サンプルコードのたった1箇所にしか出てこない。

*4:サンプルコードには出てこない。

*5:サンプルコードには出てこない。

Dynamic meshing in Fluent

NB! UDF全般に関する事項は別記事に分けている: ANSYS Fluent の UDF についての自分用メモ - dynamicsoar's log

Dynamic Mesh

  1. Setup > General > Transient
  2. Setup > Dynamic Mesh > tick "Dynamic Mesh"
  3. Setup > Dynamic Mesh > "Create/Edit..."

Smoothing, Layering, Remeshing の3手法あり、相互に排他的ではなく併用可能。基本的には Smoothing と Layering で対処するが、メッシュの変形が大きすぎる場合は Remshing を使ってメッシュ品質を維持することになる。しかし、Remeshing が発生すると時間精度が1次までに制限される(Smoothing と Layering は2次)ので注意が必要。

Smoothing

Node の数を変えずに、位置のみ動かす方法のこと。まずこれを smoothing と呼ぶのが非常にわかりづらくて、マニュアル見るまで意味わかってなかった。Deformation の方がわかりやすくないか…?

メッシュスムージングでは,一般に回転よりも平行移動による境界運動の方がはるかに良好な結果を得ることができる.

とのこと。

  • Spring/Laplace/Boundary Layer
  • Diffusion
  • Linearly Elastic Solid

の3つの方法がある。

Diffusion か Solid で周期運動の場合は、TUI から基準位置を指定することで、サイクル間のメッシュ品質の一貫性を向上できるらしい。

Spring 以外は複数回 UDF を call する(可能性がある)!

UDF マニュアルをよく見ると(なぜか DEFINE_CG_MOTION のところに…)書いてあるのだが、smoothing の手法によって(具体的には spring 以外の場合、だと思う)、UDF が複数回(ていうか2回?)call されることがある。したがって、「現在の位置に+で速度かけるタイムステップを移動量として加える」みたいなことをやってると、実際よりも多く変形してしまう、という危険性がある。そのため、

NV_D( NODE_COORD(np), +=, dr);

というように増分をインクリメントするよりも、

NV_D( NODE_COORD(np), =, new_r_vec);

のように座標の絶対値を直接代入した方がよい。

Spring/Laplace/Boundary Layer

メッシュの node 間をつなぐ edge をバネとみなして、移動境界により変形するバネ群の釣り合いを反復計算によりで解いて、メッシュ位置を求める。Diffusion 法に比べると高速だが低品質で、基本的に tetra mesh にしか使えない(使うべきではない)。下の "Parameters" で、"Spring Constant Factor" から "Laplace Node Relaxation" までが有効になる。

Spring Constant Factor はデフォルトが1だが、これだと node が物体境界を超えることがあるらしい…(そういう図がマニュアルに載っている。どうみてもダメすぎる)。0だとそれはない。ということは基本は0から始めて小さめの値を目指すべきか。実際、チュートリアルでは 0.3 にしろとある。

Spring は tetra/triangle mesh 向きで、デフォルトでは "Elements" が "Tet in Tet Zones" になっている。もし tetra 以外も変形させたい場合は "All" を選べるが、多面体では特定の条件の下でないと「バネ」の仮定がうまくいかずにセルが大きく歪むことがあるらしい(条件はマニュアルに書いてある)。したがって、tetra 以外(多面体)には Diffusion が推奨されるとのこと。

Diffusion

拡散方程式を解いてメッシュを決める。Spring 法に比べると、計算負荷が高いが高品質。

下の "Parameters" で、"Diffusion Function" と "Diffusion Parameter" が有効になる。

マニュアルにいきなり

変形境界における境界条件は,メッシュが境界の接線方向に運動するよう定められる(つまり,垂直速度成分は消失する) [English] On deforming boundaries, the boundary conditions are such that the mesh motion is tangent to the boundary (that is, the normal velocity component vanishes)

と書いてある。なんだこれは…?意味が分かりづらいが、さすがに流れの境界条件を勝手に変えるという意味ではないと思うので、メッシュ (node) 位置を決めるための「拡散方程式を解くときの境界条件としては」ってことじゃないかと思う。

拡散率の指定には2種類あり、Diffusion Function から選ぶ。

  1. boundary-distance: Diffusion Parameter は 0 から 2 の範囲で指定する(上限は3だが0から2がよいとマニュアルにある)。デフォルトの0だと全体のメッシュが一様に変形する。1など大きくするにつれて、運動している境界付近では初期メッシュ形状が維持されて、運動境界から遠い場所でより大きなメッシュの変形が生じるようになる。回転境界運動の場合は1.5が推奨されている。
    • 標準境界距離(デフォルト):移動境界から最も近い "wall" boundary までの距離に応じて拡散係数が決まる
    • 一般化境界距離(TUIで設定可能):移動境界から最も近い boundary (any type) までの距離に応じて拡散係数が決まる
  2. cell-volume: Diffusion Parameter を1よりも大きくすると、「大きなセルほどより多く変形する(多くの変形を吸収する)」ようになる。なんかこっちの方が良さそうな気がするが、どうかな…。上限は3(それ以上を入れると怒られるので初めて分かる…)。

TUIからいくつかの設定が可能。

  • /define/dynamic-mesh/controls/smoothing-parameters/verbosity を 1 にするとスムージング残差が表示されるようになる
  • /define/dynamic-mesh/controls/smoothing-parameters/max-iteration で最大反復回数を変更できる。デフォルトは30になっている(バージョンによるかも)
  • /define/dynamic-mesh/controls/smoothing-parameters/relative-convergence-tolerance で相対残差許容量を変更できる。デフォルトはマニュアルには1.0e-4とあるが実際には1.0e-10になっていた(バージョンによるかも)。当然こんなに落ちるには多くの iteration が必要になる。適当にやったテスト計算では、30回では1e-5とか1e-7くらいまでしか落ちていないこともあった。もっとも、そこまで smoothing に気を使うよりも、変形が大きいなら remeshing しないとどうしようもないような気もするが…。

境界層 smoothing とは併用できない。

Linear Elastic Solid

メッシュを固体とみなして、境界移動にともなう弾性変形からメッシュ位置を求める(FEMを解くらしい)。下の "Parameters" で、"Poisson's Ratio" のみが有効になる。ポアソン比は -1.0 から 0.5 の間で指定可能。他に、TUIから最大反復回数と相対許容残差が指定できる。

Diffusion より更に計算負荷が高いが、場合によってはより高品質になるらしい。ただし、拡散の場合は距離やセル体積に応じて非一様な分布が実現できたのに対して、こちらは物性値を一定とみなしている。そのためだと思われるが、

回転境界運動と尖った角を伴うケースでは,境界距離に依存する拡散による拡散スムージングを使用した方が有利

とのこと。

これも境界層 smoothing とは併用できない。

Layering (Dynamic Layering)

Remeshing

メッシュを(局所的に or 全体的に)切り直す。Remeshing が発生(発動)すると、時間精度は1次までになってしまう。この時間精度の切替が発生したかどうかを知るためには、

/define/dynamic-mesh/transient-settings/verbosity

を1に設定すること(数字は何でもいいようだが、おそらく0 = OFF かそれ以外 = ON)。

  • Local Cell: tetra のみに効く
    • Local Face: Local Cell にプラスして併用可能なオプション。Local Cell なしにこれだけ選ぶことはできない。境界層メッシュの tetra & wedge に適用
  • Region Face
  • CutCell Zone
  • 2.5D

Local remeshing

ゾーン内のセル全部ではなく、特定のセルで指標(max/min lengthとskewness)が指定の範囲を超えた場合にそのセル付近のみをリメッシングする…のだと思われる。

Local Cell remeshing

おそらく最も基本的なリメッシング法。Max skewness の基準はデフォルトで 3D が 0.9, 2D が 0.7. 変更は可能だが 3D で 0.7 未満を指定すると、実行時に「そんなに小さくするのは非現実的やろ」と言って勝手に 0.7 に直される(先に言えよ…)。

リメッシングが行われるタイミングは2パタンある。Max skewness 基準のリメッシングは全ての時刻ステップに対して行われるが、length 基準の方は、Size Remeshing Interval で選んだ間隔で実行される。デフォルトは5.

基準値 (Parameters) について、version 19.2 の日本語マニュアルでは

Parameters グループボックスの初期値では目的とする結果はまず得られないため,これらのフィールドを編集する必要がある.

といった記述が追加されていた(version 18 ではなかった)。とりあえず Use Default を押せばわりといい感じになるので、そこから初めるのがよいようだ。

Local Face remeshing

Local Cell remeshing を選んだ場合に追加可能なオプション。セルではなく face(面)のリメッシング。

  1. Mesh Methods Settings ダイアログで、 Maximum Face Skewness の値を設定する。
  2. Dynamic Mesh Zones ダイアログで、Deforming または User-Defined の場合、Meshing Options タブの Remeshing Method 欄が選択可能になっているので、Local にチェックを入れて Maximum Skewness を設定する。どうやらここの Local というのは face だけに関係するようだ…?
追加の Local remeshing

というのがあるらしい。TUI で、

/define/dynamic-mesh/controls/remeshing-parameter/remeshing-after-moving?

で設定する。この追加の remeshing では Size Function は無視される。

Size Function

非常に分かりづらいしよくわからないのだが、マニュアルによると、

要約すれば,サイズファンクションは,すべての境界フェース上(静止境界と移動境界の両方)におけるすべてのメッシュサイズの距離加重平均である.

とのこと。

Cell Zone remeshing

Local Cell remeshing を選んだ場合にデフォルトで有効になっている(とあるが、実際には Remeshing を有効にしたらデフォルトで有効になるのでは?)。Local では対処しきれないようなメッシュの過度な変形が生じた場合に自動で発動する。Local とは違い、そのセルゾーン全体(つまり、多くの場合は「空間全部」)をリメッシングする。高品質になるがおそらくものすごく時間がかかるはず。

TUI コマンドで自動発動を無効化できる:

/define/dynamic-mesh/controls/remeshing-parameter/zone-remeshing

逆に手動で発動するには:

/define/dynamic-mesh/actions/remesh-cell-zone

Cell Zone remeshing が発動すると、境界層の wedge メッシュも勝手に適当なパラメタでリメッシュされてしまうようだ。それについて設定したい場合は、

/define/dynamic-mesh/controls/remeshing-parameters/prism-layer-parameters

で first layer thickness, growth rate, number of layers を設定できるらしい(『通常その必要はない』とあるが、なにが通常なんだ?)。

Cell Zone remeshing は triangular, tetrahedral, and wedge のセルにしか適用できないらしい…(あれ?六面体のプリズムは??→どうやらそれには Dynamic Layering を使えよ、ってことっぽい?)

Face region remeshing

もともとピストンエンジンのシリンダ内用に開発されたようで、ピストンが移動した際に、シリンダ内壁面のメッシュが伸びるので、それをきれいにリメッシュする、というのが典型的な使い方のようだ。この場合、ピストン面が移動 zone *1、ピストン内壁は Deforming zone にするようだ。

マニュアルでは、ピストンエンジンの場合、ピストン面とシリンダの間のコーナー領域を含むようにボリューム分解をすることが推奨されている。あるいはコーナーを含まなくてもいいのでピストンとシリンダは分解しろと。そうしないとピストンが大きく移動したときにコーナー付近で潰れがちなのだろう…。

これは今考えている問題(翼の変形)には不要かな…?

CutCell zone remeshing

CutCell ということで6面体になるようだが、リメッシングでテトラからヘキサに変わるってこと…?いまいちよくわからない…。そもそも最初から CutCell でメッシュを生成していた場合はわかるのだが。うまく行けば便利そうだが、まだ発展途上な印象。もちろん単純な(工業的な?)形状に対しては有効なのだろうが。

TUIから、手動で CutCell remeshing を適用できる:

/define/dynamic-mesh/actions/remesh-cell-zone-cutcell

2.5D surface remeshing

六面体メッシュを押出してギアポンプをモデル化するような場合,特に有用

とのことで一般的ではなさそう。

Feature Detection

Dynamic Mesh Zone ダイアログの Geometry Definition タブに Feature Detection というものがある。ここの Include Features をチェックして Feature Angle (deg) をデフォルトの 180 度から下げないと、物体表面などの角が勝手に面取りされてしまう可能性があるらしい…まじかよ。0度にすると面取りを確実に防ぐようだ(が、発散しやすくなるのか?)。ただ、どうも Local Face remeshing では面取りはされなくて、Region Face remeshing のときだけされうるっぽい?そのように書いてあるが、でも Region Face remeshing にチェックを入れてなくてもこの Feature Detection を選べるんだよな…単に不具合で、将来のバージョンでは修正される可能性もあるが*2

Options

Implicit Update

時刻ステップを移動することなしにメッシュ更新を行う。6DOF dynamics や FSI のときに使用可能で、収束を改善する可能性がある。流れ場の情報を使って予測するので、Prescribed motion 時には使用できない。

Update interval はマニュアルの説明だと意味が不明瞭。時間ステップ内の iteration のことを言っている?たとえば max iteration が 20 の場合、2 に設定すると、2, 4, 6, ... iteration のときにメッシュ更新が起きる、のか?

UDFを使用して運動を計算する場合は,運動計算のためのUDFを呼び出すごとに,UDFがその 時点における流れ場を使うようにすること(それ以前に保存された情報を使わないようにする必要がある).このような確認が必要になるのは,メッシュが更新されるごとにUDFが呼び出されるからである.この呼び出しは,Update Intervalの入力内容に応じて,1つの時間ステップ内で何度も行われることがある.

これはかなり重要な情報。

Dynamic Mesh Event

いろいろなイベントを定義できるが、一番使えそうなのは Change Time Step Size と Change Under-Relaxation Factor かな。計算開始初期は発散しやすいので収束を優先し、計算が進んで落ち着いてきたら時間刻みを大きくしたり不足緩和を緩めたりできそうだ。

Execute Command があるので何でもできるのか…?

Replace Mesh というのがある。極端な話、これを使ってすべての時刻のメッシュを読み込むという力技も可能っぽいな…?

UDF

DEFINE_GEOM と DEFINE_GRID_MOTION の違い

これは引数を見たら簡単だった。DEFINE_GEOM には引数に時間 time がなく、DEFINE_GRID_MOTION にはある。つまり GEOM は時間によって不変な形状しか記述できない。したがって、物体の時々刻々の変形を prescribe するには、GRID_MOTION の方を使う。

UDFマニュアル以外だと、チュートリアルの fl00391 がおそらく唯一まともな情報源。

*1:moving dynamic zone とあり、これはおそらく Rigid Body or User-Defined or System Coupling のいずれかのタイプ、という意味での総称と思われる。

*2:実際にこういう細かいUIの変更(改良…と思いたい)はバージョンアップに伴って頻繁に起きている。

manoeuvrability and agility

Manoeuvrability(機動性?)

旋回性能を意味することが多そう。天体で言うと「公転」の方。

おそらく大きく2つに分けられる:旋回半径と旋回率。さらに旋回率は維持旋回率と瞬時旋回率に分けられる、と思われる。

Walker (2000) では先行研究を取り上げて旋回半径を紹介している。

Norberg and Rayner (1987) formally defined maneuverability as the ability to turn in a confined space and have used the lengthspecific minimum radius of the turning path ($r_{path}/L$, where $L$ is total body length) as a measure of this performance. Webb (1994a) has advocated this limited definition of maneuverability for fishes.

-- Walker, 2000.

Agility(敏捷性?)

旋回かどうかにかかわらず、姿勢の変化率を意味することが多そう。天体で言うと「自転」の方。飛行物体で言うとロールレートなど。 あと、並進加速度や加加速度が大きいことも manoeuvrable というよりは agile と呼ぶような気がするけど、微妙/曖昧かも。

Walker (2000) では以下のように文の前半では "reorient the body" とあるのになぜか後半では "suggested turning rate" とありこれは旋回率のことだ。これは誤解しているのか、誤解を招きかねないので不適切だと思う。あるいは Webb (1994a) での定義が曖昧なのかもしれない。

Webb (1994a) defined agility as the ability to quickly reorient the body and suggested turning rate, ω, as a measure of agility.

-- Walker, 2000.

References

  • Norberg, U. and Rayner, J. M. V. (1987). Ecological morphology and flight in bats (Mammalia: Chiroptera): wing adaptations, flight performance, foraging strategy and echolocation. Phil. Trans. R. Soc. Lond. B 16, pp. 335–427.
  • Walker, J. A. (2000). DOES A RIGID BODY LIMIT MANEUVERABILITY? J. Exp. Biol. 203, pp. 3391–3396.
  • Webb, P. W. (1994a). The biology of fish swimming. In Mechanics and Physiology of Animal Swimming (ed. L. Maddock, Q. Bone and J. M. V. Rayner), pp. 45–62. Cambridge: Cambridge University Press.
  • Webb, P. W. (1994b). Exercise performance of fish. In Comparative Vertebrate Exercise Physiology: Phyletic Adaptations (ed. J. H. Jones), pp. 1–49. San Diego: Academic Press.

2018 Leicester helicopter crash の報告書 AAIB Bulletin S2/2018 を読んだ

まえがき

の続き。

ja.wp の記事 の記述では、コッターピンが外れてから溶着とあるが、順番が逆だと思う。

ヨー操舵入力の流れ

まずヨーの操舵入力がどのようにテールロータのピッチ変更を行うか。正直、図を見ないと(見ても)わかりにくいのだが、おそらく以下のようになっている:

操舵入力(ペダル) → 操舵ケーブルの前後運動 (push or pull) → ヘリコプタ尾部のベルクランク → レバー → レバー端のピン(?) → ピンキャリア → コントロールシャフト(レバー側)→(シャフトが押し/引きされる)→ シャフト後端のベアリング → ピッチ変更機構(詳細略)

いくつかポイント

  • 重要なのは「シャフト後端のベアリングのインナーレース」までは、シャフトは長軸周りの回転をせず、前後の押し引きのみが起こるべきである、ということ。
  • 実際にはレバー中央がアクチュエータのソレノイドバルブにつながっていて、フィードバック制御が入るようだが、そこは省略。
  • それから、「レバー端のピン(?)」「ピンキャリア」の部分は大事なんだけど、残念ながら情報が不足しているので、想像が入っている。要するにレバーの回転をシャフトの前後運動に変換するところ。おそらく次のようになっている
    • シャフト端部にはネジが切ってあり、その途中にコッターピン用の穴もある。
    • まずシャフトにピンキャリアという部品を入れる。写真が不鮮明だが、これは要はレバー側とシャフト側の2つの円柱用の穴が空いた部材だろう。両側とも回転はすべりだけで、接合はされないと思われる。シャフト前後方向への並進自由度の制約としては、後ろ側へはおそらくシャフト径で制約していると思われる。前側は入れるために細くないといけないので、キャッスルナット (castlated nut) という特殊なナットをシャフト端部のネジ切り部にはめることで位置を制限している(これは確定)。このように、ピンキャリアとキャッスルナットはお互いに接触はするかもしれないが一体となって回転するものではなく、むしろ独立しているべきである。
    • キャッスルナットというのは、王冠のように縁に凹凸のあるナットで、この凹部とシャフトの穴にコッターピンを通すことで、ナットとシャフトの回転(緩み)を防ぐもの。

事象シーケンス

以上を前提として、事象シーケンスは以下のようになると考えられる(だいたい報告書に書いてあるが一部は推測):

  1. コントロールシャフト後端部のベアリング内外レースが(グリス不良かなにかで)正常に回転しなくなった(数度しか動かない状態)。
  2. 本来はベアリングのおかげで回転しないはずのコントロールシャフトが(テールロータと一緒に)回転し始めた。
  3. シャフト前端部(レバーやアクチュエータの側)では、シャフトと一緒にキャッスルナットも回転し始めた。コッターピンも当然一緒に回転するので、この自転ではせん断破壊しないと思われる。
  4. キャッスルナットと接触していたピンキャリアは、レバーと同じ座標系にいるため非回転。したがって、この2者の接触面が摩擦接合されてしまった。シャフト=キャッスルナットが回転していない通常状態であれば、ピンキャリアは単に前後方向に押されるだけなので、接触しても接合などするはずはなかった(なので間に接合防止部材なども入っていなかったのだろう…というかそんな想像もしなかったかもしれない)。
  5. キャッスルナットがレバー座標系=静止側に固定されてしまい、シャフトと一体回転できなくなったことで、両者をつなぐコッターピンに過剰なせん断応力が生じた。これによりコッターピンの頭部と尾部(端部?)が吹き飛んだ。
  6. シャフトがキャッスルナットおよびピンキャリアから抜け、レバーシステムとの接続が失われた。
  7. 操舵入力がテールロータに伝わらなくなり、ヨー制御が不能となって墜落に至った。

感想

この状況では「コッターピンがせん断破壊されなければ…」という想定は無理がありそう。防ぐべきは第一に後部ベアリングの回転不良だろう。また、キャッスルナットとピンキャリアの間になにか接合を防ぐような部材があれば少しはよかったかもしれないが、長時間の高速回転に耐えられるものだろうか…。

文献