blockMeshが予想以上に進化していた！

# はじめに

OpenFOAMでメッシュを作成する場合、OpenFOAM付属のメッシャーとして
- blockMesh
- snappyHexMesh

が利用可能です。 blockMeshは構造格子タイプのメッシュを組み合わせる（すなわち領域をブロッキングする）ことで任意の形状にも対処できるようになっています。しかし、形状が複雑になってくると形状をブロッキングするのは難しいため、複雑な形状は必然的にsnappyHexMeshなどを使いメッシュを作成することになります。このような事情もあって、最近はblockMeshを使用していなかったのですがOpenFOAMの例題を見てみるとblockMeshが想像以上に使い易くなっていたので紹介します

# 形状エンティティに名前をつけることができる

これは、自分が知らなかっただけで以前から存在していた機能かもしれません。現在のblockMeshDict辞書では、vertices、blocksなどに名前を付けてその形状を参照することができます。例えば、二次元のエルボー管の例を示します。

```:blockMeshDict
/*--------------------------------*- C++ -*----------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  v2206                                 |
|   \\  /    A nd           | Website:  www.openfoam.com                      |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version     2.0;
    format      ascii;
    class       dictionary;
    object      blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

// パラメータの定義
nl1   40;
nc    24;
nl2   40;
nw     8;

zmin    -0.2;
zmax     0.2;

width        1.0;
length1      5.0;
length2      5.0;
radius       1.0;
angle        90;

// 頂点（vertex)の座標値の定義
xi1      #eval{ -$length1 };
yi1      #eval{ -$radius };

xi2      #eval{ $xi1+$length1 };
yi2      #eval{ $yi1 };

xi3      #eval{ $radius*sin(degToRad($angle)) };
yi3      #eval{-$radius*cos(degToRad($angle)) };

xi4      #eval{ $xi3+$length2*cos(degToRad($angle)) };
yi4      #eval{ $yi3+$length2*sin(degToRad($angle)) };

xo1      #eval{ -$length1 };
yo1      #eval{ -($radius+$width) };

xo2      #eval{ $xo1+$length1 };
yo2      #eval{ $yo1 };

xo3      #eval{ ($radius+$width)*sin(degToRad($angle)) };
yo3      #eval{-($radius+$width)*cos(degToRad($angle)) };

xo4      #eval{ $xo3+$length2*cos(degToRad($angle)) };
yo4      #eval{ $yo3+$length2*sin(degToRad($angle)) };

//  頂点（vertex)の定義
vertices
(
    name vi1 ($xi1 $yi1 $zmin)
    name vi2 ($xi2 $yi2 $zmin)
    name vi3 ($xi3 $yi3 $zmin)
    name vi4 ($xi4 $yi4 $zmin)

    name vo1 ($xo1 $yo1 $zmin)
    name vo2 ($xo2 $yo2 $zmin)
    name vo3 ($xo3 $yo3 $zmin)
    name vo4 ($xo4 $yo4 $zmin)

    name vi1e ($xi1 $yi1 $zmax)
    name vi2e ($xi2 $yi2 $zmax)
    name vi3e ($xi3 $yi3 $zmax)
    name vi4e ($xi4 $yi4 $zmax)

    name vo1e ($xo1 $yo1 $zmax)
    name vo2e ($xo2 $yo2 $zmax)
    name vo3e ($xo3 $yo3 $zmax)
    name vo4e ($xo4 $yo4 $zmax)

);

blocks
(
    name inblk   hex (vi1 vo1 vo2 vi2   vi1e vo1e vo2e vi2e) ($nw $nl1 1) grading (1 1 1)
    name crvblk  hex (vi2 vo2 vo3 vi3   vi2e vo2e vo3e vi3e) ($nw $nc  1) grading (1 1 1)
    name outblk  hex (vi3 vo3 vo4 vi4   vi3e vo3e vo4e vi4e) ($nw $nl2 1) grading (1 1 1)
);

edges
(
    arc  vi2  vi3  origin (0 0 $zmin)
    arc  vo2  vo3  origin (0 0 $zmin)

    arc  vi2e vi3e origin (0 0 $zmax)
    arc  vo2e vo3e origin (0 0 $zmax)

);

defaultPatch
{
    name empty;
    type empty;
}

boundary
(
    walls
    {
        type    patch;
        faces
        (
            (inblk 0)
            (inblk 1)
            (crvblk 0)
            (crvblk 1)
            (outblk 0)
            (outblk 1)
        );
    }

    inlet
    {
        type    patch;
        faces   ((inblk 2)); //      faces   ((0 4 12 8));
    }

    outlet
    {
        type    patch;
        faces   ((outblk 3)); //      faces   ((7 3 11 15));
    }
);


// ************************************************************************* //
```

このblockMeshDictを使い作成したメッシュは以下のようになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/69bd5572-1c97-c560-fd45-60c328145bb0.png)

verticesの記述を見ると (x,y,z)座標値の前に名前が追加されているのがわかります。例えば
以下の例ではvi1という名前で頂点を定義しています。
```
vertices
(
    name vi1 ($xi1 $yi1 $zmin)
    ...
```

またブロックの定義では、頂点名を参照して新しくinblkという名前のブロックを作成していることがわかります
```
blocks
(
    name inblk   hex (vi1 vo1 vo2 vi2   vi1e vo1e vo2e vi2e) ($nw $nl1 1) grading (1 1 1)
    ...
```
場合によっては、エンティティを定義する際に、数字ではなく名前を使うようにしたほうがわかりやすいかもしれません。


# 面（face)を定義する際に、ブロック名＋面番号が使用できる

境界面を定義する場合、面を構成する４頂点を指定しますが、代わりの方法としてブロック名（あるいはブロック番号）と面番号を定義する方法も使用できます。ここで面番号とはブロックを構成する６面に対して定義されるものであり、頂点の並びに従って自動的に場所が特定されます。マニュアルを見ればこの規約が書かれていると思いますが、blockMesh -help と実行することで、以下のようにヘルプメッセージとして図示することが可能です（f0～f5が面番号）。ブロックの８頂点にかかれている数字がブロック構成頂点番号です。

```
blockMesh -help
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/21ed2b74-464d-5bf4-3e9a-a8b26ccb0079.png)

上に示したblockMeshDictの例だと境界面の定義は以下のようになっています。なお、従来の方法に従い４頂点の並びで面を定義しても構いません（混在も可）。面番号を使えば、境界上の頂点並び順を気にしなくてもよいため、わかりやすいかもしれません。

```
boundary
(
    walls
    {
        type    patch;
        faces
        (
//          (ブロック名あるいはブロック番号  面番号）
//          以下の inblkは最初に定義されたブロックなのでブロック番号＝0としても可
            (inblk 0)
            (inblk 1)
            (crvblk 0)
            (crvblk 1)
            (outblk 0)
            (outblk 1)
        );
    }

    inlet
    {
        type    patch;
        faces   ((inblk 2)); //      faces   ((0 4 12 8));
    }

    outlet
    {
        type    patch;
        faces   ((outblk 3)); //      faces   ((7 3 11 15));
    }
);
```

# 頂点番号を図表示することができる

blockMeshコマンドを実行する際に -write-vtk オプションを指定することでblockMeshDictのブロッキング定義状態を可視化することができます。実際に図を見てもらったほうがわかりやすいかと思いますので以下に示します。

```
blockMesh -write-vtk
```
これにより blockTopology.vtuおよび blockFaces.vtp という名前のファイルが作成されます。paraviewを起動し、blockTopology.vtuファイルを読み込みます。次にすべての表示セルを選択します。その後、find dataボタンを押し、 cell ID、point ID を表示するように指定します。

すべての表示セルを選択（予めワイヤーフレーム表示にしておく）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/8626b2ac-51ea-9a61-bb98-f527afb9a9d0.png)

find dataボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/2751b033-facc-79fc-a6cc-55329c82b9cf.png)

cell ID、point ID を表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/8e62e612-1a9d-fe28-bcd0-4cfb2c832640.png)

頂点番号（黄色）、ブロック番号（緑色）が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/63bca886-1097-38ea-0968-96d67b192f96.png)

参考までに頂点名で表示した図も示しておきます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/af0d2ac0-78ca-bfe9-e02d-87f1fa2a91f6.png)

# ブロックの配置方向を矢印で表示できる

ブロックには頂点配置により配置方向が決まります。この配置方向をベクトル図として表示することができます。

ベクトル表示ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/4418c3ea-1ade-b16a-cea6-cdcd8f095c8e.png)

ベクトルを適当に選ぶ（ここではlocal-direction0)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/0ad6438c-4e98-1962-f666-c1797a3fcac0.png)

第一ベクトル方向が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3334763/25e7164b-04df-fd13-f774-1f5c7ab4732f.png)


このように図示することでブロックの方向（および面の位置）が容易に把握できるようになります。

# まとめ

blockMeshを便利に使うためのいくつかのtipsを紹介しました。何らかの参考になれば幸いです。