いわて駐在研究日誌

OpenCAE、電子工作、R/C等、徒然なるままに

Dakotaの並列計算機能について

ようやく復帰。Dakotaの並列計算機能について調べたのでまとめてみる。

概観と簡単なサマリー

Dakota自体から起動する"simulator"はシリアル計算でも並列計算でももちろん構わない(たとえばOFの並列計算など)ので、ここではDakota本体の並列計算について調べてみた。

 

ユーザーマニュアルのChapter 17 Parallel Computingを読んで理解した限りでは、Dakota本体としては、

  1. dakotaプロセス内からの複数のsimulation起動(応答関数の複数同時evaluation)
  2. MPIによる複数のdakotaプロセスの起動(multi node用?)

の機能があり、何をどう並列計算したいかにより、並列度を変えて使い分けることができる。とりあえず一番わかりやすいSingle-Level Parallelでは、

①asynchronous local

単一ノード内で、独立した設計変数による応答関数評価を同時に起動して計算効率化

②message passing with single simulation per node

MPIにより多ノードでdakotaを起動し、それぞれのdakotaプロセスで応答関数評価simlationを1つ起動する。masterノードがそれらの結果を取りまとめする

③Hybrid

①と②の組み合わせ

 となっている。

 

この中で、おそらく個々のsimlation負荷が小さいのであれば、①か③がよく、OF計算のような計算負荷が1つ1つ大きい場合には、②もしくは③がよいのかもしれない。

なお、並列プロセス実行にはforkを推奨とのこと。

 

【DACEでの例】

一番わかりやすいと思われる設計変数に対する応答関数の評価を独立に行うDACEでの並列計算の例を調べてみる。

具体例①:ラテン超方格を使ったDACEチュートリアル(ascynchronous evaluation_concurrency)

問題:Pythonを使った2設計変数2目的関数(objective.py)の最適評価

objective.py

#!/bin/python
from sys import argv
from math import *
import numpy as np

def f1(x1, x2):
    return 2.0*sqrt(x1)

def f2(x1, x2):
    return x1-x1*x2+5.0

if __name__ == '__main__':
    x1 = float(argv[1])
    x2 = float(argv[2])
    print f1(x1,x2), f2(x1,x2)

dakota_lhs_par.in

# Dakota Input File: dakota.in

environment
#  graphics
  tabular_graphics_data
    tabular_graphics_file = 'objective.dat'

method
  dace oa_lhs
     seed = 5  
     samples = 121
model
  single

variables
  continuous_design = 2
    initial_point     2.0      1.5
    lower_bounds      1.0      1.0
    upper_bounds      4.0      2.0
    descriptors       'x1'     "x2"

interface
  fork
    asynchronous evaluation_concurrency = 4
  analysis_driver = 'simulator_script'
  parameters_file = 'params.in'
  results_file = 'results.out'
  work_directory directory_tag
    copy_files = 'templatedir/*'
  named 'workdir' file_save  directory_save
    aprepro

responses
  response_functions = 2
  no_gradients
  no_hessians

赤字の部分のようにevaluation_concurencyを指定すると同時に評価サンプルを複数実行してくれる。この場合、シングルで24.2s, evaluation_concurrency = 4 で7.5sとなった。

$ dakota dakota_lhs_par.in

[snip]

<<<<< Function evaluation summary: 121 total (121 new, 0 duplicate)

Simple Correlation Matrix among all inputs and outputs:
                       x1           x2 response_fn_1 response_fn_2
          x1  1.00000e+00
          x2  1.37441e-02  1.00000e+00
response_fn_1  9.96397e-01  1.52353e-02  1.00000e+00
response_fn_2 -4.95228e-01 -8.29560e-01 -4.94665e-01  1.00000e+00

Partial Correlation Matrix between input and output:
             response_fn_1 response_fn_2
          x1  9.96398e-01 -8.66506e-01
          x2  1.81689e-02 -9.47129e-01

Simple Rank Correlation Matrix among all inputs and outputs:
                       x1           x2 response_fn_1 response_fn_2
          x1  1.00000e+00
          x2  1.41173e-02  1.00000e+00
response_fn_1  1.00000e+00  1.41173e-02  1.00000e+00
response_fn_2 -4.56767e-01 -8.63711e-01 -4.56767e-01  1.00000e+00

Partial Rank Correlation Matrix between input and output:
             response_fn_1 response_fn_2
          x1  1.00000e+00 -8.82201e-01
          x2  1.16427e-10 -9.63760e-01


<<<<< Iterator dace completed.
<<<<< Environment execution completed.
DAKOTA execution time in seconds:
  Total CPU        =       0.09 [parent =   0.095986, child =  -0.005986]
  Total wall clock =    7.45185

※ analysis_concurrencyというキーワードもあるが、これを指定すると同時に評価する最大数を制限できる。

When asynchronous execution is enabled and each evaluation involves multiple analysis drivers, then the default behavior is to launch all drivers simultaneously. The analysis_concurrency keyword can be used to limit the number of concurrently run drivers.

 

具体例②:ラテン超方格を使ったDACEチュートリアル(mpirun on single node)

問題:Pythonを使った2設計変数2目的関数(objective.py)の最適評価(上記と同じ)

dakota_lhs.in (evaluation concurrencyの指定なしに注意)

# Dakota Input File: dakota.in
environment
#  graphics
  tabular_graphics_data
    tabular_graphics_file = 'objective.dat'

method
  dace oa_lhs
     seed = 5  
     samples = 100

model
  single

variables
  continuous_design = 2
    initial_point     2.0      1.5
    lower_bounds      1.0      1.0
    upper_bounds      4.0      2.0
    descriptors       'x1'     "x2"

interface
  fork

###    asynchronous evaluation_concurrency = 4
  analysis_driver = 'simulator_script'
  parameters_file = 'params.in'
  results_file = 'results.out'
  work_directory directory_tag
    copy_files = 'templatedir/*'
  named 'workdir' file_save  directory_save
    aprepro

responses
  response_functions = 2
  no_gradients
  no_hessians

$ mpirun -np 4 dakota dakota_lhs.in  > dakota_lhs_openmpi.out

→ dakotaプロセスが4つ起動する。前例では1つだけである。

[snip]

<<<<< Function evaluation summary: 121 total (121 new, 0 duplicate)

Simple Correlation Matrix among all inputs and outputs:
                       x1           x2 response_fn_1 response_fn_2
          x1  1.00000e+00
          x2  1.37441e-02  1.00000e+00
response_fn_1  9.96397e-01  1.52353e-02  1.00000e+00
response_fn_2 -4.95228e-01 -8.29560e-01 -4.94665e-01  1.00000e+00

Partial Correlation Matrix between input and output:
             response_fn_1 response_fn_2
          x1  9.96398e-01 -8.66506e-01
          x2  1.81689e-02 -9.47129e-01

Simple Rank Correlation Matrix among all inputs and outputs:
                       x1           x2 response_fn_1 response_fn_2
          x1  1.00000e+00
          x2  1.41173e-02  1.00000e+00
response_fn_1  1.00000e+00  1.41173e-02  1.00000e+00
response_fn_2 -4.56767e-01 -8.63711e-01 -4.56767e-01  1.00000e+00

Partial Rank Correlation Matrix between input and output:
             response_fn_1 response_fn_2
          x1  1.00000e+00 -8.82201e-01
          x2  1.16427e-10 -9.63760e-01

 

<<<<< Iterator dace completed.
<<<<< Environment execution completed.
DAKOTA master processor execution time in seconds:
  Total CPU        =       0.21 [parent   =   0.206969, child =   0.003031]
  Total wall clock =    7.38266 [MPI_Init = 9.05991e-06, run   =    7.38266]

※ 計算時間はevaluation_concurrency指定の場合とほぼ変わらず7.4s。

 ということで、マルチノードならmpi、シングルノードならevaluation concurrency指定でよさそうである。

 

→ 次は、gradien base, Non-gradient baseの最適化の例について調査すべし。

最近の状況

子育て中心で、なかなかブログを更新できておりません。

定時を過ぎたらばたばたと迎えにいって、おむつ替えて、遊びの相手して、風呂入れて、ミルク飲ませて、寝かしつける、で8時過ぎ。

飯を食って風呂入ると、疲れて眠くなり、机で気絶してたりする。少なくとも家ではまとまった研究とか読書の時間がとれないのは、要反省ですな。

しかも、夜中に起きる子供の相手すると2時間はすぐに経つし、朝5時には起きるし、慢性的に寝不足な感じです。どうもいかんなー。

パスフレーズなしのSSHログイン(OpenMPI)と、NFSマウントの設定

パスフレーズなしのSSHログイン設定メモ

 

(1)クライアント(ログインユーザはwaku)でssh2のRSA暗号鍵を生成

$ ssh-keygen -t rsa

パスフレーズを聞いてくるが、なしでよければそのままリターンでOK

 

(2)公開鍵(*.pub)のほうを接続したいサーバにコピーする。

楽をしたければ、以下のコマンド1つでOK。

$ ssh-copy-id -i ~/.ssh/id_rsa.pub waku@SEREVER

もしくは以下のように、クライアントからscpなどをつかって公開鍵をコピーし、その後、サーバー側で設定する。

※ サーバ自身も計算ノードに使う場合は、サーバ自身にたいしてもやっておくこと。

※ 同様に、各クライアント→サーバ、各クライアント→他のクライアントもパスフレーズなしで認証できるようにしておく必要がある(重要)。

@クライアント

$ scp ~/.ssh/id_dsa.pub waku@SERVER

@サーバ(コピーした公開鍵をauthoized_keysに追記)

$ cat ~/id_dsa.pub >> authorized_keys server

$ chmod 600 authorized_keys

$ rm ~/id_dsa.pub

 

(3)パスワードなしでsshログインできるか確認

$ ssh waku@ensis13
Last login: Mon Jul 13 08:55:12 2015 from ensis10
[waku@ensis13 ~]$

 

NFS設定メモ

 ※ mpirunには--preload_binaryというオプションがあるので、sshでホスト名を使ったログインができていれば、いちいちNFSマウントしていなくても実行バイナリを配ってくれるらしい。

※ 今回は真面目に、ジョブサーバの特定ディレクトリをNFSで公開し、計算ノードからNFSクライアントとしてマウントすることにする。

 

(1)使用条件

NFSサーバ(ジョブサーバ、マウントされる側)

ensis10: /home/waku/exports

NFSクライアント(マウントする側)

ensis{12/13/14}: /home/waku/exports

 

(2)NFSサーバの設定

/etc/exportsに以下を記述

/home/waku/exports  192.168.0.12(rw,no_root_squash)    192.168.0.13(rw,no_root_squash)        192.168.0.14(rw,no_root_squash)

exportsを確認

exportfs -v

/home/waku/exports
        192.168.0.12(rw,wdelay,no_root_squash,no_subtree_check)
/home/waku/exports
        192.168.0.13(rw,wdelay,no_root_squash,no_subtree_check)
/home/waku/exports
        192.168.0.14(rw,wdelay,no_root_squash,no_subtree_check)

nfs, rpcbindの設定・起動

# yum install nfs* rpcbind

# chkconfig rpcbind on

# chkconfig nfslock on

# chkconfig nfs on

# /etc/init.d/nfs start

 

(3)NFSクライアントの設定

# /etc/rc.d/init.d/rpcbind start

# chkconfig rpcbind on

# /etc/rc.d/init.d/netfs start

# chkconfig netfs on

$ mkdir /home/waku/exports

手動マウントしてみる

# mount -t nfs 192.168.0.10:/home/waku/exports /home/waku/exports

うまくいけば、

# vi /etc/fstab

192.168.0.10:/home/waku/exports /home/waku/exports nfs _netdev,rw,async,hard,intr 0 0

(注)ここでサーバ、クライアントは同じGID/UIDを持つものとしているので(事前に同じGID/UIDに変更している)、同じユーザwakuで読み書きできるはずである。ただし、NFSv4(SL6/CentOS6)のバグ?のようなものがあり、nobody.nobodyでマッピングされてしまうことがある。対処方法は、以下のようにすれば良い。

# vi /etc/idmapd.conf

  Domain = localdomain (記述を追記)

# /etc/rc.d/init.d/rpcimapd restart

#  nfsidmap -c (nfsidのキャッシュクリア)

# /etc/rcd./init.d/netfs restart

nfsv4 mounts files as nobody

 

 

OF+外部ライブラリ(物性値ライブラリ)その3

 水・水蒸気のライブラリであるfreesteamとOFの併用テスト

1)まず、freesteamをビルドして(sconsが必要)、.soライブラリ”libfreesteam.so.1”を作成しておく。OFのビルド環境で実行する。

tar xf freesteam-2.1.tar.bz2

cd freesteam-2.1

scons

scons test && ./test. (テスト)

 2)続いて、IAPWS-IF97-OFのライブラリ”libIAPWSRangeThermo.so”のビルドを行う。OFのビルド環境で実行する。

git clone https://github.com/romansCode/IAPWS-IF97-OF.git

cd IAPWS-IF97-OF

wclean

wmake libso

 

 

VAWT翼型最適化(2)

メッシャーの問題がひと段落したので、いよいよ計算という感じであるが、ここから泥臭い作業が続くのだろうなと覚悟しておく。

 

その前に、Dakotaで計算する場合、特定のCFD計算が発散したりしてエラーになる場合、それを飛ばして次の計算に移る仕組みを調べておく必要がありそう(リスタートとは別物・・・リスタート機能もちゃんと調べないとな)。

 

で、ちょっと調べてみた。

おそらくこのあたりだろうと思うが、以下のキーワードを設定すると良さそう。

Dakota Reference Manual: failure_capture

interface>analysis_drivers>failure_capture

  • abort (the default)
  • retry
  • recover
  • continuation

デフォルトではabortになっているので、各設計変数での計算が失敗した場合は、そこでdakotaも終了ということになる。retryはもう一度analysisを実行。recoverは、一緒に指定した”reals for specifying the dummy function values”をダミーで出力して次のanalysisへ進む。cotinuationは良く分からないが、それまでに成功した設計変数から、失敗した設計変数のanalysisに近い設計変数を生成し再トライするような感じである。

ということで、recoverでダミー目的関数値をしておくことで後からそれらを弾けば良さそうである。

 

続いてリスタートであるが、dakotaは黙っていても、dakota.rstというリスタートファイルを作成してくれる。ファイル名を指定したければ、

dakota -i dakota.in -write_restart my_restart_file

このファイルを読み込む場合は、

dakota -i dakota.in -read_restart my_restart_file

で良いとのこと。-write_restartと -read_restartで同時にファイルを指定すると、-write_restartの指定にappendする。

さらに、

dakota -i dakota.in -r dakota.rst -s 50 -w dakota_new.rst

とすると、dakota.rstの最初の50個のevaluationを読み込み、計算を続行する。

 

cfMeshで機能追加を希望するところ

cfMeshをいろいろ使っていて、やっぱり非常に使いやすい。

ちょっと不具合があってtwitterでぼやいていたら、わざわざ中の人が声を掛けてくれて直してくれたし(正確には、自分のSTLデータの造り方が想定外だったようだけど)、非常に好感触である。

 

さらに使い勝手向上のためには、

  • MultiRegionへの対応
  • cellZoneを指定可(patchのrenameはできるので)

してくれると嬉しいかなーと思いました。まぁ、既存のやり方で十分対応できるんですが...。

VAWT翼型最適化(1)

子育てしてると時間の感覚がなくなってしまっていかんな。もう6月半ばになってしまった。7月上旬に岩手大で発表するのに間に合わせるために、ちゃんとやらねば。

 

VAWT用2次元翼型の形状最適化を行いたいのだが、メッシュの自動生成でblockMeshではなかなか狙った形状にならないということで、sHM, cfMeshでやることにした。

流れ的には以下の通り、

(cfMeshの場合)

  • 2次元翼型形状(修正PARSEC)の設計変数をもとに、ribbon状態のSTLデータを作成(自作python
  • cfMeshでrotorZoneのメッシュ作成(cartesian2DMesh)
  • mergeMeshesコマンドでstatorZoneメッシュと結合
  • pimpleDyMFoam

※ cfMeshの難点は、ベースメッシュが対称にならないこと。

(sHMの場合)

 

  • 2次元翼型形状(修正PARSEC)の設計変数をもとに、ribbon状態のSTLデータを作成(自作python
  • blockMeshでベースメッシュ作成
  • sHMでrotorZoneのメッシュ作成(extrudeMeshで2D化)
  • mergeMeshesコマンドでstatorZoneメッシュと結合
  • pimpleDyMFoam

まずはこれらのAllrunスクリプトを作ろう。