OpenFOAMの設定値を時間などの関数にする方法（Function1について）

:::note
以下の内容はOpenFOAM v2212で確認しています。
:::

# Function1とは？
OpenFOAMのいろいろな設定項目の中には、Function1というクラスを使って実装されていて、設定値を時間などの関数にすることができるものがあります。

例えば、流量を指定する速度の境界条件`flowRateInletVelocity`の設定値`volumetricFlowRate`（体積流量の場合）や`massFlowRate`（質量流量の場合）などが、Funtion1として実装されています。

例として、この`volumetricFlowRate`を
```c++
volumetricFlowrate 0.2;
```
のように記述すれば、時間に対して一定の流量（$0.2 [m^3/s]$ ）を与える設定になりますが、
```C++
volumetricFlowRate
{
    type        sine;
    frequency   3.0;
    scale       0.01;
    level       0.2;
}
```
のように記述すると、平均$0.2[m^3/s]$、振幅$0.01[m^3/s]$、周波数$3.0 [1/s]$で時間変化をする流量を与えることができます。

Function1として実装されているほとんどの設定項目は、時間（タイムステップ）を入力とする関数として取り扱われますが、以下のように他の値を入力とするように実装されている設定項目もあります。
  - `fanPressure`境界条件の`fanCurve`（流量が入力値）
  - 液膜モデルの境界条件`temperatureDependentContactAngleForce`の`theta`（温度が入力値）

なお、どの設定項目がFunction1として実装されているか、何が入力値になっているかは、ソースコートを確認してみないと分かりません。


# 書式
Function1の設定には、いくつかの書式があります。
 
### typeでFunction1の種類を指定する方法
Function1で設定する設定項目のサブディクショナリに`type`で、Function1の種類を指定する方法です。私は下記の書式が一番読みやすいと思います。
 （`<entryName>`はFunction1で設定できる設定項目の名前です。）
```c++
<entryName>
{
    type      linearRamp;
    start     10;
    duration  20;
}
```
 
### 一定値を設定する場合
一定値の値を設定する場合には、簡易的に以下のような書き方をすることができます。
```C++
<entryName>   10;
```
```c++
<entryName> zero;
```

### Coeffsを使用した書き方
Function1のパラメータを`<entryName>Coeffs`（例えば、`volumetricFlowRateCoeffs`）のサブディクショナリとして記述します。
```C++
<entryName>   linearRamp;
<entryName>Coeffs
{
    start     10;
    duration  20;
}
```

### ベタ書き
Function1のパラメータをサブディクショナリを使わずに指定する方法です。ベタ書きだと他の設定項目と混在してしまい、読み難くなると思います。
```c++
<entryName>   linearRamp;
start     10;
duration  20;
```

# Function1の種類
ここからは、Function1で設定できる関数のタイプを種類ごとに説明します。

## 一定値を返すもの
### uniform
一定値を返します。
```C++
<entryName>
{
    type    uniform;
    value   <value>;
}
```
次のようにも記述することができます。
```C++
<entryName>  uniform 0.2;
```

___
### constant
一定値を返します。
```C++
<entryName>
{
    type    constant;
    value   <value>;
}
```

___
### one
常に$1$を返します．

___
### zero
常に$0$を返します．

## 数学関数
### polynomial
多項式による値を返します．
- カッコの中に２つの数値を記述するTuple2形式で、係数と乗数を順に指定します。
- 下記の例では，$f(t)=t^2+2t^3$の意味になります。

```C+
<entryName>
{
    type   polynomial;
    coeffs
    (
        (1 2)
        (2 3)
    );
}
```

---
### sine
$\sin$関数による値を返します．

- 周期（Period）で指定する場合
$$
a s \sin(2 \pi (t - t_0) / p))  + l
$$

- 周波数（Frequency）で指定する場合
$$
a s \sin(2 \pi f (t - t_0))  + l
$$

```C++
<entryName>
{
    type        sine;
    frequency   10;
    amplitude   0.1;
    scale       2e-6;
    level       2e-6;
}
```

| 名前  | 意味           |       | 値のタイプ                 |   設定が必要か？   | デフォルト値 |
| :-------- | :-------------------- | :---: | :------------------- | :----------: | :-----: |
| amplitude | 振幅             |  $a$  | Function1&lt;scalar> |            |    1    |
| frequency | 周波数 [1/s]       |  $f$  | Function1&lt;scalar> |   periodとどちらか  |         |
| period    | 周期 [s]            |  $p$  | Function1&lt;scalar> | frequencyとどちらか |         |
| scale     | 係数   |  $s$  | Function1&lt;Type>   |      必要     |         |
| level     | オフセット値   |  $l$  | Function1&lt;Type>   |      必要     |         |
| t0        | 時間のオフセット値     | $t_0$ | scalar               |            |    0    |


___
### cosine
$\cos$関数による値を返します．

- 周期（Period）で指定する場合
$$
a\ s\ \cos(2 \pi (t - t_0) / p)) + l
$$

- 周波数（Frequency）で指定する場合
$$
a\ s\ \cos(2 \pi f (t - t_0)) + l
$$


```C++
<entryName>
{
    type        cosine;
    frequency   10;
    amplitude   0.1;
    scale       2e-6;
    level       2e-6;
}
```

| 名前  | 意味           |       | 値のタイプ                 |   設定が必要か？   | デフォルト値 |
| :-------- | :-------------------- | :---: | :------------------- | :----------: | :-----: |
| amplitude | 振幅             |  $a$  | Function1&lt;scalar> |           |    1    |
| frequency | 周波数 [1/s]       |  $f$  | Function1&lt;scalar> |   periodとどちらか  |         |
| period    | 周期 [s]            |  $p$  | Function1&lt;scalar> | frequencyとどちらか |         |
| scale     | 係数   |  $s$  | Function1&lt;Type>   |      必要     |         |
| level     | オフセット値   |  $l$  | Function1&lt;Type>   |      必要     |         |
| t0        | 時間のオフセット値     | $t_0$ | scalar               |            |    0    |

___
### square
出力値が$[-1, 1]$の範囲の周期的な[矩形関数](https://ja.wikipedia.org/wiki/%E7%9F%A9%E5%BD%A2%E9%96%A2%E6%95%B0) $\mathrm{rect}$ による値を返します。

- 周期（Period）で指定する場合
$$
a\ s\ \mathrm{rect}((t - t0) / p)) + l
$$

- 周波数（Frequency）で指定する場合
$$
a\ s\ \mathrm{rect}(f (t - t0)) + l
$$

値が$1$になっている時間と$0$になっている時間の割合 $r$ を指定することもできます。
$$
    r= {M \over{M + S}}
$$

```C++
<entryName>
{
    type        square;
    frequency   10;
    amplitude   0.1;
    scale       2e-6;
    level       2e-6;
}
```

| 名前  | 意味           |       | 値のタイプ                 |   設定が必要か？   | デフォルト値 |
| :-------- | :-------------------- | :---: | :------------------- | :----------: | :-----: |
| amplitude | 振幅             |  $a$  | Function1&lt;scalar> |            |    1    |
| frequency | 周波数 [1/s]       |  $f$  | Function1&lt;scalar> |   periodとどちらか  |         |
| period    | 周期 [s]            |  $p$  | Function1&lt;scalar> | frequencyとどちらか |         |
| scale     | 係数   |  $s$  | Function1&lt;Type>   |      必要     |         |
| level     | オフセット値   |  $l$  | Function1&lt;Type>   |      必要     |         |
| t0        | 時間のオフセット値     | $t_0$ | scalar               |            |    0    |
| mark      | $1$の時間       |  $M$  | scalar               |            |    1    |
| space     | $0$の時間       |  $S$  | scalar               |            |    1    |


## ramp系
`start`で指定した時刻までは値が$0$で、それから`duration`の時間の間は値が変化します。指定したタイプによって値の変化のしかたが変わります。

ramp系のFunction1の名前を`<rampFunction>`とすると、下記のような書式になります。
```C++
<entryName>
{
    type      <rampFunction>;
    start     10;
    duration  20;
}
```

___
### step
`start`から`duration`の期間の値は$1$．それ以降では$0$を返します．

___
### linearRamp
`start`から`dutation`までの時間は、$0$から$1$まで、線形補間した値を返します．

___
### quadraticRamp
$\mathrm{linearRamp}$の値を二乗した値を返します。

$$
\mathrm{quadraticRamp}(t) = \mathrm{linearRamp}(t)^2
$$

___
### halfCosineRamp
半周期分の$\cos$関数による値を返します。

$$
\mathrm{halfCosineRamp}(t) = 0.5[1 - \cos \\{ \pi \times \mathrm{linearRamp}(t) \\} \]
$$

___
### quarterSineRamp
1/4周期分の$\sin$関数による値を返します。

$$
\mathrm{quarterSineRamp}(t) = \sin \\{ 0.5\pi \times \mathrm{linearRamp}(t) \\}
$$

___
### quarterCosineRamp
1/4周期分の$\cos$関数による値を返します。

$$
\mathrm{quarterCosineRamp}(t) = 1 - \cos \\{ 0.5\pi*\mathrm{linearRamp}(t) \\}
$$

## テーブル補間
指定したテーブルを使って、補間した値を返すことができます。

### csvFile
csvファイルから補間された値を返します。
```C++
<entryName>
{
    type  csvFile;
    nHeaderLine         4;          // ヘッダー部分の行数
    refColumn           0;          // 入力値のデータがかかれたカラム番号
    componentColumns    (1 2 3);    // 補間するデータが書かれたカラム番号
    separator           ",";        // データの区切り文字 (デフォルトは ",")
    mergeSeparators     no;         // 複数の区切り文字をマージするかどうか
    file                "fileXYZ";  // csvファイルのファイル名
    outOfBounds         clamp;      // 範囲外のデータ処理方法（オプション）
    interpolationScheme linear;     // 補間方法 [linear(デフォルト)|spline]（オプション）
}
```

___
### table
OpenFOAM形式のテーブルから補間された値を返します。

```C++
<entryName>
{
    type table;
    values
    (
        (0.0 (1 2 3))
        (1.0 (4 5 6))
    );
    outOfBounds         clamp;      // 範囲外のデータ処理方法（オプション）
    interpolationScheme linear;     // 補間方法 [linear(デフォルト)|spline]（オプション）
}
```

テーブルデータが書かれたファイル名を指定することもできます。
```C++
<entryName>
{
    type table;
    file "<case>/path/tableValues"; // ファイル名
}
```

___
### tableFile
OpenFOAM形式のテーブルファイルから補間された値を返します。
機能としては、tableのタイプでファイル名を指定する場合と同じです。

```C++
<entryName>
{
    type table;
    file "<case>/path/tableValues";
    outOfBounds         clamp;      // 範囲外のデータ処理方法（オプション）
    interpolationScheme linear;     // 補間方法 [linear(デフォルト)|spline]（オプション）
}
```

## その他
特殊な用途で使用できるタイプがいくつかあります。

### none
エラーが発生します。placeholder（仮の設定値）として使用するためにあります。

---
### sample
`position`で指定した点を含むセルの値を参照することができます。

```C++
<entryName>
{
    type            sample;
    field           <field name>;
    position        (0 0 0);
    interpolationScheme cell;    // 値の保管方法（デフォルト：cell）
}
```

---
### scale
`value`で指定したFunction1&lt;Type>の値に，`scale`で指定したFunction1&lt;scalar>の値を乗じて、`value`の値をスケーリングすることができます。

```C++
<entryName>
{
    type      scale;

    scale
    {
        type        linearRamp;
        start       0;
        duration    10;
    }

    value
    {
        type        sine;
        frequency   10;
        amplitude   1;
        scale       (1 0.1 0);
        level       (10 1 0);
    }
}
```

---
### coded
実行時にコンパイルされるソースコードで、計算された値を返します。

次のようなディレクティブを指定することができます。

    codeInclude | include files
    codeOptions | compiler line: added to EXE_INC (Make/options)
    codeLibs    | linker line: added to LIB_LIBS (Make/options)
    localCode   | c++; local static functions
    code        | c++; return the patch values at (scalar x)

下記の例は、入力値の2倍の値を返す例です。
```C++
<entryName>
{
    type  coded;
    name  myExpression;  // 名前

    code
    #{
        return 2.0*x;    // 引数はx
    #};

    //codeInclude
    //#{
    //    #include "volFields.H"
    //#};

    //codeOptions
    //#{
    //    -I$(LIB_SRC)/finiteVolume/lnInclude
    //#};
}
```

---
### functionObjectTrigger
`runTimeControl`のファンクションオブジェクトで発行された`trigger`に基づいて、値を変化させることができます。

- `trigger`が発行されるまでは、設定値の`defaultValue`が`true`ならば$1$、`false`ならば$0$を返します
- 何らかの`trigger`が発行されたら、その`trigger`の番号が設定値の`triggers`に含まれる場合は$1$、含まれない場合は$0$を返します
- `trigger`の番号は、`runTimeControl`のファンクションオブジェクトの下記の設定で発行します。

```C++
satisfiedAction setTrigger;
trigger         1;               // 発行するtrigger番号
```
     
下記の例では「1」、「3」、「5」番のトリガーが発行されたら、$1$を返します。
```C++
<entryName>
{
    type            functionObjectTrigger;
    triggers        (1 3 5);
    defaultValue    false;  // Optional
}
```


---
### functionObjectValue
他のファンクションオブジェクトの値を返します。

- 使用できる値は、時刻ディレクトリの`uniform/functionObjects/functionObjectProperties`の出力内容で確認することができます
- 型の違いに注意
    - scalarの値を返さなければいけない箇所で，labelの値を出力する結果を指定すると、常に$0$が返ります

```C++
<entryName>
{
    type                    functionObjectValue;
    functionObject          <name>;
    functionObjectResult    <function object result field>;
    defaultValue            <value>; // 値が出力できない場合に返される値（オプション）
}
```

---
### inputValueMapper
入力値を`mode`の設定に応じて入力値を変換（mapping）をして、`value`で設定されたFunction1&lt;Type>に渡した値を返します。
- `mode`の設定は以下が使用可能です
    - none
        - 入力値をそのまま`value`で設定されたFunction1&lt;Type>に渡します
    - function
        - 入力値を`function`で設定されたFunction1&lt;scalar>に渡し，その返り値が`value`で設定されたFunction1&lt;Type>に渡されます
    - minMax
        - 入力値が`min`と`max`の設定値でトリミングされた値が、`value`で設定されたFunction1&lt;Type>に渡されます

```C++:例1

//    Here the return value will be:
//    - poly(0.4) for x <= 0.4;
//    - poly(1.4) for x >= 1.4; and
//    - poly(x) for 0.4 < x < 1.4.

<entryName>
{
    type            inputValueMapper;
    mode            minMax;
    min             0.4;
    max             1.4;

    value polynomial
    (
        (5 1)
        (-2 2)
        (-2 3)
        (1 4)
    );
}
```

```C++:例2
<entryName>
{
    type            inputValueMapper;
    mode            function;

    function
    {
        type            functionObjectValue;
        functionObject  surfaceFieldValue1;
        functionObjectResult sum(outlet,phi);
    }

    value
    {
        type        table;
        file        "<system>/fanCurve.txt";
    }
}
```

---
### expression
expressionの機能で演算された値を返します。
- [こちらのexpressionの説明](https://www.openfoam.com/documentation/guides/latest/doc/openfoam-guide-expression-syntax.html#autotoc_md1336)の「fieldExpr」のexpression parserが使用可能です
- `args()`が引数です

```C++
<entryName>
{
    type            expression;

    // optional variables for use within the expression
    variables
    (
        "start = 0.5"
        "stop  = 1"
    );

    // A step function
    expression
    #{
        mag(arg() > start && arg() < stop) * vector(1, 0, 0)
    #};
}
```