4263

チュートリアルフリーの可視化ソフトとして今日広く利用されている ParaView の使い方についてその初歩の初歩を解説します。本号では Fortran で開発しているプログラムにおいて、部分的に C++を用いて VTK 可視化モデルを出力することで効率的に ParaView にて可視化する方法を紹介します。ParaView 関連の書籍およびウェブ上にある ParaView の操作方法に関するドキュメ
ント類と併せてお読みください。

ParaView 超入門 其の五
大西 有希
1

はじめに

本稿はフリーの汎用可視化ソフトである「ParaView」の超入門チュートリアルの第五弾です。第四弾に引き続き、やや発展的な内容を紹介したいと思います。其の一〜三（Vol.23 No.4〜Vol.24 No.2）および其の四（Vol.26No.1）をご覧になっていない方はまずそちらからご覧になることをお勧めします。
其の四では vtm.series ファイルを用いることで時系列可視化データを簡便かつ効率的に ParaView で可視化する方法を紹介しました。紹介したデータ構造自体は使用する開発言語とは無関係なのですが、第三層の末端ファイルで用いる XML 形式の VTK ファイル（vtu ファイル等）は C++ の VTK ライブラリを用いて出力することが想定されています。従って、Fortran で開発しているプログラムでは紹介した方法をそのまま用いることが出来ません。そこで其の五では Fortran コードの中から VTK ライブラリを呼び出す方法を紹介します。
Web 検索して頂ければ分かる通り、Fortran から XML形式の VTK ファイルを出力する方法は幾つかあります。今回紹介する方法はネイティブな VTK ライブラリのみを使用しますので、他の方法に比べて信頼性・継続性が高いメリットがあります。他方、デメリットとしては C++ の知識が若干必要である点とコンパイルコマンドが若干複雑になる点が挙げられます。Fortran は書けるけど C++ は全く書けない、という方もおられるかと思いますが、C++ の記述部分は極めてシンプルですのでご安心ください。なお、本稿では x86_64の Linux上で Fortran90（F90）を使用する想定で解説を行います。
また、最後にオマケとして自宅等のリモート環境から会社等のサーバーに接続して ParaView で並列可視化を行う方法を解説します。その名の通り、ParaView は筆者紹介
おおにし ゆうき
2005年東京工業大学大学院情報理工学研究科博士課程修了、みずほ情報総研株式会社を経て、現在、東京工業大学工学院助教。固体の超大変形解析、腐食や電着塗装などの電気化学解析、熱／光インプリントのプロセス解析などの研究に従事。

Vol.26, No.2 2021

（35）

並列可視化に対応していますが今まで未解説でした。
ポートフォワードあるいは VPN を使用することで社外でも手軽に並列可視化が実現できますので、在宅勤務の方は是非お試しください。

2

VTK ライブラリのビルド

Fortran 用に書かれた BLAS や LAPACK のライブラリ
関数を C/C++ のコードから呼び出して使用されている方は数多くいらっしゃると思います。本稿で紹介する方法はその逆パターンとも言うべき方法です。つまり、C++ で書かれた VTK ライブラリの関数を Fortran のコードから呼び出して使用します（後述の通り正確には少し違うので、あくまで大まかなイメージの話です）。
従って、ネイティブな VTK ライブラリをビルドしておく必要があります。基本的には其の三にて紹介したビルド方法で良いのですが、VTK のバージョンがその当時 は8.2.0で し た が 執 筆 時 現 在 は9.0.1に 上 が っ た 影 響
で、少しだけ修正を加える必要があります。
VTK のウェブサイトから「VTK-9.0.1.tar.gz」をダウンロードし、其の三での解説手順に沿って ccmake のオプション選択画面まで進めます。8.2.0では● 「VTK_Group_Rendering」を OFF に変更● 「VTK_RENDERING_BACKEND」を None に変更を行っていましたが、9.0.1では上記の代わりに● 「VTK_GROUP_ENABLE_StandAlone」をWANT、それ
以 外 の「VTK_GROUP_ENABLE_*」をDONT_WANTに変更を行ってください。それ以降は其の三の通りに進めれば ~/local/lib/ 以下に「libVTK-9.0.1.a」が出来上がると思います。
続きは Web で
日本計算工学会誌「計算工学（Vol.26, No.2）」HP:
http://www.jsces.org/activity/journal/

チュートリアル

ParaView 超入門 其の五

ccmake のオプション選択に関して少し補足しておccmake のオプション選択に関して少し補足しておく
くと，出力に其の四で紹介したファイル構造を用いると、出力に其の四で紹介したファイル構造を用いるな
なら「VTK_USE_MPI」等は OFF のままがお勧めです．まら「VTK_USE_MPI」等は OFF のままがお勧めです。また，「VTK_SMP_IMPLEMENTATION_TYPE」を OpenMP や TBB
た、「VTK_SMP_IMPLEMENTATION_TYPE」 をにするか否かは各自の状況次第ですが，先ずはOpenMP や TBB に す る か 否 か は 各 自 の 状 況 次 第 で すSequential のまま試すのが良いでしょう．
が、先ずは Sequential のまま試すのが良いでしょう。
ま た ， 多 数 の libvtk*-9.0.a フ ァ イ ル を libVTKま た、 多 数 の libvtk*-9.0.a フ ァ イ ル を libVTK-9.0.1.a
9.0.1.a の１つにまとめるシェルスクリプトは下記のの1つにまとめるシェルスクリプトは下記の通りです。
通りです．
#!/bin/bash
rm -f libVTK-9.0.1.a
ar cqT libVTK-9.0.1.a libvtk*-9.0.acom="create libVTK-9.0.1.a¥n"for i in libvtk*-9.0.a; docom="${com}addlib $i¥n"
donecom="${com}save¥nend"
echo -e $com | ar -M
用済みになったは消してしまっても構用済みになったlibvtk*-9.0.a
libvtk*-9.0.a は消してしまっても構いまいません．
せん。

Fortran90のメインコード（main.f90）
３3 Fortran90のメインコード（main.f90）
では、最も単純と思われるサンプルコードを紹介しでは，最も単純と思われるサンプルコードを紹介していきます。まず、Fortran90で書かれたメインコードていきます．まず，Fortran90で書かれたメインコード（main.f90）の 中 身 を 図1に 示
し ま す。 座 標（0,0,0）、（main.f90）の中身を図１に示
しの4点ます．
（1,0,0）、（0,1,0）、 お よ び（0,0,1）に座粒標(0,0,0)，
子 が あ り、(1,0,0)，(0,1,0)，および(0,0,1)の４点に粒子があり，各各粒子がスカラー量6、7、8、および9をそれぞれ保持粒子がスカラー量 6, 7, 8,および 9 をそれぞれ保持してしている粒子法のデータだとお考えください。
いる粒子法のデータだとお考えください．
粒子数を N に、座標を pos に、スカラー量を val に格
粒子数を N に，座標を pos に，スカラー量を val に納し、C 言語で書かれた関数 write_vtu(N,pos,val) を呼び格納し，C 言語で書かれた関数 write_vtu(N,pos,val)を出して出力処理を委託しています。座標 pos は2次元配呼び出して出力処理を委託しています．座標 pos は２列ですが、write_vtu に渡す際にはあえて real(c_double)
次 元 配 列 で す が ， write_vtu に 渡 す 際 に は あ え て型の一次元配列としています。これは C/C++ と Fortranreal(c_double)型 の 一 次 元 配 列 と し て い ま す ． こ れ はで2次元配列のインデックス順が違うことから混乱を避C/C++と Fortran で２次元配列のインデックス順が違うけるためですが、各自でルールを定めて多次元配列をことから混乱を避けるためですが，各自でルールを定使用する分には問題ありません。
めて多次元配列を使用する分には問題ありません．
コードを見てお気付きの通り、f90のコードから直接コードを見てお気付きの通り，f90 のコードから直VTK の関数を呼び出している訳ではありません。次章
接 VTK の関数を呼び出している訳ではありません．
で解説する write_vtu 関数が VTK の関数を呼んでいます。
次章で解説する write_vtu 関数が VTK の関数を呼んでいます．
4C++ の VTK 出力用コード（write_vtu.cpp）

次に、C++ で書かれた VTK 出力用コード（write_vtu.
VTK 出力用コード（write_vtu.cpp）
４cpp）
C++のの中身を図2aおよび b に示します。N、pos、val の値を受け取り、それらを元にGrid
次 に ， C++ で 書 か れ た VTKVTKの 出
力データを構築用コード
し、最終的にvtuファイルを出力してくれる
Writer に（write_vtu.cpp）の中身を図２ａおよびｂに示します．
「output.vtu」
を書き出させています。
N,pos, val の値を受け取り，それらを元にVTK の Grid
冒頭の「#include」
文や「usingstd;」はおまじデータを構築し，最終的にvtu namespaceファイルを出力してくないです。
「extern “C”」の部分は C++ の関数を C からでれる
Writer に「output.vtu」を書き出させています．
も呼び出せる形式でオブジェクト化するためのおまじ
冒頭の「#include」文や「using namespace std;」はおないですが、write_vtuまじないです．
「extern 関数の引数を変えた場合はここ“C”」の部分は C++の関数を Cも同様に変える必要があります。以降の処理は其の三からでも呼び出せる形式でオブジェクト化するためのを読んで頂ければおよそ理解できるかと思います。
Grid の Points に座標データ pos を、PointData にスカラー計算工学

おまじないですが，write_vtu 関数の引数を変えた場合量 val をセットし、Writer を通じてそれらを LZMA 圧縮はここも同様に変える必要があります．以降の処理はして出力（ただし、DEBUG モードの場合は圧縮せずに其の三を読んで頂ければおよそ理解できるかと思いまアスキー出力）しています。
す．Grid の Points に座標データ pos を，PointData にス
全体の処理の流れを要約すると、出力処理を main が
カ ラ ー 量 val を セ ッ ト し， Writer を通 じ て そ れ ら を
まず write_vtu に委託し、write_vtu がそれを VTK に再委
LZMA 圧縮して出力（ただし，DEBUG モードの場合託している、と言えます。Fortran から直接 VTK の関数は圧縮せずにアスキー出力）しています．
を呼ぼうとするとかなりハードルが高いですが、間に全体の処理の流れを要約すると，出力処理を main がwrite_vtuを挟むことでコーディングが簡単になります。
まずwrite_vtuに委託し，write_vtu がそれを VTK に再委託している，と言えます．Fortran から直接 VTK の5 コンパイルとリンク関数を呼ぼうとするとかなりハードルが高いですが，間にでは、実際にこのコードを動かしてみます。図3の手
write_vtu を挟むことでコーディングが簡単にな順でコンパイルとリンクを行うと、実行ファイル「a.
ります．
out」が出来上がるハズです。見易さを重視してコンパ５イルのコマンドにはあえて最適化オプションを付けてコンパイルとリンクいませんので、必要に応じて足してください。リンク
では，実際にこのコードを動かしてみます．図３のに加え手のコマンドには2章でビルドした
順 で コ ン パ イ ル と リ ン ク を 行 うlibVTK-9.0.1.aと，実行ファ
イルて libstdc++、libdl、および libpthread ともリンクするよ「a.out」が出来上がるハズです．見易さを重視してコう指示しています。
ンパイルのコマンドにはあえて最適化オプションを付も し リ ン ク 時 に エ ラ ー が 起 こ り、 位 置 独 立 実 行
けていませんので，必要に応じて足してください．リ（PositionIndependent Executable: PIE）形式のオプション
ンクのコマンドには２章でビルドした
libVTK-9.0.1.a「-fPIE」を指定してライブラリを作り直せと怒られた場に加えてlibstdc++，libdl，および libpthread ともリンク
合、VTK ライブラリのビルドをやり直す必要がありまするよう指示しています．
す。本稿2章ののアドバンスドモードに入ったも し リ ン ク 時ccmakeにエラーが起こり，位置独立実行所で、下記2つの処理を追加してください。
(Position Independent Executable: PIE)形式のオプション● 「CMAKE_CXX_FLAGS_RELEASE」に -fPIE を追記「-fPIE」を指定してライブラリを作り直せと怒られた● 「CMAKE_C_FLAGS_RELEASE」にも -fPIE” を追記
場合，VTK ライブラリのビルドをやり直す必要があり出来上がった「a.out」
を実行すると、N、pos、valのます．本稿２章のccmakeのアドバンスドモードに入った所で，下記２つの処理を追加してください．
各値が画面に表示されると同時に、「output.vtu」が出力
さ れ「CMAKE_CXX_FLAGS_RELEASE」に-fPIEを追記
ま す。 こ れ を ParaView で 開 い て 見 て くだ さ い。
Points「CMAKE_C_FLAGS_RELEASE」にも-fPIE”を追記と PointData のみの（Cells や CellData の無い）粒子
出来上がった「a.out」を実行すると，N,val
法用データのため、まずは表示方法を「Pointpos,Gaussian」の各値が画面に表示されると同時に，「output.vtu」がに変更します。粒子が小さ過ぎたり大き過ぎたりする
出力されます．これをParaView
で開いて見てくださ場 合 は、Properties タ ブ
内 の PointGaussian の Gaussianい．
PointsとPointDataのみの（Cellsや CellData のRadius を増減して丁度良い大きさに変更してくださ無い）
粒子法用データのため，まずは表示方法を「Pointい。表示量として「Value」を選択すると、図4の様な絵Gaussian」に変更します．粒子が小さ過ぎたり大き過が表示されると思います。
ぎ た り す る 場 合 は ， Properties タ ブ 内 の Point
Gaussianの Gaussian Radius を増減して丁度良い大き6 自作コードへ実装する際のTipsさに変更してください．表示量として「Value」を選択
上記で示したサンプルコードはあくまで最も単純とすると，図４の様な絵が表示されると思います．
思われる例であり、自作コードに実装する場合はより複雑になるかと思います。実装の仕方は人それぞれでTips を幾つか挙げておきます。
５すが、著者が思う自作コードへ実装する際のTips➢ Fortran から呼ぶ C++ の関数を増やさない。
上記で示したサンプルコードはあくまで最も単純と原則として、Fortran から呼ぶ C++ の関数は write_思われる例であり，自作コードに実装する場合はよりvtu のみで良いと思います。出力に必要なデータを複雑になるかと思います．実装の仕方は人それぞれでwrite_vtu 関数の引数に必要なだけ並べ、委託処理すが，著者が思う Tips を幾つか挙げておきます．
は一発で済ます方が可読性が上がるでしょう。例Fortran から呼ぶ C++の関数を増やさない．
えば有限要素法のデータを可視化する場合、Cells
原 則 と し て ， Fortran か ら 呼 ぶ C++ の 関 数 はや CellData となるデータの配列を write_vtu 関数のwrite_vtu のみで良いと思います．出力に必要なデ引数に必要なだけ追加します。
ータを write_vtu 関数の引数に必要なだけ並べ，➢ メモリアクセス違反チェックを頻繁に実施する。
委託処理は一発で済ます方が可読性上がるでしC と Fortran では多次元配列のインデックスが異なるため、紹介した方法はメモリアクセス違反を起（35-2）

Vol.26, No.2 2021

チュートリアル➢

7

ParaView 超入門 其の五

こしやすい方法です。コンパイラオプションあるいは valgrind 等を用いてメモリアクセス違反をこまめにチェックするようにしましょう。
vtm.series と vtm は Fortran から出力する
其の四で紹介した可視化ファイル構造を用いる場
合、C++ が出力するのは末端ファイル（vtu 等）のみで良いでしょう。vtm.series と vtm は Fortran の write
関数でも十分書けるので、わざわざ C++ に委託する必要はないでしょう。

おまけ：リモート並列可視化方法

最後におまけですが、自宅等のリモート環境から会社等のサーバーに接続し、ParaView で並列可視化を行う方法を紹介します。
ParaView リモート並列可視化を行うには次の3つの条件をクリアする必要があります。
1. 同じバージョンのParaViewがサーバーとクライアント（自宅PC等）の両方にインストールされている。
2. サーバーに ssh 等でリモートからログインして使用することが出来る。
3. サーバーと同じネットワークにリモートから VPNで入れる。または会社のルーターに対してポートフォワード機能を設定できる（自分がサーバーで開いたポートにクライアントからアクセス出来る）。
ポートフォワードを好き勝手に設定できる人は極少数かと思いますので、VPN が現実的かと思います。ただし、VPN が遅い場合、可視化速度は当然遅くなります。また、VPN のルートは適切に設定されているものとします。
次にリモート並列可視化手順を示します。
（ア）可視化データをサーバー上に置く。
（イ）サーバーで pvserver を起動する。コマンド例は以下の通り。
/opt/paraview/ParaView-5.9.0-MPI-Linux-Python3.864bit/bin/mpiexec -n $OMP_NUM_THREADS /opt/
paraview/ParaView-5.9.0-MPI-Linux-Python3.8-64bit/
bin/pvserver「-n」の後ろには並列数を指定するが、ここでは簡単のため環境変数 OMP_NUM_THREADS を指定している。デフォルトでは11111番ポートが使用されるが、これを変更したい場合は「-sp=22222」の様にオプションを追加する。実行後に表示されるConnection URL の内容（「cs://servername:11111」等）をメモしておく。

計算工学（ウ）クライアント（Windowsも可）でparaviewを起動する。
（エ）クライアントの paraview で File → Connect を選び、Add Server から上記の Connection URL のサーバーを登録する（初回のみ）。ただし、servername がクライアント環境で resolve 出来ない場合、VPN から到達できるローカル IP を記述する。登録済みのサーバーに対して Connect を実施する。
（オ）し ば ら く 待 っ て、Pipeline Browser に 登 録 し たConnection URL が表示されれば接続完了。後はサーバーで ParaView を起動しているかの様に使える。
（カ）作 業 後 は ParaView を 普 通 に 終 了 し て も 良 い し、File → Disconnect で切断しても良い。
（キ）サーバーの pvserver が終了していることを確認する。終了していない場合は Ctrl-c 等で強制的に落とす。
注意点として、バージョンの古い ParaView の場合、pvserver の CPU 使用率が常に100% に張り付くことがあります。猛烈に電力を消費するので、定期的にチェックするか、ParaView のバージョンアップを行ってください。
あと、最近の ParaView には Auto MPI（Edit → Settings →General → Enable Auto MPI）の機能が搭載されています
が、著者はこの機能をお薦めしません。著者の使い方が悪いのかも知れませんが、経験上あまり速くなっている感じがしません。加えて、自宅の家庭用 PC を使用して並列可視化しても結局すぐにメモリの上限に達してしまうので、あまり有用では無いように思います。

8

おわりに全五回にわたり ParaView のチュートリアルを執筆し、著者としては流石にネタ切れとなっております。
出来れば pvbatch で Python スクリプトを走らせる話をご紹介したかったのですが、この機能は著者自身も騙し騙し使用している状態で、チュートリアルで紹介出来る程にまとめることが出来ませんでした。Tools → Start
Trace および Stop Trace で保存したスクリプトファイルを手修正して pvbatch に食わせていますが、思い通りに行かないケースも多く、未だ試行錯誤しています。続編をどなたかに執筆して頂ければ大変ありがたいので、是非ご連絡頂けたらと思います。
紹介した種々の方法が皆様のお役に立てば幸いです。コロナ禍の今しばらくの間、快適な在宅可視化ライフをお過ごし下さい。

（35-3）

Vol.26, No.2 2021

チュートリアル

ParaView 超入門 其の五

program main!!!!!! preamble
use iso_c_binding
implicit none!!!!!! interface
interfacesubroutine write_vtu(N,pos,val) bind(c)Importinteger(c_int), VALUE :: Nreal(c_double) :: pos(*)
real(c_double) :: val(*)
end subroutine write_vtu
end interface!!!!!! datainteger(c_int), parameter :: N = 4 ! The number of particles
real(c_double), parameter :: pos(3,N) = reshape((/ & ! Position coordinates0., 0., 0., &1., 0., 0., &0., 1., 0., &0., 0., 1. &/), (/3,N/))real(c_double), parameter :: val(N) = (/ & ! Point data values6., &7., &8., &9. &/)
integer(c_int) i, j!!!!!! debug print
write(*,*) "main: N = ", Nwrite(*,*) "main: pos = "; do i=1,N; write(*,'(99e11.3)') (pos(j,i), j=1,3);
enddo
write(*,*) "main: val = "; do i=1,N; write(*,'(99e11.3)') val(i); enddo!!!!!! call
call write_vtu(N,pos,val)!!!!!! postamble
write(*,*) "done."end program main
図１：Fortran90のメインコード（main.f90）
図1 Fortran90のメインコード（main.f90）

計算工学（35-4）

Vol.26, No.2 2021チュートリアル

ParaView 超入門 其の五#include <vtkSmartPointer.h>#include <vtkUnstructuredGrid.h>#include <vtkXMLUnstructuredGridWriter.h>#include <vtkFloatArray.h>#include <vtkPointData.h>using namespace std;///////////////////////////////////////////////////////////////////////////////
extern "C"{void write_vtu(int, double*, double*);}///////////////////////////////////////////////////////////////////////////////
void write_vtu(int N,double* pos,double* val){//////// debug print ////////
cout << "write_vtu: N = " << N << endl;
cout << "write_vtu: pos =¥n"; for(int i=0; i<N; i++){ for(int j=0; j<3;j++){ cout << " " << pos[3*i+j]; } cout << endl; }cout << "write_vtu: val =¥n"; for(int i=0; i<N; i++){ cout << " " << val[i] <<endl; }//////// Grid ////////
auto Grid = vtkSmartPointer<vtkUnstructuredGrid>::New();//////// Points ////////
auto Points = vtkSmartPointer<vtkPoints>::New();
Points->SetDataTypeToFloat();Points->SetNumberOfPoints(N);for(int i=0; i<N; i++){Points->SetPoint(i, &pos[3*i]);}
Grid->SetPoints(Points);//////// PointData ////////
auto FloatArray = vtkSmartPointer<vtkFloatArray>::New();
FloatArray->SetNumberOfTuples(N);FloatArray->SetName("Value");for(int i=0; i<N; i++){FloatArray->SetTuple1(i, val[i]);}Grid->GetPointData()->AddArray(FloatArray);
図2a C++ のVTK出力用コード（write_vtu.cpp）の前半
出力用コード（write_vtu.cpp）の前半
図２ａ：C++のVTK

計算工学（35-5）

Vol.26, No.2 2021

チュートリアル

ParaView 超入門 其の五//////// Writer
Writer ////////////////////////
auto Writer
Writer == vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New();
auto
Writer->SetFileName("output.vtu");Writer->SetFileName("output.vtu");Writer->SetInputData(Grid);
Writer->SetInputData(Grid);#ifdef DEBUG
DEBUG#ifdefWriter->SetDataModeToAscii();
Writer->SetDataModeToAscii();
Writer->SetCompressorTypeToNone();Writer->SetCompressorTypeToNone();#else///DEBUG#else///DEBUG
Writer->SetByteOrderToLittleEndian();Writer->SetByteOrderToLittleEndian();Writer->SetDataModeToBinary();
Writer->SetDataModeToBinary();
Writer->SetDataModeToAppended();Writer->SetDataModeToAppended();Writer->SetEncodeAppendedData(0);Writer->SetEncodeAppendedData(0);Writer->SetCompressorTypeToLZMA();
Writer->SetCompressorTypeToLZMA();#endif//DEBUG#endif//DEBUG
Writer->Write();Writer->Write();}}
図２ｂ：C++のVTK
出力用コード（write_vtu.cpp）の後半
図2b C++VTKの VTK
出力用コード（write_vtu.cpp）の後半
図２ｂ：C++の出力用コード（write_vtu.cpp）の後半# main.f90 のコンパイル# main.f90 のコンパイル
gfortran -c main.f90
gfortran -c main.f90# write_vtu.cpp のコンパイル# write_vtu.cpp のコンパイルg++ -c write_vtu.cpp -I$HOME/local/include/vtk-9.0
g++ -c write_vtu.cpp -I$HOME/local/include/vtk-9.0
# リンク
# リンク
gfortran main.o write_vtu.o $HOME/local/lib/libVTK-9.0.1.a -lstdc++ -ldl -lpthread
gfortran main.o write_vtu.o $HOME/local/lib/libVTK-9.0.1.a -lstdc++ -ldl -lpthread

図３：コンパイルおよびリンクのコマンド
図３：コンパイルおよびリンクのコマンド
図3 コンパイルおよびリンクのコマンド

図４：サンプルコードの出力ファイル（output.vtu）の可視化例
図4 サンプルコードの出力ファイル（output.vtu）の可視化例
図４：サンプルコードの出力ファイル（output.vtu）の可視化例
計算工学（35-6）

Vol.26, No.2 2021