2020年3月7日土曜日

FiPy

FVM を利用した PDE ソルバーです。

FiPy 3.4
https://www.ctcms.nist.gov/fipy/

良いですね。項に対応する関数(fipy.terms package)を追加するだけで PDE を解くことができます。昔、先輩に紹介いただいたソフトに近いですね。MATLAB も含め有償のソフトはこのように簡単なのでしょうか?というか、これが10年以上前に既に組まれていたのですから驚きです。

https://www.ctcms.nist.gov/fipy/documentation/FAQ.htmlより引用

例えば、拡散のみであれば以下のように書きます。
eq = DiffusionTerm(D)
非定常だと
eq = TransientTerm() == DiffusionTerm(D)
移流項を加えると
eq = TransientTerm() + AdvectionTerm(U) == DiffusionTerm(D)
風上差分と同様の解方は、convection にありました。
eq = TransientTerm() + UpwindConvectionTerm(U) == DiffusionTerm(D)
advection, convection は使い分けられていますね。違いはコチラ↓
https://physics.stackexchange.com/questions/24489/what-exactly-is-the-difference-between-advection-and-convection

これでソース項を除く式の表現ができました。地下水の流速を求めるなら別途式が必要ですが、1文で移流拡散の離散化を任せられるのは手軽ですね。
さらに、∇は以下で表現されていますので、任意の項を作成・追加可能です。
().divergence

コチラの方は日本語で解説されています。
http://penguinitis.g1.xrea.com/study/FiPy/FiPy.html
短いですね。これで2次元や3次元の近似解を求めることができるのですから、手軽としか言いようがありません。


では、試行。
公式のexample と 上記の方のコードを動かしながら、3次元まで拡張です。ここまで短く記述できるのは素晴らしい。
https://www.ctcms.nist.gov/fipy/examples/README.html

  1. from fipy import *
  2.  
  3. nx = 100
  4. ny = 100
  5. nz = 10
  6. Lx = 1.
  7. Ly = 1.
  8. Lz = 1.
  9. dx = Lx/nx
  10. dy = Ly/ny
  11. dz = Lz/nz
  12.  
  13. mesh = Grid3D(dx, dy, dz, nx, ny, nz)
  14. phi = CellVariable(name='phi', mesh=mesh, value=.5)
  15.  
  16. D = 1.
  17. U = (3., 2.,1.)
  18. phi1 = 1.
  19. phi2 = 0.5
  20.  
  21. phi.constrain(phi1, mesh.facesLeft)
  22. phi.constrain(phi2, mesh.facesRight)
  23.  
  24. eq = TransientTerm() + UpwindConvectionTerm(coeff=U) == DiffusionTerm(coeff=D)
  25.  
  26. T=1.
  27. dt=0.1
  28. for step in range(1, int(T/dt)+1):
  29. print('time step:', dt*step)
  30. eq.solve(var=phi, dt=dt)
  31. TSVViewer(vars=phi).plot(filename=str(step)+".tsv")
  32. VTKViewer(vars=phi).plot(filename=str(step)+".vtk")
  33.  
  34.  
結果、2次元まではOKですが、3次元では異常に時間がかかりました(実務では厳しいくらいに)。ラップトップで12分。この程度の計算で12分もかかるのはダメ。ソルバーの変更か並列化が必須でしょう。

Mayavi が動かなかったのと plotly での表示が遅かったので、可視化は別ソフトに頼ることを念頭に VTK 書き出し(plotly での表示は以下)。

  1. import pandas as pd
  2. import plotly.express as px
  3. import plotly.graph_objects as go
  4.  
  5. df = pd.DataFrame({'x' : mesh.x, 'y': mesh.y, 'z':mesh.z, 'value': phi})
  6.  
  7. fig = go.Figure(data=go.Volume(
  8. x=mesh.x,
  9. y=mesh.y,
  10. z=mesh.z,
  11. value=df.value,
  12. opacity=0.5,
  13. surface_count=20
  14. ))
  15.  
  16. fig.update_layout(margin=dict(l=0, r=0, b=0, t=0))
  17. fig.show()
phi が FiPy のオブジェクトになっていますので、やや扱いづらい。ま、df にはなるので書き換えが可能ならPHREEQCとの連成も容易でしょう。

0 件のコメント:

コメントを投稿