MD計算のあとはやっぱりビジュアライズしたい。昔はAtomeyeを使っていたが、最近はOVITOを使っている。超優秀なのにフリーで使える素晴らしいソフトウェアだ。
OVITOを使うときは、下記のような手順でレンダリングに至る。

近年、コンピュータの高度化により、MD計算は大量の計算結果を吐き出せるようになった。データが増えてくると、これを一つ一つ手作業でやってたら時間がいくらあっても足りない。そこで、スクリプトによる自動化をしたいと思うのは自然な流れだ。
OVITOではPythonのライブラリが用意されていて、Pythonを使って自動化が可能なようである。なんて素晴らしいOVITO。マニュアルを読んで早速チャレンジしてみようと思う。
ライブラリインストール
pipでインストールできる。便利。
pip install ovito
M1 MacはmacOS12.0以上必要なので、11使ってる人はアップデート必要。
ファイルの読み込み
from ovito.io import import_file
pipeline = import_file("simulation.dump")
いろんな形式のファイルが読み込める。Input file formats参照。
modifilerを適用
必要なmodifierを追加していく。詳細はマニュアル参照。
from ovito.modifiers import CommonNeighborAnalysisModifier
from ovito.modifiers import SelectTypeModifier
from ovito.modifiers import DeleteSelectedModifier
from ovito.modifiers import SliceModifier
from ovito.modifiers import CoordinationAnalysisModifier
from ovito.modifiers import ColorCodingModifier
pipeline.modifiers.append(CommonNeighborAnalysisModifier())
pipeline.modifiers.append(SelectTypeModifier(property="Structure Type", types={CommonNeighborAnalysisModifier.Type.BCC}))
pipeline.modifiers.append(DeleteSelectedModifier())
pipeline.modifiers.append(SliceModifier(distance=290, normal=(0,0,1)))
pipeline.modifiers.append(SliceModifier(distance=-10, normal=(0,0,-1)))
pipeline.modifiers.append(CoordinationAnalysisModifier())
pipeline.modifiers.append(ColorCodingModifier(property='Coordination'))
シーンに追加・他
cell_vis = pipeline.source.data.cell.vis.rendering_color = (0,0,0) #simulation cellの色
pipeline.add_to_scene()
ビューポート作成
from ovito.vis import Viewport
vp = Viewport()
vp.type = Viewport.Type.Perspective
vp.camera_dir = (-1,1,-1)
vp.zoom_all()
vp.render_image(size=(800,600), filename="figure.png", background=(1,1,1))
結果
例えば以下のような画像が出力される。

Modifierは、OVITO使って何をどういう順番で適用するか事前に確認しておけばマニュアル見てすぐに実装できる。あとは、ループで回しまくればOK(ループで回しまくるときは、pipeline.remove_from_scene()をつけましょう)。すげーよOVITO。
並列化
原子数にもよると思うが、joblib等で並列化しないとレンダリングが遅い。joblibでレンダリングだけ並列化しようと思ったが、ViewportとかPipelineがpickle化できないと怒られて進めなかったので、全部並列化する関数にぶっこんだらOKだった。画像一つの書き出し時間は変わらないが、プロセス数の数だけ早くなる。多コアは正義。
import joblib
import glob
def render(file):
(省略:上に同じ)
pipeline.remove_from_scene(). # これしないと前の画像の上に更に画像が重ねられて画像が作られる。
files = glob.glob('dislocation/[0-9]*.dump')
joblib.Parallel(n_jobs=-1)(joblib.delayed(render)(file) for file in files)
(少しハマった)pipeline.remove_from_scene()をつけないと、どんどんとシーンが追加されていくため、誤った画像が出力される。それにメモリの使用量がどんどん膨らんでいってパンクする。おそらくfor文で単純に回す場合でも同様と思う。