Pythonを用いたOpenFOAMの波高計設置スクリプトの作成

# はじめに
造波・吸収機能を有するOpenFOAMのソルバである[OlaFlow](https://olaflow.github.io/)では波高計を設置することができます。

設置方法の例はこんな感じです。
ここでは、３つの波高計を設置しており、それぞれの始点・終点を設定しています。

<details>
<summary>controlDictの中身はこちら</summary>

```c++:system/controlDict
/*---------------------------------------------------------------------------*\
| =========                 |                                                 |
| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
|  \\    /   O peration     | Version:  1.3                                   |
|   \\  /    A nd           | Web:      http://www.openfoam.org               |
|    \\/     M anipulation  |                                                 |
\*---------------------------------------------------------------------------*/
FoamFile
{
    version         2.0;
    format          ascii;
    location        "system";
    class           dictionary;
    object          controlDict;
}

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

application     olaFlow;

startFrom       latestTime;

startTime       0;

stopAt          endTime;

endTime         1;

deltaT          0.01;

writeControl    adjustableRunTime;

writeInterval   0.2;

purgeWrite      0;

writeFormat     ascii;

writePrecision  6;

compression     off;

timeFormat      general;

timePrecision   6;

runTimeModifiable yes;

adjustTimeStep  yes;

maxCo           0.5;
maxAlphaCo	    0.5;
maxDeltaT       1;
functions
{
     Hakoukei
     {
         type    sets;
         libs ("libsampling.so");
         writeControl    adjustableRunTime;
         writeInterval   0.02;
         setFormat       raw;
         surfaceFormat   raw;
         interpolationScheme cell; //cellPointFace
         fields          ( alpha.water );
         sets
         (
              Hakoukei01
              {type    face; axis    xyz; start   ( 3 -0.05 -0.3 ); end     ( 3 -0.05  0.3 );}
              Hakoukei02
              {type    face; axis    xyz; start   ( 5 -0.05 -0.3 ); end     ( 5 -0.05  0.3 );}
              Hakoukei03
              {type    face; axis    xyz; start   ( 7 -0.05 -0.3 ); end     ( 7 -0.05  0.3 );}
         );
     }

}


// ************************************************************************* //

```
</details>

波高計の設置自体はカンタンですね！すごい！

しかし、時にはたくさんの波高計を設置したい時もあると思います。
- 例えば、斜面上の遡上波を計測するために等間隔に複数の波高計を設置するなど。※1

設置する波高計が50個、100個、、、となるとcontrolDictに書き込む作業が辛いですね。
ちなみに[waves2foam](https://openfoamwiki.net/index.php/Contrib/waves2Foam)では、手作業で書き込まずに、２つの波高計の設置座標を決め、その間に任意の数だけ波高計を設置できるような便利な機能があります。

そんな便利な機能があったら、olaFlowでの波高計設置はもっとカンタンになるはず！
しかし、見つけることができなかった。。


※1：波高計を斜めに設置した場合、波高計で計測した遡上波は可視化した結果と比べると小さくなっていた記憶があります。ただ、waves2foamで検証した時の話かも、、、

# 目的
controlDictに手作業で波高計の座標を定義しなくてもいいようにする。

## 作りたいもの
- 波高計の座標を生成を自動化するPythonスクリプト

inputする情報
- 波高計の鉛直長さ：h
- 設置したい波高計の数：N
- 1個目の波高計のxyz座標
- N個目の波高計のxyz座標 

outputするもの
- 波高計の設定を定義したcontrolDict

イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3831763/36da62e9-d051-4eef-8324-c8eef175c097.png)

# 方法
まずは、controlDictの波高計の定義部分を分離しました。
ファイル構成はこんな感じです。
~~~
system/
│── controlDict
wave_gauge/
│── Hakoukei_controlDict
│── Hakoukei_sets
~~~

<details>
<summary>controlDictの中身はこちら（変更点周辺を抜粋）</summary>

```c++:system/controlDict
maxCo           0.5;
maxAlphaCo	    0.5;
maxDeltaT       1;
functions
{
    #includeIfPresent "../wave_gauge/Hakoukei_controlDict";
}
```
</details>

<details>
<summary>wave_gauge/Hakoukei_controlDict</summary>

```c++:wave_gauge/Hakoukei_controlDict
Hakoukei
     {
         type    sets;
         libs ("libsampling.so");
         writeControl    adjustableRunTime;
         writeInterval   0.02;
         setFormat       raw;
         surfaceFormat   raw;
         interpolationScheme cell; //cellPointFace
         fields          ( alpha.water );
         
         #includeIfPresent "../wave_gauge/Hakoukei_sets";
     }
```
</details>

今回はPythonスクリプトを作成し、wave_gauge/Hakoukei_setsを作成することをゴールにします。
inputの情報が以下のような場合、wave_gauge/Hakoukei_setsの中身は以下のようになる想定です。

inputする情報
- 波高計の鉛直高さ：h = 0.6
- 設置したい波高計の数：N = 3
- 1個目の波高計のxyz座標：( 3 -0.05 -0.3 )
- N個目の波高計のxyz座標：( 7 -0.05 -0.3 ) 

<details>
<summary>wave_gauge/Hakoukei_sets</summary>

```c++:wave_gauge/Hakoukei_sets
sets
         (
              Hakoukei01
              {type    face; axis    xyz; start   ( 3 -0.05 -0.3 ); end     ( 3 -0.05  0.3 );}
              Hakoukei02
              {type    face; axis    xyz; start   ( 5 -0.05 -0.3 ); end     ( 5 -0.05  0.3 );}
              Hakoukei03
              {type    face; axis    xyz; start   ( 7 -0.05 -0.3 ); end     ( 7 -0.05  0.3 );}
         );

```

</details>

# 作ってみる
今回はtomlファイルに波高計のinput情報を記載し、pythonスクリプトをdockerコンテナ内で実行することによりHakoukei_setsを作成します。

tomlファイルは以下のような感じです。
```toml:/usr/local/bin/set_wavegauge.toml
[Hakoukei]
h = 0.6
N = 3
start = [3,-0.05,-0.3]
end = [7,-0.05,-0.3]
```

Hakoukei_sets作成スクリプトは以下のような感じです。
```python:/usr/local/bin/set_wavegauge.py
import tomli

file_toml = (
    "/usr/local/bin/set_wavegauge.toml"
)

# TOML ファイルを読み込む
with open(file_toml, "rb") as f:
    config_toml = tomli.load(f)

# 設定値を取得
h = config_toml["Hakoukei"]["h"]
N = config_toml["Hakoukei"]["N"]
start = config_toml["Hakoukei"]["start"]
end = config_toml["Hakoukei"]["end"]


# x座標をN等分

diff = (end[0] - start[0]) / (N - 1)
x_values = [start[0] + i * diff for i in range(N)]
print(x_values)

output = "sets\n(\n"
for i, x in enumerate(x_values, start=1):
    output += f"""    Hakoukei{i:02d}
    {{
        type    face;
        axis    xyz;
        start   ( {x} {start[1]} {start[2]} );
        end     ( {x} {end[1]} {start[2] + h} );
    }}\n"""
output += ");\n"

# ファイルに書き込む
with open("/root/OpenFOAM/-v2012/applications/utilities/olaFlow/tutorials/mybaseWaveFlume/wave_gauge/Hakoukei_sets", "w") as f:
    f.write(output)

```

コンテナ内でスクリプトを実行します。
```:コンテナ内で実行
python3 /usr/local/bin/set_wavegauge.py
```

実行結果です。
```
sets
(
    Hakoukei01
    {
        type    face;
        axis    xyz;
        start   ( 3.0 -0.05 -0.3 );
        end     ( 3.0 -0.05 0.3 );
    }
    Hakoukei02
    {
        type    face;
        axis    xyz;
        start   ( 5.0 -0.05 -0.3 );
        end     ( 5.0 -0.05 0.3 );
    }
    Hakoukei03
    {
        type    face;
        axis    xyz;
        start   ( 7.0 -0.05 -0.3 );
        end     ( 7.0 -0.05 0.3 );
    }
);

```
いい感じ！！

# まとめ
OpenFOAMの計算を少し工夫するPythonスクリプトを作ってみました。

そろそろ越波の計算してみたいなぁ