2020/04/29

Plotlyによる応力解析結果の出力

前回まではmatplotlibを用いた2次元画像による応力解析結果の可視化を試してみました。
しかし、3次元の構造解析モデルの応力解析結果を確認する場合、汎用解析ツールのUIのように
同じく3次元空間でグリグリとオブジェクトを回しながら結果確認ができると実務的に便利です。
そこで今回は、Pythonにも対応しているインタラクティブなデータ可視化ライブラリPlotlyを用いてOpenseesPyによる3次元トラスの応力解析結果の出力を行います。

Plotlyはオープンソースのデータ可視化ライブラリです。
Pythonだけでなく、JAVAscriptやMATLAB等にも対応しています。
同じデータ可視化ライブラリであるmatplotlibは主にグラフデータの画像出力に対応していましたが、
Plotlyでは出力したグラフデータをブラウザ上でマウスなどを動かしながらインタラクティブな状態で確認できます。
Pythonでの使用にはOpenseesPyの場合と同じく、ライブラリのインストールおよびプログラムへのインポートが必要となります。
インストール法や使用方法の詳細につきましては、以下サイトをご覧ください。

https://plotly.com/python/

今回もこれまでに構築した3次元トラス解析プログラムをベースに検討を進めます。
Plotlyを使ってデータをグラフ化するプロセスを以下に簡単に示します。

・ライブラリのインポート

import plotly.offline as po
import plotly.graph_objs as go
上記によりPlotlyをプログラムにインポートします。

・初期化

po.init_notebook_mode()
上記によりPlotlyを初期化します。

・グラフの定義

graph=go.Scatter3d(x=node_x, y=node_y, z=node_z, name='beam%s'%(int(ele_no[i])), mode='lines+text', line=dict(width=int(area[i]),color=color_tag),
hovertext='AxialForce %s'%(round(temp[0],2)), showlegend=True)
上記スクリプトの形式で描画するグラフを定義します。
なお、上記スクリプトはモデル図兼応力図を描くためのスクリプトになります。

モデルの各梁要素を線グラフとして描画します。線の太さは梁要素の断面積のデータから、線の色は応力解析により得られた梁要素の軸力から決定するように定義しています。なお、軸力についてはグラフ上でカーソルを合わせると確認できる「hovertext」として定義しています。

・レイアウトの定義とグラフの描画

data.append(graph)
layout = go.Layout(xaxis=dict(showgrid=False))
fig2 = dict(data = data, layout=layout)
po.plot(fig2, filename="model")
定義したグラフデータを保存したdataリストとグラフのレイアウト等を定義したlayoutリストをfig2に呼び出して、po.plotにて描画しています。


上記のPlotlyによるデータ図化機能を応用して、結果としてグリグリ動かせるモデル軸力図・変形図が出力できました。
ブラウザ上の画面で動かせる形式になっており、
マウスを梁上に移動させると軸力も表示させることができます。


変位図を出力したり、画面上で選択することで、モデル図応力図と変位図の2つのグラフを同時に出現させたりすることもできます。
マウスで図を回転させたり、拡大したりすることが非常に直感的に行えます。



以上、汎用の構造解析ツールのような操作感覚で、解析結果を確認することができました。
今後さらに複雑な立体トラスモデルの応力解析結果を確認する場合には、非常に役立ちそうなツールだと思います。
最後に今回使用したソースコードを以下に示します。
#plotlyによる描画
po.init_notebook_mode()
trace1 = go.Scatter3d(x=cor_x, y=cor_y, z=cor_z, mode='markers+text', marker_color='blue', marker_size=2, name="Node", text=no, showlegend=True)
data = [trace1]

#モデル図・軸力図の描画
for i in range(len(ele_no)):
    temp2=[]
    temp3=[]
    node_x=[]
    node_y=[]
    node_z=[]
    temp2=nodeCoord(int(n1[i]))
    temp3=nodeCoord(int(n2[i]))
    node_x.append(temp2[0])
    node_x.append(temp3[0])
    node_y.append(temp2[1])
    node_y.append(temp3[1])
    node_z.append(temp2[2])
    node_z.append(temp3[2])
    
    temp=basicForce(int(ele_no[i]))#各部材の応力値をRGB値に変換
    if temp[0] >=0:
        if max_tens == 0:
            color_tag='rgb(0,0,'+str(255*temp[0])+')'
        else:
            color_tag='rgb(0,0,'+str(255*temp[0]/max_tens)+')'     
    else:
        if max_comp == 0:
            color_tag='rgb('+str(-255*temp[0])+',0,0)'
        else:  
            color_tag='rgb('+str(-255*temp[0]/max_comp)+',0,0)'
            
    graph=go.Scatter3d(x=node_x, y=node_y, z=node_z, 
                               name='beam%s'%(int(ele_no[i])), mode='lines+text', line=dict(width=int(area[i]),color=color_tag),
                               hovertext='AxialForce %s'%(round(temp[0],2)), showlegend=True)

    data.append(graph)

#変位図の描画
node_x=[]
node_y=[]
node_z=[]
temp2=[]
temp3=[]
for i in range(len(ele_no)):
    temp2=[x + y * mag_factor for (x, y) in zip(nodeCoord(int(n1[i])),nodeDisp(int(n1[i])))]
    temp3=[x + y * mag_factor for (x, y) in zip(nodeCoord(int(n2[i])),nodeDisp(int(n2[i])))]
    node_x.append(temp2[0])
    node_x.append(temp3[0])
    node_y.append(temp2[1])
    node_y.append(temp3[1])
    node_z.append(temp2[2])
    node_z.append(temp3[2])
graph=go.Scatter3d(x=node_x, y=node_y, z=node_z, 
                               name="Disp", mode='lines', line_color='blue',line=dict(width=2, dash='dot'),
                               showlegend=True)
data.append(graph)

layout = go.Layout(xaxis=dict(showgrid=False))
fig2 = dict(data = data, layout=layout)
po.plot(fig2, filename="model")