3次元物理シミュレーションのサロゲートモデルを作りたい

# はじめに
複雑な3次元構造を扱う機械学習モデルは論文レベルで幾らか出ているようには思いますが、一般的な手法が確立されているようには見えていません。試しにやってみたいなと思い、データの準備とサンプルモデルの作成に取組もうと思います。
内容を掘り下げるために、二部構成の記事シリーズを予定しています。本シリーズでは、以下の内容に焦点を当てます。
1. シミュレーションデータを機械学習用のデータセット（Torch-geometric）に変換（本記事）
2. データセットを使ってサロゲートモデルを作成
このシリーズを通して、3次元物理シミュレーションのサロゲートモデルへの理解を深めたいと考えています。

# 利用するデータ
今回はパブリックに公開されている3次元物理シミュレーションのデータを活用させてもらいます。ジェットエンジンのブラケットについてのシミュレーションとなっています。

[SimJEB: Simulated Jet Engine Bracket Dataset](https://simjeb.github.io/)

# シミュレーションデータ詳細
## 1. データ構造
先ずは、今回のシミュレーションデータのデータ構造についてです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660703/af4085c7-fc2c-8c5a-7b43-d71c47e7448e.png)
次項からは個別の要素について、実データと共に詳しく見ていきます。

## 2. 節点（GRID）
GRIDは「節点」を表すために使用され、これは構造モデルの基本的な構成要素となっています。GRID要素は、モデル内の特定の位置を定義し、その位置における構造の挙動を解析するための基点となります。

実際のデータは以下のような構造となっています。
```
$$
$$  GRID Data
$$
GRID           1        26.34596-76.117 37.7368 
GRID           2        25.76159-75.678737.7368 
```
一つ目について詳細に見ていくと、
- GRID：　該当行が節点の情報であることを示しています
- "1"：　節点のIDを示しています
- "26.34596-76.117 37.7368"：　X, Y, Z座標を示しています。なお、座標を示す数列は8文字づつ区切られており"26.34596-76.117 37.7368"は[x, y, z]=[26.34596, -76.117, 37.7368]となります

## 3. 四面体メッシュ（CTETRA）
CTETRAは、NASTRANで使用される要素タイプの一つです。CTETRAは「四面体要素」とも呼ばれ、3D要素の一種で、4つの節点（頂点）を持ちます。この要素は、特に複雑な形状や曲面を持つモデルの解析に適しています。

実際のデータは以下のような構造となっています。
```
$$
$$  CTETRA elements 4-noded
$$
CTETRA     84765       1   42792   53062   53064   55395
CTETRA     84766       1   52276   51898   52277   58873
```
一つ目について詳細に見ていくと、
- CTETRA：　該当行が四面体メッシュの情報であることを示しています
- "84765"：　四面体メッシュのIDを示しています
- "42792   53062   53064   55395"：　四面体メッシュを構成する節点のIDを示しています。

## 4. 単一点拘束（SPC）
モデル上の特定の節点（GRID点）に適用される制約条件を表し、構造物の運動や変形を制限するのに使われます。

実際のデータは以下のような構造となっています。
```
$$
$$  SPC Data
$$
SPC            1  112874  123456     0.0
SPC            1  112875  123456     0.0
```
一つ目について詳細に見ていくと、
- SPC：　該当行が単一点拘束の情報であることを示しています
- "1"：　単一点拘束のIDを示しています
- "112874"：　拘束を適用する節点のIDを示しています
- "123456"：　自由度を示しており、この場合、6方向に制約をかけていることとなります
- "0.0"：　拘束の大きさを示しています

## 5. 静的加重（FORCE）
ベクトルを指定することによって、節点における静的加重を定義します。

実際のデータは以下のような構造となっています。
```
$$
$$  FORCE Data
$$
FORCE          2  112878       01.0     0.0     0.0     35585.77
FORCE          3  112878       01.0     -37809.90.0     0.0     
```
一つ目について詳細に見ていくと、
- FORCE：　該当行が静的加重の情報であることを示しています
- "2"：　静的加重のIDを示しています
- "112878"：　静的加重を適用する節点のIDを示しています
- "01.0"：　スケールファクター
- "0.0     0.0     35585.77"：　静的加重の大きさをベクトル成分で表現しています。GRIDの時と同様8文字区切りとなっており、今回の場合、[x, y, z]=[0.0, 0.0, 35585.77]となります

## 6. モーメント（MOMENT）
ベクトルを指定することによって、節点における静的モーメントを定義します。

実際のデータは以下のような構造となっています。
```
$$
$$  MOMENT Data
$$
MOMENT         5  112878       01.0     0.0     0.0     564924.2   
```
一つ目について詳細に見ていくと、
- MOMENT：　該当行が静的モーメントの情報であることを示しています
- "5"：　静的モーメントのIDを示しています
- "112878"：　静的モーメントを適用する節点のIDを示しています
- "01.0"：　スケールファクター
- "0.0     0.0     564924.2"：　静的モーメントの大きさをベクトル成分で表現しています。GRIDの時と同様8文字区切りとなっており、今回の場合、[x, y, z]=[0.0, 0.0, 564924.2]となります

## 7. 解析ケース（SUBCASE）
異なる解析条件やシナリオをSUBCASEとして設定し、同一のモデルに対して複数の解析を行うための項目です。

実際のデータは以下のような構造となっています。
```
$
$HMNAME LOADSTEP               1"vertical"       0
$
SUBCASE        1
  LABEL vertical
  SPC =        1
  LOAD =        2
$
$HMNAME LOADSTEP               2"horizontal"       0
$
SUBCASE        2
  LABEL horizontal
  SPC =        1
  LOAD =        3
```
一つ目について詳細に見ていくと、
- "SUBCASE"：　続く行が解析ケースの情報であることを示しています
- "1"：　解析ケースのIDを示しています
- "LABEL vertical"：　この解析ケースに割り当てられているラベルを示しています。今回の場合はVerticalが割当てられています。
- "SPC = 1"：　この解析ケースに適用するSPCを示しています。今回の場合、SPC ID＝1が適用されています
- "LOAD = 2"：　この解析ケースに適用するLOADを示しています。LOADに対応するのは前述のFORCEとMOMENTとなります。FORCE ID=2が適用されています

## 8. RBE2
複数の節点の剛体的な結合を定義するための要素です。単一の影響を及ぼす独立節点と複数の影響を受ける従属節点から構成されます。

実際のデータは以下のような構造となっています。
```
RBE2      654876  112874  123456   21080   21081   21082   21083   21084
+          21085   21086   21087   21088   21089   21090   21091   21092
+          21093   21094   21095   21096   21097   21098   21099   21100
+          21101   21102   21103   21104   21105   21106   21107   21108
+          21109   21110   23177   23178   23179   23180   23181   23182
+          23183   23184   23185   23186   23187   23188   23189   23190
+          23191   23192   23193   23194   23435   23436   23437   23438
+          23439   23440   23441   23442   23443   23444   23445   23446
+          23447   23448   23449   23450   23451   23452   23453   23454
+          23455   23456   23457   23458   23459   23460   23461   23462
+          23463   23464   23465   23466   23467   23468   23469   23470
+          23471   23472   23473   23474   23475   23476   23477   23478
+          23479   23480   23481   23482   23483   23484   23485   23486
+          23487   23488   23489   23490   23491   23492   23493   23494
+          23495   23496   23497   23498   23499   23500   23501   23502
+          23503   23504   23505   23506   23507   23508   23509   23510
+          23511   23512   23513   23514   23515   23516   23517   23518
+          23519   23520   23521   23522   23523   23524   23525   23526
+          23527   23528   23529   23530   23531               
```
- "RBE2"：　続く行がRBE2の情報であることを示しています
- "654876"：　RBE2のIDを示しています
- "112874"：　独立接点となる節点のIDを示しています
- "123456"：　自由度を示しています
- "21080"以降：　従属節点となる節点のIDを示しています。独立節点の同様の挙動を示します

## 9. RBE3
複数の節点間で荷重や変位を分散させるために使用される分散連結要素です。単一の運動の中心となる重心節点と運動を分散させる従属節点から構成されます。

実際のデータは以下のような構造となっています。
```
$$
$$  RBE3 Elements
$$
RBE3      654880          112878  1234561.0          123    4581    4582
+           4583    4584    4585    4586    4587    4588    4589    4590
+           4591    4592    4593    4594    4595    4596    4597    4598
+           4599    4600    4601    4602    4603    4604    4605    4606
+           4607    4608    4609    4610    4611    4612    4613    4614
+           4615    4616    4617    4618    4619    4620    4621    4622
+           4623    4624    4625    4626    4627    4628    4629    4630
+           4631    4632    4633    4634    4635    4636    5558    5559
+           5560    5561    5562    5563    5564    5565    5566    5567
+           5568    5569    5570    5571    5572    5573    5574    5575
+           5576    5577    5578    5579    5580    5581    5582    5583
+           5584    5585    5586    5587    5588    5589    5590    5591
+           5592    5593    5594    5595    5596    5597    5598    5599
+           5600    5601    5602    5603    5604    5605    5606    5607
+           5608    5609    5610    5611    5612    5613    6574    6575
+           6576    6577    6578    6579    6580    6581    6582    6583
+           6584    6585    6586    6587    6588    6589    6590    6591
+           6592    6593    6594    6595    6596    6597    6598    6599
+           6600    6601    6602    6603    6604    6605    6606    6607
+           6608    6609    6610    6611    6612    6613    6614    6615
```
- "RBE3"：　続く行がRBE3の情報であることを示しています
- "654880"：　RBE3のIDを示しています
- "112878"：　重心節点となる節点のIDを示しています
- "123456"：　自由度を示しています
- "1.0"：　スケーリングファクタを示しています
- "123"：　スケーリングファクタを持つグローバル成分を示しています
- "4581"以降：　従属節点となる節点のIDを示しています

## 10. シミュレーション結果
シミュレーション結果として各節点に対して以下の項目が与えられています。「()：括弧」書きされている部分はSUBCASEのLABELに対応する部分となります。

- x displacement(vertical): float
- y displacement(vertical): float
- z displacement(vertical): float
- magnitude of displacement "sqrt(x^2+y^2+z^2)"(vertical): float
- stress(vertical): float
- x displacement(horizontal): float
- y displacement(horizontal): float
- z displacement(horizontal): float
- magnitude of displacement "sqrt(x^2+y^2+z^2)"(horizontal): float
- stress(horizontal): float
- x displacement(diagonal): float
- y displacement(diagonal): float
- z displacement(diagonal): float
- magnitude of displacement "sqrt(x^2+y^2+z^2)"(diagonal): float
- stress(diagonal): float
- x displacement(torsion): float
- y displacement(torsion): float
- z displacement(torsion): float
- magnitude of displacement "sqrt(x^2+y^2+z^2)"(torsion): float
- stress(torsion): float


# グラフデータへの変換
## 1. グラフ形式のデータについて
グラフ形式のデータは主に以下の二つの要素からなる。

- ノード（頂点）
- エッジ（辺）

ノードとエッジはそれぞれ属性を持っており、ノード間をエッジが接続する形となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660703/9824bb67-58e7-9a73-dde1-822d943c939e.png)

詳しくは以下を参照ください。
https://www.akita-pu.ac.jp/system/elect/ins/kusakari/japanese/teaching/SoftTech/2009/note/8.pdf

## 2. シミュレーションデータとグラフデータの対応付け
機械学習への適用を考慮しつつ、シミュレーションデータとグラフデータを対応付ける。
- 節点（GRID)
    - ノードに対応する要素となる。節点のx, y, z座標の値をノードの属性として持たせる。
- 四面体メッシュ（CTETRA）
    - エッジに対応する要素となる。4つの節点を繋ぐことでエッジを表現する。
- 単一点拘束（SPC）
    - ノードの属性に含めるべき要素となる。SPCの値をノードの属性として持たせる。
- 静的加重（FORCE）,　静的モーメント（MOMENT）
    - ノードの属性に含めるべき要素となる。FORCEやMOMENTの値をノードの属性として持たせる。
- RBE2, RBE3
    - エッジに対応する要素となる。独立節点または重心節点から従属節点に対してエッジを作成する。

## 3. 変換処理
詳しくはKaggle Notebookを参照ください
※全てのデータを載せると容量が大きいため、入っているデータは一つとなっています

[Kaggle Notebook](https://www.kaggle.com/shinyatakaramoto/simjeb-to-torch-geometric-dataset)

## 4. 変換後のデータ
KaggleのDatasetとして登録しています。

[Kaggle dataset](https://www.kaggle.com/datasets/shinyatakaramoto/jet-bracket-torch-geometrict-dataset)

以下のように利用できます。
``` python
class JetBracket(InMemoryDataset):
    def __init__(self, root, transform=None, pre_transform=None, pre_filter=None):
        super().__init__(root, transform, pre_transform, pre_filter)
        self.data, self.slices = torch.load(f"{root}/jet_bracket.pt")

jet_bracket = JetBracket("保存したパス")
```

## 5. 変換後のデータの内容
```
データセットから一つ取り出すと以下のような内容となっています。
Data(x=[112878, 16], edge_index=[2, 1453438], y=[112878, 20])

それぞれの項目は以下のような内容となっています。
x [ノード数, 属性数(16)]: 機械学習の入力となる側
    x axis: float, 
    y axis: flaot, 
    z axis: float, 
    condition of constraint: 0(off) or 1(on),
    force magnitude x(vertical): float,
    force magnitude y(vertical): float, 
    force magnitude z(vertical): float, 
    force magnitude x(horizontal): float, 
    force magnitude y(horizontal): float, 
    force magnitude z(horizontal): float,
    force magnitude x(diagonal): float, 
    force magnitude y(diagonal): float, 
    force magnitude z(diagonal): float, 
    force magnitude x(torsion): float, 
    force magnitude y(torsion): float, 
    force magnitude z(torsion): float,

y [ノード数, シミュレーション結果数(20)]: 機械学習の出力側、シミュレーションの結果
    x displacement(vertical): float
    y displacement(vertical): float
    z displacement(vertical): float
    magnitude of displacement "sqrt(x^2+y^2+z^2)"(vertical): float
    stress(vertical): float
    x displacement(horizontal): float
    y displacement(horizontal): float
    z displacement(horizontal): float
    magnitude of displacement "sqrt(x^2+y^2+z^2)"(horizontal): float
    stress(horizontal): float
    x displacement(diagonal): float
    y displacement(diagonal): float
    z displacement(diagonal): float
    magnitude of displacement "sqrt(x^2+y^2+z^2)"(diagonal): float
    stress(diagonal): float
    x displacement(torsion): float
    y displacement(torsion): float
    z displacement(torsion): float
    magnitude of displacement "sqrt(x^2+y^2+z^2)"(torsion): float
    stress(torsion): float

edge_index [2, エッジ数]: ノード間を接続するエッジ
```


# まとめ
今回の記事では、シミュレーションデータの中身を確認し、torch-geometricのデータセットに変換する部分まで記載しました。シミュレーションの生データからのデータ変換はかなり骨の折れる作業となるため、作成してあるデータセットを使ってもらえればと思います。次の記事では、今回作成したデータセットを使ってサロゲートモデルを作成したいと思います。

[今回のNotebook](https://www.kaggle.com/shinyatakaramoto/simjeb-to-torch-geometric-dataset)
[今回のDataset](https://www.kaggle.com/datasets/shinyatakaramoto/jet-bracket-torch-geometrict-dataset)