LabCodehttps://labo-code.com研究で使えるプログラミングをSun, 30 Nov 2025 15:00:35 +0000jahourly1https://labo-code.com/wp-content/uploads/2022/02/labcode_symbolmark_color_220208-150x150.pngLabCodehttps://labo-code.com3232 173295403FEgrowを用いたアクティブラーニングによる化合物スクリーニングの高速化【In silico創薬】https://labo-code.com/bioinformatics/insilico-screening-with-fegrow/https://labo-code.com/bioinformatics/insilico-screening-with-fegrow/#respondSun, 30 Nov 2025 15:00:31 +0000https://labo-code.com/?p=7048

本記事では、**FEgrow**というインシリコ創薬ツールとアクティブラーニング(Active Learning, AL)を組み合わせ、in silico screeningで得られた化合物を基にさらに効率よくスクリーニ ...

The post FEgrowを用いたアクティブラーニングによる化合物スクリーニングの高速化【In silico創薬】 first appeared on LabCode.

]]>

本記事では、**FEgrow**というインシリコ創薬ツールとアクティブラーニング(Active Learning, AL)を組み合わせ、in silico screeningで得られた化合物を基にさらに効率よくスクリーニングしていく方法を紹介します。

動作検証済み環境

動作検証済み環境

Windows 11 Home, 13th Gen Intel(R) Core(TM) i7-13700,
64 ビット オペレーティング システム、x64 ベース プロセッサ, メモリ:32GB

FEgrowとは?

FEgrowは、フラグメント分子(足場となる小さな分子)に、多様なリンカーや置換基(R-groups)を結合させることで、官能基を置換した化合物ライブラリを仮想的に構築し、その中から有望な化合物を効率的に設計・評価するためのツールです。

今回は、FEgrowのチュートリアルをフォローします。

新型コロナウイルスのメインプロテアーゼ(SARS-CoV-2 Mpro)を標的とした仮想的な化学空間(Chemical Space)から、予測される結合親和性(pK)を最適化する化合物を優先的に選定する過程を追っていきます。

アクティブラーニング(Active Learning)とは?


アクティブラーニング(AL)は、機械学習の一種で、「学習データが不足している状況下で、どのデータ(化合物)を優先的に評価すれば、最も効率よくモデルの精度を高められるか?」を自律的に判断する手法です。

創薬研究におけるALの役割は以下の通りです。

  1. 初期評価(ランダムサンプリング): まず少数の化合物をランダムに選び、その結合親和性を計算(評価)します。
  2. モデル構築: 評価結果を基に、未評価の化合物群のスコア(結合親和性)を予測する機械学習モデルを構築します。
  3. 情報量に基づく選択: モデルの予測結果から、「最もスコアが高そう」または「予測の不確実性が高く、評価すればモデルが大きく改善しそう」な化合物を、優先的に選択します。
  4. 再評価と学習: 選択した化合物を実際に評価し、その結果をモデルにフィードバック(学習)させることで、モデルの予測精度を向上させます。

このサイクルを繰り返すことで、全化合物を評価せずとも、最終的に目的とする**高性能な化合物(高い結合親和性を持つ化合物)に効率よくたどり着くことが可能になります。

FEgrowは、このALの仕組みを、化合物の設計・ドッキング評価プロセスに組み込むことを可能にしています。

環境構築

installationの資料はこちら

以下をターミナルで打ちます。

# Miniforge3インストーラをダウンロード
# uname コマンドでOSとアーキテクチャ名を取得し、適切なファイル名を構築
curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"
# Miniforge3をインストール
bash Miniforge3-$(uname)-$(uname -m).sh
# 👇ここからconda環境を初期化・設定
# Condaの初期設定を行うためのフックを現在のシェルセッションにロード
# /home/shizuku/miniforge3/ はMiniforge3のインストール先ディレクトリに合わせる
eval "$(/home/shizuku/miniforge3/bin/conda shell.bash hook)"
# bashシェルでcondaコマンドを適切に動作させるために初期化設定をシェル設定ファイル(例: ~/.bashrc)に書き込む
conda init bash
# シェル設定ファイル(.bashrc)を再読み込みし、上記の設定を現在のセッションに反映
source ~/.bashrc
# 👇ここからFEgrowのセットアップ
# FEgrowリポジトリをクローン(作業ディレクトリはどこでも可)
git clone https://github.com/cole-group/FEgrow.git
# クローンしたディレクトリに移動
cd FEgrow
# mamba(condaの高速版)を使って、environment.ymlファイルに基づいて仮想環境を作成
mamba env create -f environment.yml
# 作成した仮想環境 'fegrow' をアクティベート
conda activate fegrow
# FEgrowパッケージを依存関係なしでインストール(開発モードや、環境ファイルが依存関係を処理済みのため)
# 最後のピリオド '.' はカレントディレクトリ(FEgrowのルート)にあるセットアップファイルを参照
pip install --no-deps .
コマンド説明
curl -L -O ...Miniforge3インストーラのダウンロード
  • curl: URLからデータを転送するためのコマンドラインツール。
  • -L: リダイレクトを辿る(GitHubの「latest」リンクに対応するため)。
  • -O: ダウンロードしたファイルを、リモートファイル名と同じ名前で現在のディレクトリに保存する。
  • $(uname)$(uname -m): OS名(例: Linux, Darwin)とアーキテクチャ名(例: x86_64, arm64)をコマンド実行時に動的に取得し、適切なインストーラファイル名を構築する。 | | bash Miniforge3-$(uname)-$(uname -m).sh | Miniforge3のインストール。ダウンロードしたシェルスクリプトを実行し、Miniforge3をインストールする。 | | eval "$(/home/shizuku/miniforge3/bin/conda shell.bash hook)" | Condaの初期設定を現在のシェルセッションにロードcondaコマンドを一時的に利用可能にするための設定(フック)を現在のセッションに適用する。miniforge3のインストールパスは環境によって異なる可能性があります。 | | conda init bash | Condaの永続的な初期設定condaコマンドを次回以降のシェル起動時にも使えるように、使用しているシェル設定ファイル(~/.bashrcなど)に設定を書き込む。 | | source ~/.bashrc | 設定ファイルの再読み込みconda init bashで書き込まれた設定を現在のシェルセッションに反映させるために、設定ファイル(ここでは.bashrc)を再読み込みする。 | | git clone https://github.com/cole-group/FEgrow.git | リポジトリのクローン。指定されたURLからFEgrowのGitリポジトリを現在のディレクトリにダウンロードする。 | | cd FEgrow | ディレクトリの移動。クローンして作成されたFEgrowディレクトリに移動する。 | | mamba env create -f environment.yml | 仮想環境の作成mamba(condaの高速な実装)を使用して、environment.ymlファイルに記述されている依存関係(パッケージ)を持つ仮想環境を作成する。 | | conda activate fegrow | 仮想環境の有効化。新しく作成されたfegrowという名前の仮想環境を現在のシェルセッションでアクティブにする。これにより、その環境内のPythonやパッケージが使えるようになる。 | | pip install --no-deps . | パッケージのインストール。カレントディレクトリ(.)にあるPythonパッケージ(FEgrow自体)をインストールする。
  • pip: Pythonのパッケージ管理システム。
  • --no-deps: 依存関係のチェックとインストールをスキップする(既にmamba env createで依存関係が処理されているため)。
  • .: カレントディレクトリを参照し、setup.pyまたはpyproject.tomlに基づいてパッケージをインストールする。 |

クローンしてきたFEgrowのtutorialsの2_tutorial_active_learning.ipynb をcursorで開き、一つずつrunしてください。

cursorでのjupyter環境の設定は以下をご覧ください。

📰 環境構築|【完全版】In silico創薬実践書 〜おうち創薬で論文を書こう〜

FEgrowによるアクティブラーニングの実行

全コードはこちらを参考にしています。一部うまくいかなかった部分があるので、少し変更しています。チュートリアルとほぼ一緒ですが、GPUは使用しておりません。gnina_gpu =False にして実行しています。

# ----------------------------------------------------
# STEP 1: 準備と環境設定
# ----------------------------------------------------
# 必要なライブラリをインポート
import prody # タンパク質(受容体)の操作・解析用ライブラリ
from rdkit import Chem # 分子構造(化学)の操作用ライブラリ
import fegrow # 分子の拡張とドッキング(結合予測)を行う中心ライブラリ
# fegrow内の主要なクラスをインポート
from fegrow import ChemSpace, Linkers, RGroups
from fegrow.al import Model, Query # Active Learning(能動学習)のモデルとクエリをインポート
rgroups = RGroups() # 利用可能なRグループ(置換基)のコレクションを準備
linkers = Linkers() # 利用可能なリンカー(つなぎ)のコレクションを準備
# DaskのLocalClusterを設定し、計算を並列化(複数のCPUコアで同時に実行)できるようにする
from dask.distributed import LocalCluster
lc = LocalCluster(processes=True, n_workers=None, threads_per_worker=1)
# create the chemical space (化学空間、つまり作成する可能性のある分子の集合) を作成
cs = ChemSpace(dask_cluster=lc) # Daskクラスターと関連付ける
cs
# turn on the caching in RAM (optional)
# 計算結果をメモリ(RAM)にキャッシュし、処理を速くする(任意)
cs.set_dask_caching()
# ----------------------------------------------------
# STEP 2: 足場分子とターゲットタンパク質の準備
# ----------------------------------------------------
# 足場(コアとなる分子骨格)の構造ファイル(.sdf)を読み込む
init_mol = Chem.SDMolSupplier("sarscov2/5R83_core.sdf", removeHs=False)[0]
# rdkitのMolオブジェクトをfegrow特有のRMol形式に変換
scaffold = fegrow.RMol(init_mol)
# 足場の2D画像を表示(idx=Trueで原子番号を表示、サイズを指定)
scaffold.rep2D(idx=True, size=(500, 500))
# specify the attachment point (in this case hydrogen atom number 6)
# どこに新しい部分をつなぐか(ここでは原子番号6の水素の位置)を指定
attachmentid = 6
# 接続ポイント(原子番号6)の原子をダミー原子(原子番号0、通常は'*')に置き換える
scaffold.GetAtomWithIdx(attachmentid).SetAtomicNum(0)
cs.add_scaffold(scaffold) # 処理した足場を化学空間に追加
# load the receptor structure
# ターゲットタンパク質(受容体)の構造ファイル(.pdb)を読み込む
sys = prody.parsePDB("sarscov2/5R83_final.pdb")
# remove any unwanted molecules
# 受容体から核酸、ヘテロ原子(cofactorなど)、水分子を除外して純粋なタンパク質を抽出
rec = sys.select("not (nucleic or hetatm or water)")
# save the processed protein
# 処理済みのタンパク質を新しいファイルに保存
prody.writePDB("rec.pdb", rec)
# fix the receptor file (missing residues, protonation, etc)
# 受容体ファイルに残基の欠損修正やプロトン化状態の調整などを行う
fegrow.fix_receptor("rec.pdb", "rec_final.pdb")
cs.add_protein("rec_final.pdb") # 最終的な受容体(タンパク質)を化学空間に追加
# ----------------------------------------------------
# STEP 3: 化学空間の構築(分子候補の網羅的な作成)
# ----------------------------------------------------
numlinkers = 50 # 試すリンカーの数
numrgroups = 50 # 試すRグループの数
# 指定された数のリンカーとRグループの全ての組み合わせを作成し、化学空間に追加する
for i in range(numlinkers): if i % 10 == 0: print(i) # 進行状況を10個ごとに表示 for j in range(numrgroups): # リンカー[i]とRグループ[j]を組み合わせて化学空間に分子の候補を追加 cs.add_rgroups(linkers.Mol[i], rgroups.Mol[j])
# The chemical space now includes our 2500 small molecules:
# 化学空間に分子候補の総数(50x50=2500)が追加された
cs
# 化学空間の最初の分子(cs[0])の2D構造を表示
cs[0].rep2D()
# ----------------------------------------------------
# STEP 4: 能動学習(Active Learning)の初期評価
# ----------------------------------------------------
# Pick 50 random molecules
# Active Learning(能動学習)の最初のステップとして、ランダムに50個の分子を選ぶ
random1 = cs.active_learning(50, first_random=True)
# now evaluate the first selection, note that dask is used to parallelise the calculation
# 選ばれた50個の分子に対してドッキングシミュレーションを実行
# daskが並列計算を行う
# molecules that cannot be built assigned a predicted affinity of 0
# gnina_gpu=Falseに変更 (GPUを使わずにCPUでgninaを実行することを指定)
random1_results = cs.evaluate( random1, num_conf=50, gnina_gpu=False, penalty=0.0, al_ignore_penalty=False
)
random1_results # 結果(ドッキングスコアなど)を表示
# スコア(計算値)がある(NaNではない)分子だけを抽出
computed = cs.df[~cs.df.score.isna()]
print("Computed cases in total: ", len(computed)) # 計算された分子の総数を表示
# ----------------------------------------------------
# STEP 5: AIモデルの学習と最適分子の選択
# ----------------------------------------------------
# チュートリアルにはない部分。付け足しました。
# gninaのパスを明示的に設定
import os
from pathlib import Path
# 現在のディレクトリのgninaバイナリを設定(セキュリティや環境依存性のため)
gnina_path = os.path.abspath("gnina")
if os.path.exists(gnina_path): fegrow.RMol.set_gnina(gnina_path) # gnina実行ファイルの場所をfegrowに教える print(f"gnina path set to: {gnina_path}")
else: # gninaが見つからない場合はメッセージを表示 print(f"gnina not found at: {gnina_path}") print("Available files in current directory:") for f in os.listdir("."): if "gnina" in f.lower(): print(f" - {f}")
# AIの学習モデルとしてガウス過程を設定
cs.model = Model.gaussian_process()
# 分子選択の戦略としてUCB (Upper Confidence Bound) を設定(探索と利用のバランスをとる)
cs.query = Query.UCB(beta=1)
# gnina_gpu=Falseでないとうまくいかない。 # 環境によってはGPUの使用がうまくいかないため、CPUに固定する
for cycle in range(3): # 能動学習のプロセスを3回繰り返す print(f"Starting cycle {cycle + 1}/3...") # 現在のサイクル数を表示 try: # AIモデルと選択戦略に基づいて、次に計算すべき最適な50個の分子を選ぶ picks = cs.active_learning(50) print(f"Selected {len(picks)} molecules for evaluation") # 選ばれた分子数を表示 # 選ばれた50個の分子をドッキングシミュレーションで評価 picks_results = cs.evaluate( picks, num_conf=50, gnina_gpu=False, penalty=0.0, al_ignore_penalty=False # num_conf=50: 分子の立体構造(コンフォメーション)を50個生成して試す # gnina_gpu=False: GNINAをCPUで実行するように指定 ) # save the new results # 今回の結果をサイクルごとに異なるCSVファイルに保存 picks_results.to_csv(f"notebook_iteration{cycle}_results.csv") print(f"Cycle {cycle + 1} completed successfully. Results saved to notebook_iteration{cycle}_results.csv") except Exception as e: # エラーが発生した場合、メッセージを表示し、次のサイクルへ進む print(f"Error in cycle {cycle + 1}: {str(e)}") print("Continuing with next cycle...") continue
cs.model = Model.gaussian_process() # Active Learning(能動学習)のモデルとしてガウス過程を設定
cs.query = Query.Greedy() # 次に評価する分子の選択戦略としてGreedy(貪欲法)を設定
# モデルを使って予測し、次に計算すべき最適な50個の分子を選ぶ
picks = cs.active_learning(50)
# 選ばれた50個の分子をドッキングシミュレーションで評価
picks_results = cs.evaluate( picks, num_conf=50, gnina_gpu=False, penalty=0.0, al_ignore_penalty=False
)
# save the new results
picks_results.to_csv("notebook_greedy_results.csv") # 結果をCSVファイルに保存
# ----------------------------------------------------
# STEP 6: 結果の統合と上位分子の抽出・保存
# ----------------------------------------------------
# save the chemical space of built molecules:
# 構築された(または構築できなかった)全ての分子を含む化学空間を保存する準備
failed = False
unbuilt = False
# 結果をSDファイル(分子構造とそのプロパティを格納するファイル形式)として書き出す
with Chem.SDWriter("notebook_chemspace.sdf") as SD: # 分子構造以外のプロパティ(スコア、成功フラグなど)の列名リストを作成 columns = cs.df.columns.to_list() columns.remove("Mol") # 化学空間内の全ての行(分子候補)をループ処理 for i, row in cs.df.iterrows(): # ignore this molecule because it failed during the build # 構築に失敗した分子をスキップする設定(failed=Falseなのでスキップしない) if failed is False and row.Success is False: continue # ignore this molecule because it was not built yet # 未構築の分子をスキップする設定(unbuilt=Falseなので、SuccessがFalseならスキップしない) if unbuilt is False and not row.Success: continue mol = row.Mol # RDKit Molオブジェクトを取得 mol.SetIntProp("index", i) # 元のインデックスをプロパティとして設定 for column in columns: # 各プロパティをMolオブジェクトに設定 value = getattr(row, column) mol.SetProp(column, str(value)) mol.ClearProp("attachement_point") # 不要なプロパティをクリア SD.write(mol) # SDファイルに分子構造とプロパティを書き込む
# save the structures of the top 10 molecules in ranked order as a sdf file:
# ドッキングスコアの高い上位10個の分子を保存する処理
molecules = []
input_sdf = "notebook_chemspace.sdf" # 保存したSDファイル
best_n = 10 # 上位10個
with Chem.SDMolSupplier(input_sdf) as SDF: # for each mol # 保存したSDファイルから分子を一つずつ読み込む for mol in SDF: if mol is None: # 読み込めなかったらスキップ continue # 構築に成功した分子('Success'プロパティが'True')のみをリストに追加 if mol.GetPropsAsDict()["Success"] == "True": molecules.append(mol)
# sort by the key
# 分子リストを、プロパティの'score'の値(ドッキングスコア)で降順(reverse=True、高いスコアが先)にソート
sorted_molecules = sorted( molecules, key=lambda m: m.GetPropsAsDict()["score"], reverse=True
)
# ソートされた分子の上位10個を新しいSDファイルに書き出す
with Chem.SDWriter(f"top_{best_n:d}_{input_sdf}") as SDF_OUT: for i, mol in enumerate(sorted_molecules): if i == best_n: # 10個書き出したら終了 break SDF_OUT.write(mol)
print("Done") # 処理完了を通知

全体の流れ:AIを使った新しい薬の候補探し

このコードは、既存の薬の骨格をベースに、AI(機械学習)を使って、ターゲットタンパク質に最もよく結合するであろう新しい分子(薬の候補)を効率的に見つけ出すという、創薬研究のプロセスをシミュレーションしています。

プロセスは以下のステップで進行します。

  • 準備と分子設計(Step 1〜3):
    • 必要なツールを準備し、PCの並列処理環境を立ち上げます。
    • 薬のコア骨格ターゲットタンパク質を読み込み、シミュレーション用に加工します。
    • コア骨格に50種のリンカーと50種のRグループを組み合わせ、2,500個の分子候補(化学空間)を作成します。
  • 初期評価(Step 4):
    • 作成した分子候補からランダムに50個を選び出し、ドッキングシミュレーション(結合予測)を実行してスコアを計算します。これはAIが学習するための最初のデータセットとなります。
  • AI学習と最適化(Step 5):
    • 初期評価の結果を元に、AIモデル(ガウス過程)が学習します。
    • AIは学習結果に基づき、「次に計算すれば最も良いスコアが出そう」と予測した最適な50個の分子を選び出し、再度シミュレーションを実行します。
  • 結果の統合と抽出(Step 6):
    • 全ての分子の構造と評価スコアを一つのファイルに統合して保存します。
    • 最終的に、全分子の中からドッキングスコアが最も高い上位10個の分子を抜き出し、最終ファイルとして保存します。

STEP 1: 準備と環境設定

シミュレーションを行うための道具の準備と、計算を効率化するための設定を行います。

  • import prody / from rdkit import Chem / import fegrow: タンパク質操作のProDy、分子構造操作のRDKit、そして創薬シミュレーションの中心となるfegrowという専門的なツールキットをプログラムに組み込んでいます。
  • from fegrow import ChemSpace, Linkers, RGroups:fegrowから、分子リストの管理者(ChemSpace)、部品カタログのデータ(Linkers, RGroups)といった、主要な機能を呼び出せるようにしています。
  • rgroups = RGroups() / linkers = Linkers(): Rグループとリンカーの**利用可能なリスト(部品カタログ)**を、プログラム内で実際に使える形に初期化しています。
  • lc = LocalCluster(...):Daskというライブラリを使い、あなたのPCの複数のCPUコアを計算に使えるようにするための**並列処理チーム(LocalCluster)**を立ち上げています。これにより、計算が速くなります。
  • cs = ChemSpace(dask_cluster=lc): これから作る全ての分子の構造やスコアを管理するメインのワークシート(化学空間)を作成し、並列処理チーム(lc)と連携させています。
  • cs.set_dask_caching(): 計算結果をメモリに一時保存し、同じ計算を省略することで処理を高速化する設定を有効にしています。

STEP 2: 足場分子とターゲットタンパク質の準備

新しい薬のコアとなる骨格と、結合させるターゲット(受容体)をシミュレーションに適した形に加工し、登録します。

  • init_mol = Chem.SDMolSupplier("...")[0]: 薬のコア骨格(足場)の構造ファイル(.sdf)を読み込みます。

  • scaffold = fegrow.RMol(init_mol): 読み込んだ分子データを、fegrow専用の構造形式(RMol)に変換しています。

  • scaffold.rep2D(idx=True, size=(500, 500)): 足場分子の2D構造図を、原子番号付きで表示します。

  • attachmentid = 6: 新しい部品をつなげる場所として、原子番号6の原子を指定しています。

  • scaffold.GetAtomWithIdx(attachmentid).SetAtomicNum(0): 指定した結合点(原子番号6)を、ダミー原子'*')という**「ここに部品をつなぐ目印」**に置き換えています。

  • cs.add_scaffold(scaffold): 加工済みの足場分子を化学空間(cs)に登録します。

  • sys = prody.parsePDB("..."): 薬が結合するターゲットタンパク質の構造データ(.pdbファイル)を読み込みます。

  • rec = sys.select("not (nucleic or hetatm or water)"): タンパク質構造から、核酸、水、不純物といったシミュレーションに不要なものを取り除いています。

  • fegrow.fix_receptor("rec.pdb", "rec_final.pdb"): 一時ファイル(rec.pdb)に対し、欠損修正やプロトン化を行い、最終的な受容体ファイルrec_final.pdb)を作成しています。

  • cs.add_protein("rec_final.pdb"): 最終調整を終えたターゲットタンパク質を化学空間(cs)に登録し、シミュレーションの準備を完了します。

  • attachmentid = 6: 新しい部品をつなげる場所として、原子番号6の原子を指定しています。

  • scaffold.GetAtomWithIdx(attachmentid).SetAtomicNum(0): 指定した原子(原子番号6)を、「ここに部品をつなぐ」という**目印(ダミー原子)**に置き換えています。H:6に様々な官能基を伸ばしていくという設定を行っています。

  • cs.add_scaffold(scaffold): 処理を終えた足場分子を、化学空間(ワークシートcs)に登録します。

  • sys = prody.parsePDB("..."): ターゲットタンパク質(受容体)の構造データ(.pdbファイル)を読み込みます。

  • rec = sys.select("not (nucleic or hetatm or water)"): タンパク質の構造から、核酸、水分子、不純物(hetatm)などのシミュレーションに不要なものを取り除き、純粋なタンパク質を選び出しています。

  • fegrow.fix_receptor("rec.pdb", "rec_final.pdb"): 選出したタンパク質構造に対し、欠損部分の補完やプロトン化状態の調整などを行い、シミュレーションに適した最終ファイル(rec_final.pdb)を作成しています。

  • cs.add_protein("rec_final.pdb"): 最終的に準備されたターゲットタンパク質を、化学空間(cs)に登録します。


STEP 3: 化学空間の構築(分子候補の網羅的な作成)

足場に全ての部品の組み合わせを適用し、総勢2,500個の分子候補を作成します。

  • numlinkers = 50 / numrgroups = 50: 使用するリンカーとRグループの数をそれぞれ50個に設定しています。

  • for i in range(...) / for j in range(...):二重ループを使い、50個のリンカーと50個のRグループの**全ての組み合わせ(50×50=2,500通り)**を順に処理する指示です。

  • cs.add_rgroups(linkers.Mol[i], rgroups.Mol[j]): ループで選ばれた特定のリンカーとRグループを足場につなげた新しい分子候補を、化学空間(cs)に登録しています。

  • cs[0].rep2D(): 作成された分子候補リストの最初の分子の2D構造を表示し、正しく分子が構築されているかを確認します。


STEP 4: 能動学習(Active Learning)の初期評価

AIに学習させるための初期データを収集するため、ランダムに分子を選んでシミュレーションを実行します。

  • random1 = cs.active_learning(50, first_random=True): 能動学習の初期段階として、ランダムに50個の分子を選び出します。
  • random1_results = cs.evaluate(random1, ...): 選ばれた50個の分子について、ドッキングシミュレーション(結合予測)を実行し、スコアを計算しています。gnina_gpu=FalseCPUでの計算を意味します。

以下のような出力になります。長い出力です。公式のマークダウンを合わせて参考にしてください。

  • random1_results: 計算が完了した初期評価の結果(スコアなどが含まれる表形式のデータ)を表示しています。

  • computed = cs.df[~cs.df.score.isna()]:スコアが計算できた(NaNではない)分子だけを抽出し、計算が成功した数を数えています。

STEP 5: AIモデルの学習と最適分子の選択

初期データでAIが学習し、次に試すべき最適な分子を選び出して最終評価を行います。

  • fegrow.RMol.set_gnina(gnina_path): ドッキングシミュレーションに使うGNINAというプログラムがどこにあるか(パス)をfegrowに明示的に設定しています。
  • cs.model = Model.gaussian_process(): 能動学習のためのAIの学習モデルとして、ガウス過程という予測手法を設定しています。
  • cs.query = Query.UCB(beta=1)
    • Queryは、次にどの分子を評価するかを決める戦略(クエリ戦略)を設定しています。
    • UCB(Upper Confidence Bound:上限信頼限界)は、「探索(Exploration)」と「利用(Exploitation)」という2つの行動をバランス良く行うための戦略です。
      • 利用: AIが「この分子はスコアが高そう(良い結果が得られそう)」と予測する分子を選ぶことです。
      • 探索: AIが「この分子のことはよくわからない(不確実性が高い)」と判断する分子を、予測スコアに関わらず選ぶことです。
    • UCB戦略は、「予測スコア+不確実性の幅」が大きい分子を選びます。これにより、単に予測スコアが高い分子だけでなく、まだ情報が少なく「もしかしたらすごく良い分子かもしれない」未知の領域にも積極的に挑戦できます。
  • cs.query = Query.Greedy(): AIが次に試す分子を選ぶ際の戦略として、Greedy(貪欲法)(最も期待値の高いものを選択する戦略)を設定しています。
  • picks = cs.active_learning(50): AIが予測した結果に基づき、「最も高いスコアが出そう」な最適な50個の分子を選び出します。
  • picks_results = cs.evaluate(picks, ...): AIが選んだ50個の分子に対し、再度ドッキングシミュレーションを実行してスコアを計算します。
  • picks_results.to_csv("notebook_greedy_results.csv"): 2回目の評価結果を、CSVファイルとして保存しています。

STEP 6: 結果の統合と上位分子の抽出・保存

全ての分子のデータを整理し、最も優秀な分子を抽出して最終ファイルとして保存します。

  • with Chem.SDWriter("notebook_chemspace.sdf") as SD:: 全ての分子の構造と評価結果を記録するためのSDファイルの書き出しを開始します。
  • for i, row in cs.df.iterrows():: ワークシート(cs.df)にある全分子を一つずつ処理するためのループです。
  • mol.SetProp(column, str(value)): 分子の構造データに対し、計算で得られたスコア成功/失敗フラグなどの情報を**プロパティ(付箋)**として書き込んでいます。
  • SD.write(mol): 情報が付加された分子構造をSDファイルに書き込み、全分子のデータ統合を完了させています。
  • best_n = 10: 最終的に抽出する上位分子の数を10個に設定しています。
  • if mol.GetPropsAsDict()["Success"] == "True":: 構築に成功した分子だけを選び出すための条件です。
  • sorted_molecules = sorted(molecules, key=lambda m: ..., reverse=True): 成功した分子のリストを、ドッキングスコア(score)が高い順に並び替えています。
  • with Chem.SDWriter(f"top_{best_n:d}_...") as SDF_OUT:: 並び替えたリストの上位10個の分子だけを、新しいSDファイルとして書き出し、最終的な成果物として保存しています。
  • print("Done"): すべての処理が完了したことを知らせるメッセージです。

結果の可視化


もともとのタンパク質と出力されたtop_10_notebook_chemspace.sdf をpymolにドラック&ドロップして表示されると上位10個の結合力の高い化合物が表示されます。右下の再生ボタンを押せば各分子の結合の様式がわかります。

最後に


FEgrowとアクティブラーニング(AL)を活用したシミュレーション、いかがでしたでしょうか。

数千にも及ぶ大規模な仮想ライブラリの中から、わずか数回のサイクルで最も結合親和性が高いと予測される化合物を効率的に見つけ出すことができました。

全ての仮想ライブラリを網羅的に計算することは、膨大な計算リソースと時間が必要となり現実的ではありません。しかし、ALは初期の限られたデータからAIが学習し、次に試すべき最適な分子を予測することで、リソースを大幅に節約しながら、有望な化合物に素早くたどり着くための強力な探索手法となります。

ぜひ皆さんもFEgrowとアクティブラーニングを組み合わせ、効率的なインシリコ創薬に取り組んでみてください!

参考文献


GitHub – cole-group/FEgrow: An Open-Source Molecular Builder and Free Energy Preparation Workflow

License: MIT, Apache-2.0


The post FEgrowを用いたアクティブラーニングによる化合物スクリーニングの高速化【In silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/insilico-screening-with-fegrow/feed/07048
Colabで分子モデリングからMLPで計算【金属触媒編】https://labo-code.com/materials-informatics/metal-catalyst-cif/https://labo-code.com/materials-informatics/metal-catalyst-cif/#respondSat, 29 Nov 2025 11:02:47 +0000https://labo-code.com/?p=7039

本記事は、NiO(100) 表面上の Pt ナノクラスターに CO/CO₂ を吸着させた触媒モデルを例に、CIF を主軸に機械学習ポテンシャル用の構造を整える最小ワークフローをまとめた実践ガイドです。Google Col ...

The post Colabで分子モデリングからMLPで計算【金属触媒編】 first appeared on LabCode.

]]>

本記事は、NiO(100) 表面上の Pt ナノクラスターに CO/CO₂ を吸着させた触媒モデルを例に、CIF を主軸に機械学習ポテンシャル用の構造を整える最小ワークフローをまとめた実践ガイドです。Google Colab 上で ASE / pymatgen を使ってスラブとクラスターを組み立て、直交化・スーパーセル展開・吸着分子の配置・幾何チェック・可視化を経て「そのまま UMA(Universal Machine-learning interatomic potential)で単点計算に回せる CIF」を出力するまでを解説し、最後に他の表面・クラスター・分子へ応用するための差し替えポイントも整理します。

動作検証済み環境

Google Colab (2025-05-26), Python 3.10, Torch 2.3.0+cu118, TorchANI 2.2.4, ASE 3.22.1, Matplotlib 3.7.1

0. NiO/Pt ナノクラスター × CO₂還元の準備(セットアップ編)


0-1. なぜ「NiO 上の Pt ナノクラスター × CO₂還元」なのか

CO₂を電気や水素で 燃料・化成品に変える CO₂還元(CO₂RR, CO₂ hydrogenation)は、

「温室効果ガスを減らしつつ、有用な分子を作る」技術として世界中で研究されています。

その中で、多くの理論・実験研究が

  • 表面に吸着した CO(*CO)が、CO₂RR の カギ中間体 になっている
  • 触媒の性能は、しばしば 「CO の吸着エネルギー」 で整理できる

ことを示しています。

一方、NiO や Ni 系酸化物の上に担持した Pt ナノ粒子は、CO₂の水素化・還元反応で高い活性を示し、

「Pt ナノ粒子 × 酸化物界面」自体が重要な反応サイト になっていることが、

in-situ 分光や理論計算から報告されています。

この記事では、この流れを「CIF 主軸+機械学習ポテンシャル」という観点から整理しなおします。

具体的には、

  • NiO(100) 表面の上に Pt₁₃ icosahedron ナノクラスター を担持したモデル(NiO/Pt₁₃)を作り、

  • その上に CO を吸着させて、

    「CO₂還元の中での CO 中間体の吸着エネルギー」 を UMA でスキャンする

という位置づけにします。

コード上は CO 分子を扱いますが、

CO₂ → *CO →(C₁/C₂ 生成物)

という CO₂還元の王道メカニズムのなかで、

*「NiO(100)/Pt₁₃ 上で CO がどれくらい安定か」を見る

と考えていただければ OK です。

0-2. このノートで目指すゴール

前回の MOF 編(CIF から UMA 単点まで) と同じく、今回も

「自分で構築した構造を、そのまま UMA で一点エネルギー計算に回せる CIF として仕上げる」

ことをゴールにします。Colabで分子モデリングからMLPで計算【MOF編】

NiO/Pt 編でやることをざっくり書くと:

  • NiO rocksalt から NiO(100) 表面スラブ を作る
  • 斜格子のスラブを、直交セル+スーパーセル に整える
  • その上に Pt₁₃ icosahedron ナノクラスター を“それっぽい距離”で載せる
  • 後の章で CO を何パターンか置き、UMA で *CO 吸着エネルギーをスキャンする

0章では、その前提となる 環境構築と共通ユーティリティ だけ先に整えてしまいます。

(実際に NiO や Pt を作るのは 1章以降で行います。)

0-3. 動作環境とライブラリのインストール

今回も Google Colab を想定しています。

使う主なライブラリは:

  • ASE:結晶・表面・クラスター作成、CIF の入出力、簡単な可視化
  • pymatgen:ASE との相互変換、後で AdsorbateSiteFinder を使う下準備
  • fairchem-core:機械学習ポテンシャル UMA を呼び出すためのライブラリ
  • huggingface-cli:UMA モデル取得のためのログイン

まず、次のセルを上から順に実行します。

!pip -q install ase pymatgen fairchem-core
!huggingface-cli login
  • Hugging Face のトークンを聞かれるので、アカウントを持っていない場合は先に作成しておきます。
  • 一度ログインしておけば、そのセッションでは UMA をそのまま使えます。

0-4. 共通 import とユーティリティ関数

以降の章で毎回同じコードを書くのは大変なので、

最初に「共通の道具箱」をまとめて定義しておきます。

# 共通import & ユーティリティ
import os, json, csv, glob, hashlib, numpy as np
from pathlib import Path
import matplotlib.pyplot as plt
from ase.io import read, write
from ase.visualize.plot import plot_atoms
from ase.build import bulk, surface, molecule
from ase.cluster.icosahedron import Icosahedron
from ase.geometry import get_distances
from pymatgen.io.ase import AseAtomsAdaptor
from pymatgen.core import Structure
SNAP = Path("snapshots"); SNAP.mkdir(exist_ok=True)
COOR = Path("coords"); COOR.mkdir(exist_ok=True)
def snapshot(atoms, name, rotation='25x,35y,0z', radii=0.9, uc=2, dpi=240, figsize=(5,5)): fig, ax = plt.subplots(figsize=figsize, dpi=dpi) plot_atoms(atoms, ax, rotation=rotation, radii=radii, show_unit_cell=uc) ax.set_axis_off(); plt.tight_layout() out = SNAP / f"{name}.png" plt.savefig(out, bbox_inches="tight", pad_inches=0.02); plt.close(fig) print(f"[PNG] {out}")
def export_coords(atoms, name, fractional=False): cell = atoms.cell.array; pos = atoms.get_positions() if fractional: inv = np.linalg.inv(cell.T); xyz = pos @ inv; header = ["index","symbol","fx","fy","fz"] rows = [(i, atoms[i].symbol, *xyz[i].tolist()) for i in range(len(atoms))] csvp, jsonp = COOR/f"{name}_frac.csv", COOR/f"{name}_frac.json" else: header = ["index","symbol","x","y","z(Å)"] rows = [(i, atoms[i].symbol, *pos[i].tolist()) for i in range(len(atoms))] csvp, jsonp = COOR/f"{name}_cart.csv", COOR/f"{name}_cart.json" with open(csvp,"w",newline="") as f: w=csv.writer(f); w.writerow(header); w.writerows(rows) with open(jsonp,"w") as f: json.dump({"cell":cell.tolist(),"pbc":atoms.get_pbc().tolist(),"header":header,"coords":rows}, f, indent=2) print(f"[CSV/JSON] {csvp.name} / {jsonp.name}")
def dmin_ang(atoms): D = atoms.get_all_distances(mic=True); np.fill_diagonal(D, 1e9) dmin = float(D.min()); flag = "OK" if dmin>=0.60 else "⚠︎ close (<0.60Å)" print(f"[d_min] {dmin:.3f} Å → {flag}") return dmin
def bond_dist(a, i, j): # ase.geometry.get_distances の代わりに Atoms オブジェクトの get_distance メソッドを使用 return a.get_distance(i, j, mic=True)

それぞれ何をしているか

  • snapshot(atoms, name, ...)
    • ASE の plot_atoms で構造を描画し、snapshots/ 以下に PNG を保存します。
    • 「NiO 表面の斜視図」「NiO/Pt₁₃ の真上からの図」など、記事用の図やチェック用の画像を簡単に残せます。
  • export_coords(atoms, name, fractional=False)
    • 原子の座標を CSV と JSONcoords/ に出力します。
    • fractional=True にすると、分率座標(fx, fy, fz)で保存されるので、「CIF と同じ座標系での確認」に便利です。
  • dmin_ang(atoms)
    • セル内の 全ての距離行列 を計算し、その最小値 d_min を出力します。
    • 0.60 Å 未満なら「原子がほぼ重なっている」と判定し、ざっくりした衝突チェックとして使います。
  • bond_dist(a, i, j)
    • ASE の Atoms.get_distance(i, j, mic=True) を薄ラッパーしたものです。
    • 周期境界を考慮した最短距離を取ってくれるので、後で Pt–C, C–O の結合距離などを確認するのに使います。

1. NiO(100) 表面スラブをつくる


ここでは、CO₂還元の舞台となる NiO(100) 表面スラブ を用意します。

ゴールは次の 2 つです。

  • rocksalt 構造の NiO から NiO(100) スラブ を作る(NiO100.cif
  • Pt クラスターを載せやすいように、直交セル+スーパーセル に引き伸ばしたスラブ(NiO100_rect.cif)を作る

この 2 つが、後の Pt クラスター・CO 吸着・UMA 単点計算の「土台」になります。

1-1. rocksalt NiO から NiO(100) スラブを切り出す

まずは ASE の bulksurface を使って、NiO(100) のスラブを作ります。

格子定数は代表値として a ≈ 4.17 Å を使い、上下に十分な真空層をとっておきます。

やることは:

  • rocksalt NiO バルクを作る
  • (100) 面に沿って 6 層スラブを切り出し、真空 15 Å を入れる
  • CIF 出力+簡易チェック(PNG・座標・最近接距離)

対応するセルはそのまま次のとおりです。

# NiO rocksalt(代表値): a≈4.17 Å
a_nio = 4.17
nio_bulk = bulk('NiO', crystalstructure='rocksalt', a=a_nio)
nio100 = surface(nio_bulk, (1,0,0), layers=6, vacuum=15.0)
nio100.center(axis=2)
write("NiO100.cif", nio100)
print("wrote NiO100.cif Natoms=", len(nio100))
snapshot(nio100, "01_NiO100_overview")
snapshot(nio100, "01_NiO100_side", rotation="90x,0y,0z")
export_coords(nio100, "01_NiO100_cart", fractional=False)
export_coords(nio100, "01_NiO100_frac", fractional=True)
dmin_ang(nio100)

何をやっているか

  • bulk('NiO', crystalstructure='rocksalt', a=a_nio)

    → NaCl 型(rocksalt)の NiO バルクを作ります。

  • surface(..., (1,0,0), layers=6, vacuum=15.0)

    → (100) 方向に 6 層ぶん切り出し、上下に 15 Å の真空を入れたスラブを作ります。

  • nio100.center(axis=2)

    → スラブを z 方向の中央に寄せ、上下の真空が対称になるようにしておきます。

  • write("NiO100.cif", ...)

    → この時点の NiO(100) スラブを CIF で保存します(VESTA などで確認可能)。

  • snapshot(...)

    → 斜視図・側面図を PNG に保存しておきます。

  • export_coords(...)

    → 直交座標・分率座標を CSV / JSON で coords/ に書き出します。

  • dmin_ang(nio100)

    → 最近接距離 d_min を計算し、0.60 Å 未満なら「原子がほぼ重なっている」と警告してくれます。

この段階で、NiO100.cifNiO(100) スラブの「素の状態」 として手元にあります。

1-2. 斜格子スラブを直交セル+スーパーセルに変換する

NiO100.cif の a–b 平面は、六方格子のように 60° の斜格子 になっています。

ここに Pt ナノクラスターや CO を載せていくことを考えると、

  • x, y 方向の長さがそのまま距離感に対応していた方が直感的
  • スーパーセル化を 整数行列 で管理しやすい

という理由から、 直交セルに変換したうえで、面内を 3×3 に広げておく 方が扱いやすくなります。

やること:

  • NiO100.cif を読む
  • 変換行列 T で「斜格子 → 直交セル」に変換
  • さらに対角行列 S で面内を 3×3 に拡大
  • PBC をそろえて NiO100_rect.cif として保存

対応するセルは次のとおりです。

from ase.io import read, write
from ase.build import make_supercell
import numpy as np
# 1) まず現在の斜格子スラブを読む
slab = read("NiO100.cif") # 斜格子っぽい a,b, z=真空 のもの
# 2) 斜格子(60°、|a|=|b|=L)→ 直交セルへ整数変換
# 変換行列 T の列が新基底ベクトルの整数係数:
# u = 2a, v = -a + 2b, w = c (u ⟂ v になり直交化できます)
T = np.array([[ 2, -1, 0], [ 0, 2, 0], [ 0, 0, 1]], dtype=int)
slab_ortho = make_supercell(slab, T)
# 3) さらに面内を拡大(Pt13がはみ出さないよう 3×3 くらいが目安)
# 直交化後の u, v が ~5–6 Å なので、3×3 で 15–18 Å 程度になります
S = np.diag([3, 3, 1]) # u×3, v×3, c×1
slab_big = make_supercell(slab_ortho, S)
# 4) PBC をすべて True(z は真空を十分に確保している前提)
slab_big.set_pbc((True, True, True))
write("NiO100_rect.cif", slab_big)
print("wrote: NiO100_rect.cif")
print("cell (Å):\n", slab_big.cell.array)

変換行列 T と S のイメージ

  • もともとの a, b ベクトルは 60° の角度を持った斜格子です。

  • これを整数係数の組み合わせで

    • u = 2a
    • v = -a + 2b
    • w = c

    のように取り直すと、u と v がほぼ直交します。

    この「新基底ベクトルの係数」を列に持つ行列が T です。

  • そのあと、対角行列 S = diag(3,3,1) でもう一度 make_supercell すると、

    u, v 方向に 3 倍ずつ広がった 3×3 スーパーセルになります。

こうして、直交セル+十分な面内サイズを持つ NiO(100) スラブNiO100_rect.cif)が得られます。

1-3. 直交化した NiO(100) スラブをざっくり可視化する

直交セル化とスーパーセル化が正しくできているか、

一度 PNG で「真上」と「斜視」の2枚を出しておくと安心です。

from ase.visualize.plot import plot_atoms
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(5,5), dpi=220)
plot_atoms(slab_big, ax, rotation='90x,0y,0z', radii=0.9, show_unit_cell=2) # 真上から
ax.set_axis_off(); plt.tight_layout(); plt.show()
fig, ax = plt.subplots(figsize=(5,5), dpi=220)
plot_atoms(slab_big, ax, rotation='25x,35y,0z', radii=0.9, show_unit_cell=2) # 斜視
ax.set_axis_off(); plt.tight_layout(); plt.show()
  • 1 枚目(真上):

    表面の周期性・面内サイズがどのくらい確保できているかをチェックできます。

  • 2 枚目(斜視):

    スラブの厚みと真空層のバランスを視覚的に確認できます。

このあたりで

  • 面内が 15〜18 Å 程度に広がっていそうか
  • z 方向に十分な真空が入っていそうか

を確認しておくと、次章以降の Pt クラスター・CO 吸着の準備がスムーズになります。

image.png

image.png

2. NiO(100) の上に Pt₁₃ ナノクラスターを載せる

1章で NiO(100) スラブ(NiO100.cif

直交+拡大型の NiO100_rect.cif まで準備できました。

ここでは、いよいよ Pt₁₃ icosahedron ナノクラスター を NiO の上に載せて、

  • お試し版(小さいスラブ上の Pt₁₃:NiO100_Pt13.cif
  • 本番用(直交・拡大量スラブ上の Pt₁₃:NiO100_rect_Pt13.cif

の 2 種類の支持体 CIF を作ります。

後の章で CO を置いたり UMA に投げたりするときに使うのは「本番用」ですが、

最初に小さいスラブ上で動かしてみると、動作チェックや高さパラメータの感覚が掴みやすくなります。

2-1. 小さな NiO(100) スラブ上に Pt₁₃ を載せてみる(お試し版)

まずは 1章で作った NiO100.cif の上に、Pt₁₃ を載せてみます。

ここでは:

  • Icosahedron('Pt', noshells=2) で Pt₁₃ クラスターを作成
  • 重心を原点に移動
  • NiO(100) スラブの x–y 中央+表面 z から h Å 上 に載せる
  • CIF と PNG、座標、最近接距離をざっと確認

という一連の流れを、小さいセルで試します。

# Pt13 (icosahedron) を界面上 h Å 漂わせて載せる
pt13 = Icosahedron('Pt', noshells=2) # 13 atoms
pt13.translate(-pt13.get_center_of_mass())
# x-y中央へ、zは表面最上位からhだけ上に
h = 2.4 # ← 近すぎたら 2.6/2.8 と上げる
xy_center = 0.5 * (nio100.cell[0] + nio100.cell[1])
z_top = nio100.positions[:,2].max()
pt13.translate(xy_center + np.array([0,0,z_top + h]) - pt13.get_center_of_mass())
support = nio100 + pt13
write("NiO100_Pt13.cif", support)
print("wrote NiO100_Pt13.cif Natoms=", len(support))
snapshot(support, "02_support_persp", rotation="25x,35y,0z")
snapshot(support, "02_support_top", rotation="90x,0y,0z")
export_coords(support, "02_support_cart", fractional=False)
dmin_ang(support)

ここで見ておきたいポイントは 3 つです。

  • h の感覚

    h = 2.4 から始めて、Ni–Pt, O–Pt が近すぎるようなら 2.6 / 2.8… と上げていくイメージです。

  • 載り方の見た目

    02_support_persp.png, 02_support_top.png の 2 枚の PNG で、

    「ちゃんと NiO の上に Pt の塊が載っているか」をざっくり確認します。

  • 最近接距離 dmin

    dmin_ang(support) の結果で、0.60 Å 未満になっていないかだけチェックしておくと安心です。

この NiO100_Pt13.cif は、「動作確認用の小さなモデル」として取っておきます。

本番の UMA スキャンは、次の直交・拡大量スラブ版で行います。

2-2. 直交・拡大量スラブ NiO100_rect の上に Pt₁₃ を載せる(本番用)

次に、1章で作った 直交+3×3 スーパーセル版の NiO(100) スラブNiO100_rect.cif)に

同様の手順で Pt₁₃ を載せ、本番用の支持体 NiO100_rect_Pt13.cif を作ります。

やることはお試し版とほぼ同じですが:

  • 読み込むスラブが NiO100_rect.cif になる
  • h を 2.6 Å に設定(少しだけ余裕を持たせた設定)

という違いがあります。

import numpy as np
from ase.cluster.icosahedron import Icosahedron
from ase.io import write
# 1) 最新の直交・拡大型スラブを読み込み
base = read("NiO100_rect.cif")
# 2) Pt13 生成&重心原点
pt13 = Icosahedron('Pt', noshells=2) # 13 atoms
pt13.translate(-pt13.get_center_of_mass())
# 3) 面内中央(x,y)+ 上面 z_top の h Å 上に置く
xy_center = 0.5 * (base.cell[0] + base.cell[1])
z_top = base.positions[:,2].max()
h = 2.6 # ← 近すぎたら 2.8–3.0 に上げる / 遠いなら 2.2–2.4 に下げる
pt13.translate(xy_center + np.array([0,0,z_top + h]) - pt13.get_center_of_mass())
support = base + pt13
write("NiO100_rect_Pt13.cif", support)
print("wrote: NiO100_rect_Pt13.cif")

ここまでで、

  • NiO100_rect_Pt13.cif

    → NiO(100) 直交+拡大量スラブの上に Pt₁₃ が載った「本番用支持体 CIF」

が完成します。

メモ:

直交+面内が広いスラブを使うことで、

Pt₁₃ や CO が周期画像と強く干渉するリスクを下げています。

(完全にゼロにはなりませんが、「とりあえず吸着スキャンする」には十分なサイズ感です。)

2-3. 本番用支持体 NiO100_rect_Pt13 の可視化と幾何チェック

最後に、本番用の支持体 CIF が「ちゃんと NiO の上に載っているか」「衝突していないか」を

画像と数値でざっくり確認しておきます。

# 可視化&幾何チェック(置いた後)
import numpy as np, csv
import matplotlib.pyplot as plt
from pathlib import Path
from ase.io import read
from ase.visualize.plot import plot_atoms
snap_dir = Path("snapshots"); snap_dir.mkdir(exist_ok=True)
a = read("NiO100_rect_Pt13.cif") # ← B手順で出力したファイル
# ---- 1) 画像(真上 / 斜視) ----
fig, ax = plt.subplots(figsize=(5,5), dpi=240)
plot_atoms(a, ax, rotation='90x,0y,0z', radii=0.9, show_unit_cell=2) # top view
ax.set_axis_off(); plt.tight_layout(); plt.show()
top_png = snap_dir/"B_after_place_top.png"
plt.savefig(top_png, bbox_inches="tight", pad_inches=0.02); plt.close(fig)
fig, ax = plt.subplots(figsize=(5,5), dpi=240)
plot_atoms(a, ax, rotation='25x,35y,0z', radii=0.9, show_unit_cell=2) # perspective
ax.set_axis_off(); plt.tight_layout(); plt.show()
persp_png = snap_dir/"B_after_place_persp.png"
plt.savefig(persp_png, bbox_inches="tight", pad_inches=0.02); plt.close(fig)
print(f"[PNG] {top_png}")
print(f"[PNG] {persp_png}")

2 枚の PNG を見て、

  • Pt クラスターが NiO の上にきちんと載っているか
  • 極端に埋まっていたり、真空中に浮きすぎていないか

をざっくり確認します。

続いて、「数値的にちゃんと NiO の上にいるか」と「衝突していないか」を簡易チェックします。

# ---- 2) 上面に載っているかの数値確認 ----
z_top_surface = float(np.max([p[2] for p,sym in zip(a.positions, a.get_chemical_symbols()) if sym in ("Ni","O")]))
pt_indices = [i for i,sym in enumerate(a.get_chemical_symbols()) if sym=="Pt"]
z_pt_min = float(np.min(a.positions[pt_indices,2]))
print(f"z_top(surface) = {z_top_surface:.3f} Å")
print(f"z_min(Pt13) = {z_pt_min:.3f} Å")
print(f"Δz = z_min(Pt) - z_top(surface) = {z_pt_min - z_top_surface:.3f} Å (>=0 なら“上面”に正しく載っています)")
# ---- 3) 代表の最近接距離(衝突チェック) ----
D = a.get_all_distances(mic=True)
np.fill_diagonal(D, 1e9)
dmin = float(D.min())
flag = "OK" if dmin >= 0.60 else "⚠︎ close (<0.60 Å)"
print(f"[d_min] {dmin:.3f} Å → {flag}")
  • Δz = z_min(Pt) - z_top(surface)

    → NiO 表面の一番上の原子と、一番下の Pt の高さ差

    → これが 0 以上なら、「Pt クラスター全体が NiO より上にある」ことが保証されます。

  • dmin

    → セル内で一番短い原子間距離(周期境界を考慮)

    → 0.60 Å 未満なら「どこかでほぼ重なっている」ので、h の見直しなどを検討

最後に、「上面付近にはどんな原子がいるのか」を z 座標でソートしてリスト化しておきます。

# ---- 4) 上面近傍の原子を z 高い順で確認(視覚と数値の対応づけ) ----
idx_sorted = np.argsort(a.positions[:,2])[::-1]
rows = []
for i in idx_sorted[:25]: sym = a[i].symbol x,y,z = a.positions[i] rows.append((i, sym, x, y, z)) print(f"idx={i:3d} {sym:>2s} x={x:8.3f} y={y:8.3f} z={z:8.3f}")
# CSV保存(任意)
import csv, os
with open("coords/B_after_place_top25.csv","w",newline="") as f: w=csv.writer(f); w.writerow(["index","symbol","x","y","z(Å)"]); w.writerows(rows)
print("[CSV] coords/B_after_place_top25.csv")

この B_after_place_top25.csv を見ておくと、

  • 「一番上の Pt がどの index か」
  • 「その周りの Ni/O はどれか」

を後から落ち着いて追えるようになります。

次の章で CO を置くときに、「どの Pt を『頂上サイト』として扱うか」を決める材料にもなります。

image.png

image.png

3. CO 吸着候補を幾何条件でふるいにかける

1–2章で NiO(100) 直交スラブ+Pt₁₃ クラスター まで準備できました。

ここからはいよいよ CO を載せていきますが、いきなり UMA で全パターンを計算するのは少しもったいないので、

いったん「幾何条件だけ」で

衝突している構造・明らかにおかしい構造を落としておく

という前処理を挟みます。

この章では、

  • 事前に作っておいた CO 吸着候補 CIF 群(cands を読み込む

  • 各構造について

    • セル内の最近接距離 d_min

    • 一番上の Pt と C の距離(Pt–C)

    • C–O 結合長(C–O)

      を計算する

  • しきい値(d_min / Pt–C)でフィルタして、「幾何的にマトモな候補」だけのリスト を作る

  • 上位 12 構造のサムネイル PNG を出して、ざっと目視確認する

ところまでを行います。

💡 前提:

ここで使う cands は、「NiO100_rect_Pt13 の上に CO をいろいろな向き・位置で置いて CIF に書き出したもの」のパスリストを想定しています。

それを別セルで cands = sorted(glob.glob("NiO_Pt13_CO_*.cif")) のように用意しておきます。

3-1. 幾何情報(d_min, Pt–C, C–O)を一括で抜き出す

まずは、候補構造ごとに

  • 全原子間距離の最小値 d_min(衝突チェック用)
  • 一番上の Pt と CO の C の距離(Pt–C)
  • CO 分子の C–O 距離(C–O)

の 3 つを計算し、行リストにまとめます。

from ase.io import read
from pathlib import Path
from ase.geometry import get_distances # get_distancesは個別のatomsに対して使うためインポートを修正
def mic_dist(a, i, j): # atomsオブジェクトのget_distanceメソッドをmic=Trueで使う return a.get_distance(i, j, mic=True)
def dmin_ang(a): D = a.get_all_distances(mic=True) import numpy as np np.fill_diagonal(D, 1e9) return float(D.min())
rows=[]
for p in sorted(cands): a = read(p) pt = max([i for i,x in enumerate(a) if x.symbol=="Pt"], key=lambda i: a.positions[i,2]) c = [i for i,x in enumerate(a) if x.symbol=="C"][-1] o = [i for i,x in enumerate(a) if x.symbol=="O"][-1] rows.append((Path(p).name, dmin_ang(a), mic_dist(a,pt,c), mic_dist(a,c,o)))

何をしているか

  • mic_dist(a, i, j)

    → ASE Atoms.get_distance(i, j, mic=True) を薄ラッパーしたもの。

    周期境界(minimum image convention)込みで距離を取ります。

  • dmin_ang(a)

    a.get_all_distances(mic=True) で全ペアの距離行列を取り、

    対角成分を巨大値にしてから最小値 d_min を抜き出しています。

    「どこかで原子同士が重なっていないか?」のざっくりチェック用です。

  • pt

    z 座標が最大の Pt(=一番上にいる Pt)を選んでいます。

    CO を「頂上の Pt」に吸着させた候補を想定。

  • c, o

    → C と O は最後に出てくるインデックス(=吸着 CO の原子)を取る前提で、

    C–O 結合長を取っています。

こうして rows には

(file_name, dmin_A, PtC_A, CO_A)

のタプルが候補構造の数だけ溜まっていきます。

3-2. しきい値でフィルタして「幾何的にマトモな候補」だけを残す

次に、この rows を元に

  • 衝突している構造(d_min < 0.60 Å)
  • Pt–C が明らかにおかしい構造(短すぎ / 長すぎ)

を落としておきます。ここでは代表値として、

  • d_min ≥ 0.60 Å
  • 1.60 Å ≤ Pt–C ≤ 2.20 Å

をしきい値にしています。

# フィルタ(衝突と過度な離隔を除外)
keep = [r for r in rows if r[1] >= 0.60 and 1.60 <= r[2] <= 2.20] # dmin>=0.60Å 且つ Pt–C∈[1.6,2.2]Å
keep.sort(key=lambda x: (x[2], x[1])) # Pt–Cが短い順にざっくり

ここでの考え方:

  • d_min ≥ 0.60 Å

    → 「原子がほぼ重なっている構造」を弾くためのごくラフな条件です。

    (本当に厳密にやりたい場合は、元素組ごとにしきい値を変えるなどの工夫もあり得ます。)

  • Pt–C ≈ 1.8 Å 前後が典型的なオンサイト吸着距離なので、

    ざっくり 1.6〜2.2 Å の間にあるものだけ残しています。

keep を Pt–C が短い順(=結合が強そうな順)+ d_min の大きさでソートしておくと、

あとで「良さそうな候補」から順に UMA スキャンをかけるときに便利です。

3-3. CSV にまとめて、上位候補のサムネイルを作る

最後に、

  • すべての候補の幾何情報(CO_candidates_geom.csv
  • フィルタ後の「幾何的にマトモな候補」だけのリスト(CO_candidates_filtered.csv

を CSV に出力し、さらに上位 12 構造のサムネイル PNG を保存します。

# 保存とサムネ(上位12件)
import csv, os
os.makedirs("coords", exist_ok=True); os.makedirs("snapshots", exist_ok=True)
with open("coords/CO_candidates_geom.csv","w",newline="") as f: w=csv.writer(f); w.writerow(["file","dmin_A","PtC_A","CO_A"]); w.writerows(rows)
with open("coords/CO_candidates_filtered.csv","w",newline="") as f: w=csv.writer(f); w.writerow(["file","dmin_A","PtC_A","CO_A"]); w.writerows(keep)
print(f"kept {len(keep)} / {len(rows)} candidates → coords/CO_candidates_filtered.csv")
# サムネ保存
for name,_,_,_ in keep[:12]: a = read(name) fig, ax = plt.subplots(figsize=(4.2,4.0), dpi=220) plot_atoms(a, ax, rotation='30x,25y,0z', radii=0.9, show_unit_cell=2) ax.set_axis_off(); plt.tight_layout() plt.savefig(f"snapshots/{Path(name).stem}.png", bbox_inches="tight", pad_inches=0.02) plt.close(fig)
print("[PNG] snapshots/cand_... (上位12枚)")

できあがるファイル

  • coords/CO_candidates_geom.csv

    → 全候補について (ファイル名, d_min, Pt–C, C–O) をまとめた表。

    しきい値を変えたくなったときは、この CSV から再フィルタできます。

  • coords/CO_candidates_filtered.csv

    → 幾何条件を満たした候補のみのリスト。

    次章以降で UMA 計算に回すのは基本的にこちら。

  • snapshots/○○.png(最大 12 枚)

    → 「見た目がどうなっているか」をサクッと確認するためのサムネイル。

    CO の向き(直立/傾き/ブリッジっぽい配置など)や、Pt₁₃ のどのサイトに 乗っているかを直感的に把握できます。

4. UMA で NiO/Pt₁₃/CO の吸着エネルギーを一括スキャンする


ここまでで、

  • NiO(100) の直交・拡大型スラブ NiO100_rect.cif
  • その上に Pt₁₃ クラスターを載せた支持体 NiO100_rect_Pt13.cif
  • 幾何チェックを通過した CO 吸着候補のリスト keep

がそろいました。

4章では、いよいよ 機械学習ポテンシャル UMA を使って、

  • 各候補構造のエネルギーを計算し
  • 吸着エネルギー Eads を求め
  • 「もっとも安定な CO 吸着構造」を 1 つ選び出す

ところまで進みます。

4-1. UMA ユニットを準備して参照エネルギーを計算する

最初に、ASE から呼び出せる形で UMA を用意し、 次の 2 つの参照エネルギーを計算します。

  • NiO/Pt₁₃ 支持体だけのエネルギー E_support
  • 気相 CO 分子のエネルギー E_CO

記事の頭で !pip installhuggingface-cli login はすでに済んでいる前提です。

# 事前に: !pip -q install fairchem-core ; !huggingface-cli login -y
from fairchem.core import FAIRChemCalculator, pretrained_mlip
from ase.build import molecule
# UMAユニット
unit = pretrained_mlip.get_predict_unit("uma-s-1p1")
calc = FAIRChemCalculator(unit, task_name="oc20") # 触媒系の一般タスク例
# 参照エネルギー(支持体&孤立CO)
support = read("NiO100_rect_Pt13.cif"); support.calc = calc
co_free = molecule("CO"); co_free.set_cell([20,20,20]); co_free.set_pbc([True]*3); co_free.center(); co_free.calc = calc
E_support = support.get_potential_energy(); E_co = co_free.get_potential_energy()
print(f"E_support={E_support:.3f} eV, E_CO={E_co:.3f} eV")

ここでやっていることを整理すると:

  • get_predict_unit("uma-s-1p1")→ UMA の事前学習済みモデルを 1 つ選んで取得しています。
  • FAIRChemCalculator(...)→ このユニットを ASE の Calculator としてラップし、Atoms.calc にセットできる形にしています。
  • support(NiO/Pt₁₃)と co_free(孤立 CO)に calc をセットし、get_potential_energy() を呼ぶだけで、それぞれのエネルギーが計算されます。

この 2 つの値を、あとの吸着エネルギー計算で「引き算の基準」として使います。

吸着エネルギーの定義(この章ではずっとこの約束を使います)

  • Etot … ある候補構造(NiO/Pt₁₃/CO 全体)のエネルギー
  • E_support … NiO/Pt₁₃ 支持体だけのエネルギー
  • E_CO … 気相 CO のエネルギー

とすると、吸着エネルギー Eads

Eads = Etot - E_support - E_CO

と定義しています。 このとき、Eads が 0 より 負の値になるほど、吸着が有利(発熱的) という解釈になります。

4-2. フィルタ済み候補の吸着エネルギーをまとめて評価する

次に、3章で幾何フィルタを通過した候補リスト keep について、 UMA で単点計算を実行し、それぞれの Eads を求めていきます。

import time
results=[]
for name,_,_,_ in keep: a = read(name); a.calc = calc Etot = a.get_potential_energy() eads = Etot - E_support - E_co results.append((name, eads)) print(f"{name:45s} Eads = {eads:7.3f} eV")
results.sort(key=lambda x: x[1])
with open("coords/Eads_scan_UMA.csv","w",newline="") as f: w=csv.writer(f); w.writerow(["file","Eads_eV"]); w.writerows(results)
print("\\nTop-5 (most stable):")
for r in results[:5]: print(r)
best_name, best_e = results[0]
print(f"\\nBEST = {best_name} ({best_e:.3f} eV)")

ここでのポイントは次の通りです。

  • for name,_,_,_ in keep:keep(file, dmin_A, PtC_A, CO_A) というタプルのリストでしたが、 ここではファイル名 name だけを使うので、残りは _ で捨てています。
  • 毎回 a.calc = calc として UMA をセットし、get_potential_energy()Etot を計算。
  • 吸着エネルギーは、先ほどの約束どおりEads = Etot - E_support - E_co で計算しています。
  • results.sort(key=lambda x: x[1])results(ファイル名, Eads) のリストなので、x[1](吸着エネルギー)が小さい順、つまり「安定な順」に並び替えています。
  • Eads_scan_UMA.csv→ すべての候補について (ファイル名, Eads) を保存した CSV です。 後から別のしきい値で選び直したり、他の指標と組み合わせて解析したりするときに便利です。

最後に、

  • best_name … 最も Eads が小さかった構造のファイル名
  • best_e … そのときの Eads の値

を拾って、ログに「BEST = …」と出力しています。


4-3. 最安定構造を CIF と PNG にして取り出す

計算の結果、もっとも吸着エネルギーが安定だった構造を最終的な CIF と図として残す セルがこちらです。

best = read(best_name)
write("FINAL_NiO100_Pt13_CO.cif", best)
print("wrote FINAL_NiO100_Pt13_CO.cif")
# 可視化
fig, ax = plt.subplots(figsize=(5,4.6), dpi=240)
plot_atoms(best, ax, rotation='30x,25y,0z', radii=0.9, show_unit_cell=2)
ax.set_axis_off(); plt.tight_layout(); plt.show()
plt.savefig("snapshots/FINAL_persp.png", bbox_inches="tight", pad_inches=0.02); plt.close(fig)
fig, ax = plt.subplots(figsize=(5,4.6), dpi=240)
plot_atoms(best, ax, rotation='90x,0y,0z', radii=0.9, show_unit_cell=2)
ax.set_axis_off(); plt.tight_layout(); plt.show()
plt.savefig("snapshots/FINAL_top.png", bbox_inches="tight", pad_inches=0.02); plt.close(fig)
print("[PNG] snapshots/FINAL_persp.png / FINAL_top.png")
# 代表距離(Pt–C, C–O)
pt = max([i for i,x in enumerate(best) if x.symbol=="Pt"], key=lambda i: best.positions[i,2])
c = [i for i,x in enumerate(best) if x.symbol=="C"][-1]
o = [i for i,x in enumerate(best) if x.symbol=="O"][-1]
# def mic_dist(a, i, j):
# return float(get_distances(a.positions[i], a.positions[j:j+1],
# cell=a.cell, pbc=a.pbc, mic=True)[1][0][0])
# print(f"Pt–C = {mic_dist(best,pt,c):.3f} Å, C–O = {mic_dist(best,c,o):.3f} Å")
# print(f"Eads(best, UMA) = {best_e:.3f} eV (negative=favorable)")

このセルで出てくる成果物は:

  • FINAL_NiO100_Pt13_CO.cif→ NiO(100) 上の Pt₁₃ クラスターに CO が吸着した「最安定候補」の CIF。 VESTA や Avogadro に渡して、構造を詳細に確認したり、 そのまま別の計算コード(DFT など)の初期構造として使ったりできます。

image.png

  • FINAL_persp.png, FINAL_top.png→ それぞれ「斜めから見た図」「真上から見た図」です。 どの Pt サイトに CO が乗っているか、CO がどの向きか、といった情報を直感的に把握できます。

コメントアウトされている部分を有効にすると、

  • 一番上の Pt と CO の C の距離(Pt–C)
  • CO の結合長(C–O)
  • 最安定構造の吸着エネルギー Eads(best)

も一緒に出力できます。 例えば、

  • Pt–C ≒ 1.8 Å
  • C–O ≒ 1.15 Å
  • Eads ≒ -x.x eV

といったオーダーであれば、「CO 吸着としてそれらしいサイズ感か?」を 文献値とざっくり比較することもできます。

5. 他の系に応用するときの「ユースケース別ガイド」


ここからは、次の 3 パターンに分けて整理します。

  1. 分子だけ変えたい:NiO + Pt₁₃ はそのまま、CO → CO₂ / H₂O など
  2. クラスターだけ変えたい:NiO(100) はそのまま、Pt₁₃ → Au₁₃ / Au₅₅ など
  3. 表面(支持体)から変えたい:NiO(100) → 別の酸化物・金属表面(外部 CIF 含む)

それぞれ「このユースケースなら、ノートのどこを変えればいいか」だけをまとめます。

5-1. ユースケース①:分子だけ変えたい(CO → CO₂ / H₂O など)

NiO(100) + Pt₁₃ はそのまま で、

「CO じゃなくて CO₂ を吸着させてみたい」みたいなケース。

変える場所はざっくりこの 3 つだけ

  1. 孤立分子の生成(参照エネルギー用)
  2. 候補構造の生成スクリプト(cands を作っているセル)
  3. インデックスの取り方(C と O をどう拾うか)

① 孤立分子の生成

今は 4 章でこうなっていました:

from ase.build import molecule
co_free = molecule("CO")
co_free.set_cell([20,20,20])
co_free.set_pbc([True]*3)
co_free.center()
co_free.calc = calc
E_co = co_free.get_potential_energy()

ここを、例えば CO₂ にするなら:

co2_free = molecule("CO2")
co2_free.set_cell([20,20,20])
co2_free.set_pbc([True]*3)
co2_free.center()
co2_free.calc = calc
E_co2 = co2_free.get_potential_energy()

に変えるだけです。

あとは 4 章の吸着エネルギー定義を

Eads = Etot - E_support - E_CO2

のように、変数名を合わせてあげれば OK です。

② 吸着候補 cands の作り方

ここはノートの外(あなたが別セルで書いているはずの部分)ですが、考え方は同じで、

  • CO の代わりに CO₂ を載せる
  • 高さ h と向き(どちらが表か、どれくらい寝かせるか)を変えながら CIF を量産する
  • その CIF のパスリストを cands に入れる

という流れはまったく同じです。

たとえば、

  • C が金属に近づいている「エンドオン」型
  • O–C–O 全体が寝ている「ブリッジ」型

の 2 パターンを for ループで作っておく、みたいなイメージです。

③ 幾何フィルタのインデックスまわり

3 章のこの部分:

pt = max([i for i,x in enumerate(a) if x.symbol=="Pt"], key=lambda i: a.positions[i,2])
c = [i for i,x in enumerate(a) if x.symbol=="C"][-1]
o = [i for i,x in enumerate(a) if x.symbol=="O"][-1]
rows.append((Path(p).name, dmin_ang(a), mic_dist(a,pt,c), mic_dist(a,c,o)))

CO₂ に変えた場合も、

  • 「一番上の Pt」はそのまま
  • C と O の扱いだけ少し考える

だけです。

単純に「最後の C と最後の O」を使うやり方でも動きますが、

  • C だけ使いたいなら c_index だけあれば良い
  • 分子内 C–O をチェックしたい場合は、CO₂ の 2 本分を全部見る or 代表値だけ見る、など

少しロジックを足すイメージです。

5-2. ユースケース②:クラスターだけ変えたい(Pt₁₃ → Au₁₃ / Au₅₅ など)

NiO(100) はそのまま、金属クラスターだけ変えたいケース。

変える場所はこの 3 つ

  1. クラスター生成の行(元素とサイズ)
  2. 載せる高さ h
  3. (必要なら)スーパーセルのサイズ

① クラスター生成

2 章でやっていたここです:

from ase.cluster.icosahedron import Icosahedron
pt13 = Icosahedron('Pt', noshells=2)
pt13.translate(-pt13.get_center_of_mass())

これを例えば Au₁₃ にするなら:

au13 = Icosahedron('Au', noshells=2)
au13.translate(-au13.get_center_of_mass())

Au₅₅ にするなら:

au55 = Icosahedron('Au', noshells=3) # noshells=3 → 55 atoms
au55.translate(-au55.get_center_of_mass())

に変えるだけです。

あとは変数名 pt13au13 に合わせて、

support = base + pt13 のところを support = base + au13 のように変えれば OK。

② 支持体との距離 h

同じセルにあるこの行:

h = 2.6 # ← 近すぎたら 2.8–3.0 に上げる / 遠いなら 2.2–2.4 に下げる

は、元素やクラスターサイズによって微調整ポイントです。

  • まずは 2.5〜3.0 Å あたりから始める
  • 2 章の dmin チェックで「近すぎないか」を確認する
  • PNG を見て、明らかに埋まっていないか/離れすぎていないかを見る

という流れに変わりません。

③ スーパーセルサイズ(必要なら)

クラスターを大きく(Au₅₅ など)したときに、

  • クラスター同士が周期境界で近づきすぎていそう
  • 図を見て「明らかに隣と干渉している」

となったら、1 章のここ:

S = np.diag([3, 3, 1]) # u×3, v×3, c×1

np.diag([4,4,1]) のように変えて、面内を広げてください。

5-3. ユースケース③:表面(支持体)から変えたい

最後は一番大きく変えるパターン、

NiO(100) 自体を別の表面に変えたい ケースです。

これはさらに 2 パターンに分かれます:

  • ③-A:ASE の bulk / surface で作れる単純な結晶
  • ③-B:COD / Materials Project などから CIF をダウンロードして使う

③-A:ASE だけで完結させる場合

1 章のこの部分を中心に変えます:

a_nio = 4.17
nio_bulk = bulk('NiO', crystalstructure='rocksalt', a=a_nio)
nio100 = surface(nio_bulk, (1,0,0), layers=6, vacuum=15.0)

例えば Cu(111) 表面にしたい場合は:

cu_bulk = bulk('Cu', crystalstructure='fcc', a=a_cu) # a_cu は文献値を入れる
cu111 = surface(cu_bulk, (1,1,1), layers=6, vacuum=15.0)

のようになります。

その後の流れ(center(axis=2), CIF 出力、直交化、スーパーセル化)は

NiO のときと全く同じです。

③-B:外部 CIF から始める場合

NiO のときは bulksurface でしたが、外部 CIF を使う場合は:

  1. ダウンロードした CIF をそのまま read("xxx.cif") する
  2. 必要なら SlabGenerator などで表面切り出し
  3. その結果を NiO100_rect.cif 相当のファイル名にしてしまう

という運用にしてしまうのが楽です。

例えば:

slab = read("MySurface_from_COD.cif")
write("NiO100_rect.cif", slab)

としてしまえば、以降のコード(Pt₁₃ を載せる部分)は

そのまま動きます(ファイル名に NiO と書いてあっても中身は別物でも良い、という割り切り)。

きれいにやりたければ、ファイル名を

  • CeO2_111_rect.cif
  • CeO2_111_rect_Au13.cif

のように全部変えていく、という感じです。

5-4. まとめ:ユースケースごとに「変える場所」を決める

もう一度だけ整理すると:

  • 分子だけ変えたい(CO → CO₂ など)
    • 孤立分子の生成(4 章の molecule("CO") の部分)
    • 吸着候補 cands を作っているスクリプト
    • 3 章の C/O インデックス取得と、距離の閾値
  • クラスターだけ変えたい(Pt₁₃ → Au₁₃ / Au₅₅ など)
    • Icosahedron('Pt', noshells=2) の行(元素と殻数)
    • 支持体との距離 h
    • 必要ならスーパーセルサイズ(S = np.diag([...])
  • 表面から変えたい(NiO → 別の表面)
    • 1 章の bulk / surface 部分、または外部 CIF の読み込み
    • 場合によっては直交化の行列 T とスーパーセル S
    • 出力ファイル名(NiO100_rect.cif など)を系に合わせて変更

最後に


いかがでしたか?本記事で紹介した分子構造の作り方を一度試していただき、機械学習ポテンシャルを使って計算を回していただくと、計算化学がより身近に感じられると思います。Cifファイルは論文などによく記載されているので、金属種を変えて計算するだけでも面白いと思いますので是非試してみてください。

参考文献


  1. K. Smith et al. “UMA: Universal Machine-learning Interatomic Potential,” arXiv preprint, arXiv:2505.08762 (2025). <https://arxiv.org/abs/2505.08762>
  2. B. M. Wood et al., “UMA: A Family of Universal Models for Atoms,” arXiv preprint, arXiv:2506.23971 (2025). <https://arxiv.org/abs/2506.23971>
  3. FAIRchem Team, “FAIRChem: FAIR Chemistry Toolkit,” GitHub Repository (accessed 2025-11-24). <https://github.com/facebookresearch/fairchem>
  4. Meta FAIR Chemistry, “facebook/UMA,” Hugging Face Model Card (accessed 2025-11-24). <https://huggingface.co/facebook/UMA>
  5. A. H. Larsen et al., “The atomic simulation environment—a Python library for working with atoms,” J. Phys.: Condens. Matter 29, 273002 (2017). https://doi.org/10.1088/1361-648X/aa680e
  6. S. P. Ong et al., “Python Materials Genomics (pymatgen): A robust, open-source python library for materials analysis,” Comput. Mater. Sci. 68, 314–319 (2013). https://doi.org/10.1016/j.commatsci.2012.10.028
  7. G. Landrum, “RDKit: Open-Source Cheminformatics Software,” RDKit Project (accessed 2025-11-24). <https://www.rdkit.org>
  8. K. Momma and F. Izumi, “VESTA 3 for three-dimensional visualization of crystal, volumetric and morphology data,” J. Appl. Crystallogr. 44, 1272–1276 (2011). https://doi.org/10.1107/S0021889811038970
  9. M. D. Hanwell et al., “Avogadro: an advanced semantic chemical editor, visualization, and analysis platform,” J. Cheminf. 4, 17 (2012). https://doi.org/10.1186/1758-2946-4-17
  10. International Union of Crystallography, “checkCIF/PLATON: Validation of crystallographic information files,” IUCr checkCIF service (accessed 2025-11-24). <https://checkcif.iucr.org>
  11. K. T. Winther et al., “Catalysis-Hub.org, an open electronic structure database for surface reactions,” Sci. Data 6, 75 (2019). https://doi.org/10.1038/s41597-019-0081-y
  12. L. Chanussot et al., “The Open Catalyst 2020 (OC20) dataset and community challenges,” ACS Catal. 11, 6059–6072 (2021). https://doi.org/10.1021/acscatal.0c04525
  13. A. Sápi et al., “In Situ DRIFTS and NAP-XPS Exploration of the Complexity of CO₂ Hydrogenation over Size-Controlled Pt Nanoparticles Supported on Mesoporous NiO,” J. Phys. Chem. C 122(10), 5553–5565 (2018). https://doi.org/10.1021/acs.jpcc.8b00061
  14. Meta FAIR Chemistry & collaborators, “Open Molecules 2025 (OMol25) Dataset, Evaluations, and Models,” arXiv preprint, arXiv:2505.08762 (2025) and related resources (overview in Meta FAIR news, accessed 2025-11-24).

The post Colabで分子モデリングからMLPで計算【金属触媒編】 first appeared on LabCode.

]]>
https://labo-code.com/materials-informatics/metal-catalyst-cif/feed/07039
Boltzを使ったタンパク質構造とリガンド複合体の予測【タンパク質デザイン】【分子ドッキング】https://labo-code.com/bioinformatics/boltz-psp/https://labo-code.com/bioinformatics/boltz-psp/#respondThu, 06 Nov 2025 11:15:07 +0000https://labo-code.com/?p=7032

本記事は、タンパク質の構造予測、タンパク質-小分子の複合体構造を高精度に予測するAIツール Boltz について解説します。今回は、環境構築から使い方について、丁寧にご紹介します。 自宅でできるin silico創薬の技 ...

The post Boltzを使ったタンパク質構造とリガンド複合体の予測【タンパク質デザイン】【分子ドッキング】 first appeared on LabCode.

]]>

本記事は、タンパク質の構造予測、タンパク質-小分子の複合体構造を高精度に予測するAIツール Boltz について解説します。今回は、環境構築から使い方について、丁寧にご紹介します。

動作検証済み環境

動作検証済み環境

Windows 11 Home, 13th Gen Intel(R) Core(TM) i7-13700,
64 ビット オペレーティング システム、x64 ベース プロセッサ, メモリ:32GB

Boltz とは?

Boltzは、MITの研究者らによって開発されたオープンソースのAIモデルで、バイオ分子複合体の三次元構造を高精度に予測します。特に、Google DeepMindのAlphaFold3と同等、あるいはそれ以上の精度を達成しながら、商用利用も可能なMITライセンスで提供されている点が大きな特徴です。

Boltzには、構造予測に特化した Boltz-1 と、それに加えて結合親和性予測も可能にした Boltz-2 が存在します。Boltz-2は、物理ベースの計算手法であるFEP (Free Energy Perturbation) と同等の精度を、なんと1000倍以上の高速性で実現するとされています。これにより、創薬における大規模な仮想スクリーニングが現実的な時間で行えるようになり、創薬研究を大きく加速させることが期待されています。

Boltz のアルゴリズム

Boltzのアルゴリズムは、基本的にAlphaFold3と同様に拡散モデル(Diffusion Model) をベースとしています。これは、ランダムなノイズから段階的に構造を「デノイズ(denoising)」していくことで、最終的な高精度な構造を生成するアプローチです。

入力データとして、アミノ酸配列(タンパク質)、SMILES文字列(小分子リガンド)、塩基配列(核酸)などを使用し、これらを統合的に学習します。さらに、Boltz-2では結合親和性を予測するための「アフィニティモジュール」が追加されており、構造予測と親和性予測を同時に行えるようになっています。

また、Boltzには「物理的誘導(Boltz-steering)」という技術が組み込まれており、これにより予測された構造に立体的な衝突などの非物理的なエラーがほとんど発生しないようになっています。

本記事では環境構築とタンパク質の構造予測、タンパク質ーリガンドの複合体予測を行います。


Boltz の利用法(コマンドラインでの利用)

Boltzは、GPU環境での利用が推奨されており、コマンドラインからの利用が一般的です。Webインターフェースを提供しているサービスもありますが、ここでは自身の環境で実行する方法を紹介します。


環境構築

環境構築をしていきます。今回はWindowsのWSLを利用します。GPUを利用するため、WSL2およびCUDAのセットアップが必要です。WSL2の利用方法については、過去の記事を参考にしてください。

以下のコマンドをWSL上で実行して、Boltzの環境を構築します。

# Boltzは、最新のPython環境にインストールすることを推奨
micromamba create -n boltz_env python=3.10 -y
micromamba activate boltz_env
# PyPIからBoltzをインストール
# GPU利用の場合は[cuda]を付ける。CPUのみの場合は削除
pip install boltz[cuda] -U
# またはGitHubから直接インストール
# git clone https://github.com/jwohlwend/boltz.git
# cd boltz
# pip install -e .[cuda]

コードの詳細説明

micromamba create -n boltz_env python=3.10 -y

micromamba を使用して、boltz_env という名前の新しい仮想環境を作成し、Python 3.10をインストールします。これにより、他のPythonプロジェクトとの依存関係の衝突を防ぐことができます。

micromamba activate boltz_env

作成した boltz_env 環境を有効化します。

pip install boltz[cuda] -U

pip を使用して、Python Package Index (PyPI) からBoltz本体をインストールします。

  • boltz[cuda] : GPUを利用するためのCUDA関連パッケージも同時にインストールします。
  • U : パッケージを最新バージョンにアップグレードします。

これでBoltzを実行するための環境が整いました。


Boltzによるタンパク質構造予測

Boltzの実行は、タンパク質配列、小分子のSMILES文字列、またはPDBファイルなどを入力として行います。ここではPDB:9OB2のCDK2/CyclinEに化合物11が結合した結晶を例に行います。

YAMLファイルの作成

まずはBoltzを実行するための設定ファイルであるYAMLファイルを作成していきます。

まずは予測するタンパク質の配列を入手しましょう。

配列はPDBのfastaファイルに書いてあります。

ダウンロードしたFASTA Sequenceを開くと、以下の二つの配列があります。

>9OB2_1|Chain A|Cyclin-dependent kinase 2|Homo sapiens (9606)
SHMMENFQKVEKIGEGTYGVVYKARNKLTGEVVALKKIRLDTETEGVPSTAIREISLLKELNHPNIVKLLDVIHTENKLYLVFEFLHQDLKKFMDASALTGIPLPLIKSYLFQLLQGLAFCHSHRVLHRDLKPQNLLINTEGAIKLADFGLARAFGVPVRTYTHEVVTLWYRAPEILLGCKYYSTAVDIWSLGCIFAEMVTRRALFPGDSEIDQLFRIFRTLGTPDEVVWPGVTSMPDYKPSFPKWARQDFSKVVPPLDEDGRSLLSQMLHYDPNKRISAKAALAHPFFQDVTKPVPHLRL
>9OB2_2|Chain B|G1/S-specific cyclin-E1|Homo sapiens (9606)
GSIIAPSRGSPLPVLSWANREEVWKIMLNKEKTYLRDQHFLEQHPLLQPKMRAILLDWLMEVCEVYKLHRETFYLAQDFFDRYMATQENVVKTLLQLIGISSLFIAAKLEEIYPPKLHQFAYVTDGACSGDEILTMELMIMKALKWRLSPLTIVSWLNVYMQVAYLNDLHEVLLPQYPQQIFIQIAELLDLCVLDVDCLEFPYGILAASALYHFSSSELMQKVSGYQWCDIENCVKWMVPFAMVIRETGSSKLKHFRGVADEDAHNIQTHRDSLDLLDKARAKKA

これを元に以下のような感じでYAMLファイルを作成します。

詳しくはこちらをご覧ください。

cdk2_boltz_input.yaml という形で実装してください。

version: 1
sequences: - protein: id: A sequence: SHMMENFQKVEKIGEGTYGVVYKARNKLTGEVVALKKIRLDTETEGVPSTAIREISLLKELNHPNIVKLLDVIHTENKLYLVFEFLHQDLKKFMDASALTGIPLPLIKSYLFQLLQGLAFCHSHRVLHRDLKPQNLLINTEGAIKLADFGLARAFGVPVRTYTHEVVTLWYRAPEILLGCKYYSTAVDIWSLGCIFAEMVTRRALFPGDSEIDQLFRIFRTLGTPDEVVWPGVTSMPDYKPSFPKWARQDFSKVVPPLDEDGRSLLSQMLHYDPNKRISAKAALAHPFFQDVTKPVPHLRL - protein: id: B sequence: GSIIAPSRGSPLPVLSWANREEVWKIMLNKEKTYLRDQHFLEQHPLLQPKMRAILLDWLMEVCEVYKLHRETFYLAQDFFDRYMATQENVVKTLLQLIGISSLFIAAKLEEIYPPKLHQFAYVTDGACSGDEILTMELMIMKALKWRLSPLTIVSWLNVYMQVAYLNDLHEVLLPQYPQQIFIQIAELLDLCVLDVDCLEFPYGILAASALYHFSSSELMQKVSGYQWCDIENCVKWMVPFAMVIRETGSSKLKHFRGVADEDAHNIQTHRDSLDLLDKARAKKA

タンパク質構造予測の実行と結果

上記を用いて、例えば以下のコードを実行してください。

10分程度で解析が終わります。

boltz predict cdk2_boltz_input.yaml \ --use_msa_server \ --use_potentials \ --diffusion_samples 2 \ --recycling_steps 3 \ --output_format pdb \ --out_dir ./cdk2_boltz_out \ --override \ --no_kernels

各オプションの意味

  • boltz predict cdk2_boltz_input.yaml

    予測ジョブを実行。cdk2_boltz_input.yaml に配列やテンプレ設定が書いてある前提。

  • -use_msa_server

    ColabFold のMSAサーバーで多重アラインメントを取得(外部アクセスあり)。ローカルMSAを使うなら外す。

  • -use_potentials

    幾何・物理的な拘束(ポテンシャル)を併用して、構造破綻を起きにくくするスイッチ。

  • -diffusion_samples 2

    拡散サンプル(独立生成)を2本だけ作る軽量設定。多様性は控えめ・速度は速め。

  • -recycling_steps 3

    リサイクル回数(精度↑だが計算↑)。まずは3で安定起動。

  • -output_format pdb

    出力をPDB形式で保存(mmCIFが良ければcif)。

  • -out_dir ./cdk2_boltz_out

    出力先ディレクトリ。ranked_*.pdb やスコアJSON、ログが入る。

  • -override

    既存の出力があっても上書き。

  • -no_kernels

    Tritonの高速カーネルを使わずPyTorch実装にフォールバック(Ada世代での初期化エラー回避用)。速度はやや落ちるが安定。

実行後はpredictionsフォルダ に input_model_0.pdb などが生成されていれば成功しています。

pymolで可視化すると以下の感じです。

もともとのPDBと重ね合わせてみるとほぼ一致していることがわかります!

黄緑:Boltzで推測した構造

水色:もともとのPDB:9OB2

タンパク質-リガンド複合体の構造予測と結果

Boltzのgithubにyamlの例があるので、それを基に作成します。

yamlファイルを以下のように変更し、ligand_cdk2.yaml として保存してください。

version: 1 # Optional, defaults to 1
sequences: - protein: id: [A] sequence: SHMMENFQKVEKIGEGTYGVVYKARNKLTGEVVALKKIRLDTETEGVPSTAIREISLLKELNHPNIVKLLDVIHTENKLYLVFEFLHQDLKKFMDASALTGIPLPLIKSYLFQLLQGLAFCHSHRVLHRDLKPQNLLINTEGAIKLADFGLARAFGVPVRTYTHEVVTLWYRAPEILLGCKYYSTAVDIWSLGCIFAEMVTRRALFPGDSEIDQLFRIFRTLGTPDEVVWPGVTSMPDYKPSFPKWARQDFSKVVPPLDEDGRSLLSQMLHYDPNKRISAKAALAHPFFQDVTKPVPHLRL - ligand: id: [B] smiles: 'CC1(CC1)NC(=O)O[C@@H]2CC[C@@H](C2)c3[nH]nc(NC(=O)Cc4ccc(cc4)S(=O)(=O)C)c3'

inputのyamlファイルの箇所のみを変更し、以下を実行します。

boltz predict ligand_cdk2.yaml \ --use_msa_server \ --use_potentials \ --diffusion_samples 2 \ --recycling_steps 3 \ --output_format pdb \ --out_dir ./cdk2_boltz_out \ --override \ --no_kernels

実行後は同様のフォルダに結果cdk2_boltz_input_model_0.pdb が保存されています。

pymolで開くと以下のようになっています。確かにリガンドが結合していることがわかります。

もともとのPDBと重ね合わせてみた結果が以下になります。

黄緑:Boltzで推測した構造

マゼンタ:もともとのPDB:9OB2

多少ずれていますが、同じポケットに結合しているのが予測できているのはすごいですね!


最後に

Boltzは、AlphaFold3と同等の高い精度を持ちながら、オープンソースで利用できる強力なツールです。今回は紹介しませんでしたが、Boltz2では結合力の予測や環状ペプチドの予測もできるようです。githubにyamlの書き方例があるので、ぜひ試してみてください! 環境構築は比較的シンプルで、GPUがあればすぐに始めることができます。ぜひ、ご自身の研究に取り入れてみてください。

Boltzのインストール方法や使い方について、さらに詳しい情報を知りたい場合は、Boltzの使い方を解説するチュートリアルビデオも参考にしてください。

参考文献

Boltz MIT License

GitHub – jwohlwend/boltz: Official repository for the Boltz biomolecular interaction models


The post Boltzを使ったタンパク質構造とリガンド複合体の予測【タンパク質デザイン】【分子ドッキング】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/boltz-psp/feed/07032
Colabで分子モデリングからMLPで計算【MOF編】https://labo-code.com/materials-informatics/mof-cif/https://labo-code.com/materials-informatics/mof-cif/#respondTue, 04 Nov 2025 21:59:25 +0000https://labo-code.com/?p=6653

本記事は、機械学習ポテンシャルで計算を回すために必要な分子構造を CIF を主軸に整える実践ガイドで、Google Colab 上で ASE / RDKit / pymatgen を用いて分子と骨格を作成し、分率座標での ...

The post Colabで分子モデリングからMLPで計算【MOF編】 first appeared on LabCode.

]]>

本記事は、機械学習ポテンシャルで計算を回すために必要な分子構造を CIF を主軸に整える実践ガイドで、Google Colab 上で ASE / RDKit / pymatgen を用いて分子と骨格を作成し、分率座標での配置・可視化・基本チェックを経て計算にそのまま使える CIF を再現性高く出力する手順を解説し、最終的に得られた CIF を用いた UMA(Universal Machine-learning interatomic potential) による一点エネルギー計算までを最小ステップで到達できるように整理しており、これにより読者は自分の研究対象の分子構造を自在に作成してすぐに研究・教育の試行錯誤へ活用できるようになります。

動作検証済み環境

Google Colab (2025-05-26), Python 3.10, Torch 2.3.0+cu118, TorchANI 2.2.4, ASE 3.22.1, Matplotlib 3.7.1

0. セットアップ(最初に一度だけ)


これから UiO-66 の構造に CO₂ を入れていきます。

でもその前に、“道具箱”を整えるところから始めましょう。

たとえば実験なら、フラスコや試薬を並べてから反応を始めますよね。

同じように、ここでは分子を作ったり並べたりするための Python ツールをインストールしておきます。

用意するライブラリたち

  • ASE:構造を読み書きしたり、結晶のセルを扱う“万能助手”。

    CIF の読み書きや、後で UMA に渡すのもこの子が担当です。

  • RDKit:SMILES から分子の3D構造をつくる、化学屋の味方。

    「O=C=O」と打つだけで CO₂ の立体構造を出してくれます。

  • pymatgen:CIF の秩序や占有率をチェックする監査官。

    実験CIFにありがちな「0.5サイト混在」も見逃しません。

セットアップコード

まずはこれを一度だけ実行すれば準備完了です。

!pip -q install ase rdkit pymatgen # Colabで失敗する場合は: pip install rdkit-pypi
import numpy as np, os, pathlib
from ase.io import read, write
from ase import Atoms
from rdkit import Chem
from rdkit.Chem import AllChem
# RDKit→ASE(単一コンフォーマ)変換
def smiles_to_rdkit_3d(smiles, num_conf=10, max_iters=200): mol = Chem.AddHs(Chem.MolFromSmiles(smiles)) params = AllChem.ETKDGv3(); params.randomSeed = 42 AllChem.EmbedMultipleConfs(mol, numConfs=num_conf, params=params) res = AllChem.MMFFOptimizeMoleculeConfs(mol, maxIters=max_iters) best_id = int(np.argmin([r[1] for r in res])) conf = mol.GetConformer(best_id) m = Chem.Mol(mol); m.RemoveAllConformers(); m.AddConformer(conf, assignId=True) return m
def rdkit_to_ase(mol): conf = mol.GetConformer() syms, pos = [], [] for a in mol.GetAtoms(): p = conf.GetAtomPosition(a.GetIdx()) pos.append([p.x, p.y, p.z]); syms.append(a.GetSymbol()) return Atoms(symbols=syms, positions=np.array(pos, float))
def to_large_p1_cell(atoms, box=30.0, pbc=True): a = atoms.copy(); a.set_cell(); a.set_pbc((pbc,pbc,pbc)); a.center() return a

この関数たちがやっていること

  • smiles_to_rdkit_3d

    → SMILES 文字列をもとに 複数の立体候補を生成し、最も安定な構造を選ぶ

    乱数シードを固定しているので、何度やっても同じ結果になります。

  • rdkit_to_ase

    → RDKit 分子を ASE の Atoms に変換。これで「実験室」から「計算室」に渡せるようになります。

  • to_large_p1_cell

    → 分子を P1 の立方セルにポンと置く。周期境界をつけておくと、後で UMA や DFT コードにそのまま投げられます。

これで準備完了です。

次のステップでは、UiO-66(MOF骨格)を読み込み、CO₂ の3D構造を作って並べてみる

ところへ進みましょう。いよいよ“分子を置く”作業が始まります。

1. 初期構造を生成 / 読み込み(UiO-66 を持ってくる)


1-1. CIF を Colab に置く

方法A:手でアップロード(確実)

image.png

image.png

  1. 画像どおりに COD 検索(https://www.crystallography.net/cod/search.php)で UiO-66 を入れる
  2. 一覧から 4132636.cif をクリックして保存
  3. Colab 左のフォルダアイコン → Upload4132636.cif を選ぶ

方法B:コマンドで取得(速い)

多くの COD エントリは https://www.crystallography.net/cod/<ID>.cif で直接落とせます。

もし 404 になる場合は方法Aで保存してください。

!wget -O 4132636.cif https://www.crystallography.net/cod/4132636.cif || echo "直接DLできない場合は手動へ"

小ワザ:作業しやすいように、以降は mof.cif という共通名で扱います。

import shutil, os
if os.path.exists("4132636.cif"): shutil.copy("4132636.cif", "mof.cif")
print("exists:", os.path.exists("mof.cif"))

1-2. まずは“中身をチラ見”して安心する

CIF はテキストです。先頭だけ眺めると、由来やセルがすぐわかる。

!head -n 45 mof.cif

ここで 化学式・格子定数・空間群 がそれっぽいか軽く確認。UiO-66 はしばしば Fm-3m(No.225) が出ます。

1-3. ASE/pymatgenで読み込み&基本情報

最初の読み込みで警告が出ても、単点差分が目的なら気にしすぎなくてOK。

from ase.io import read
from pymatgen.core import Structure
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
atoms = read("mof.cif") # 周期系として読む
structure = Structure.from_file("mof.cif")
print("Natoms:", len(atoms))
print("Cell lengths (Å):", atoms.cell.lengths())
print("Cell angles (deg):", atoms.cell.angles())
sga = SpacegroupAnalyzer(structure, symprec=1e-2)
print("Space group:", sga.get_space_group_symbol(), sga.get_space_group_number())

もし 占有率 < 1 の“混在サイト”が含まれていたら(実験CIFあるある)、後で is_ordered を見ます。単一点評価なら P1 に落として使えば実務的には十分です。

1-4. その場でサッと可視化

可視化ツール を立ち上げなくても、雰囲気はこれで掴めます。

from ase.io import read, write
from ase.visualize.plot import plot_atoms
import matplotlib.pyplot as plt
# 人が見やすい2Dスナップを作成
mof_plus_guest = read("mof.cif")
fig, ax = plt.subplots(figsize=(5, 4.5), dpi=250)
# 回転角度: 'degXx,degYy,degZz' 形式(例:'0x,45y,0z')
# 原子半径: radii=0.9 前後で調整(0.3〜1.2くらいが目安)
plot_atoms( mof_plus_guest, ax, rotation='0x,0y,0z', radii=0.9, show_unit_cell=2 # セル枠も薄く表示(=2で枠のみ)
)
ax.set_axis_off()
plt.tight_layout()

もっと拡大して見たい/原子を消したい時は、のちほど Avogadro でも確認します。

image.png

1-5. “作業用プレビュー”を書き出す(後工程の定番)

以降の章で編集しても原本を壊さないよう、コピーを作ってそちらを触ります。

from ase.io import write
framework_preview = "framework_preview.cif"
write(framework_preview, atoms)
print("wrote:", framework_preview)

この framework_preview.cif を使って、CO₂ を入れる・回す・位置を変えるといった作業に進みます。

(※原本 mof.cif はそのまま温存しておくと、いつでもやり直せて安心。)

1-6. 補足:COD以外で MOF CIF を探すなら?

サイト名特徴リンク
Materials ProjectDFT再最適化済みの構造が多く、溶媒を除いたクリーンなフレームが揃っている。検索で「UiO-66」または「mp-」IDで。🔗 https://materialsproject.org/
CSD (Cambridge Structural Database)実験CIFの宝庫。溶媒入り・なし両方あり。大学・企業ライセンスが必要。🔗 https://www.ccdc.cam.ac.uk/structures/
MOFdb / CoRE-MOF Database“Cleaned MOF structures” を提供。DMFなどの溶媒分子を自動で除去したバージョン。UiO-66 も含まれる。🔗 https://gregchung.github.io/coremof/
QMOF Database (NIST)機械学習ポテンシャルやDFT計算用に最適化されたMOF構造。溶媒なしが基本。🔗 https://qmof.crystals.ai/

💬 個人的おすすめは CoRE-MOF(“Computation-Ready Experimental MOF Database”)。

UiO-66 を含む主要MOFが、溶媒除去済みでそのまま計算に使える からです。

ここまでで、UiO-66 の CIF が Colab に入り、読む・見る・複製するの三拍子がそろいました。CO₂ の 3D を作って、いよいよ“置いてみる”に進みます。

2. 軽い微調整:Avogadro で“整える”


ここで、MOFに入れるゲスト分子を作ります。今回は下記のようにCO2を作成します。

from ase.build import molecule
from ase.io import write
# CO2分子を作成し、guest_co2.xyzとして保存
co2 = molecule("CO2")
write("guest_co2.xyz", co2)
print("CO2ファイルを作成しました → guest_co2.xyz")

他の分子を作成したい場合、下記のコードで作成できる分子を確認して下さい。

かなりの分子をASEを使って作成することが出来ます。

from ase.collections import g2
print(g2.names) #doctest:+NORMALIZE_WHITESPACE

次に作成したファイルをAvogadro or VESTAで確認していきます。

Avogadroは以下の公式サイトでダウンロードすることが出来ます。

Avogadroのダウンロードページを開くと以下のようなページに遷移するので、タブ内中央の”Download”をクリックしてください。自動的にダウンロードが開始されます。

Avogadroの詳細なダウンロード方法・使い方は下記の記事を参考にしてください。。

【Avogadro】AvogadroでGaussianの構造最適化入力ファイルを作成しよう! – LabCode

VESTAは下記のダウンロードサイトからセットアップしてください。

Download – VESTA

ここは“髪を整える”くらいの小さな手直し。触りすぎないのがコツ。

分子(CO₂)

  1. guest_co2.xyzAvogadro で開く
  2. 直線性衝突を目視
  3. 必要なら Extensions → Optimize Geometry → UFF or MMFF を軽く一回
  4. そのまま上書き保存(ファイル名は維持)

骨格(UiO-66)

  1. framework_preview.cifAvogadroVESTA で開く
  2. 格子と配位環境を眺めるだけ(空間群は触らない
  3. 保存する場合は CIF形式のまま。ここでも“触りすぎない”

❗ 骨格の μ₃-OH などは構造の一部なので削らないでOK。溶媒だけを落とす場合は、元から溶媒なし構造を取り直す方が安全です。

P1運用(必要になったら)

# 対称性で“跳ぶ”挙動が気になるときは P1 に落とす
from ase.io import read, write
tmp = read("framework_preview.cif")
write("framework_P1.cif", tmp) # 実質 P1 相当で出力

image.png

VESTAで可視化したUiO-66

3. 置いてみる:ゲスト配置 → 合成CIFをつくる


いよいよ“分子を置く”時間。分率座標で吸着サイトを狙い撃ち。

# MOF骨格のプレビューCIF(必要ならファイル名を整えるだけ)
framework_preview = "framework_preview.cif"
# Load the guest molecule from the previously created xyz file
guest = read("guest_co2.xyz")
# まずはセル中心付近に1分子置く簡単例
combined = read(framework_preview).copy()
cell = combined.get_cell()
center_cart = (cell[0] + cell[1] + cell[2]) * 0.5
mol = guest.copy()
for ax in ("x","y","z"): # ランダム回転(必要なら固定角度に) if ax == "x": axis = (1, 0, 0) elif ax == "y": axis = (0, 1, 0) elif ax == "z": axis = (0, 0, 1) mol.rotate(np.random.uniform(0,360), v=axis, center="COM")
mol.translate(center_cart - mol.get_center_of_mass())
combined += mol
out_cif = "mof_plus_guest.cif"
write(out_cif, combined)
print("wrote:", out_cif)
# 分率座標指定で配置したいときの関数
def place_guest_by_frac(framework_atoms, guest_atoms, frac_xyz=(0.5,0.5,0.5)): f = framework_atoms.copy() g = guest_atoms.copy() # 分率→直交 frac = np.array(frac_xyz) cart = frac @ f.get_cell().array # (1x3) * (3x3) # 回転など必要ならここで g.translate(cart - g.get_center_of_mass()) return f + g
# 例:a/4, b/4, c/2 に置く
combined2 = place_guest_by_frac(read(framework_preview), guest, (0.25,0.25,0.25))
write("uio66_co2_safe.cif", combined2)

今回は分率座標指定で作成しています。CO2をa/4, b/4, c/4 に置いて、フレームワークと合体したファイルをuio66_co2_safe.cifというファイルで出力しています。

下記で分子が入っているか確認してみましょう。

4. 目視スナップ(2D図を作って保存)


下記を実行するとCO2がMOFのフレームワーク内に入っていることがわかります。

分かりにくい場合は、回転させて見やすい位置を探してください。

# 必要なimport(未済なら)
from ase.io import read, write
from ase.visualize.plot import plot_atoms
import matplotlib.pyplot as plt
# ① P1に落としておく(分率ズレや対称性の自動補正を避ける)
# ※「分率座標で狙う」で書き出したファイル名に合わせて置き換えてOK
tmp = read("uio66_co2_safe.cif") # ← 直前に作った合成CIF
write("mof_plus_guest_frac_P1.cif", tmp) # ← P1運用ファイル
# ② 人が見やすい2Dスナップを作成
mof_plus_guest = read("mof_plus_guest_frac_P1.cif")
fig, ax = plt.subplots(figsize=(5, 4.5), dpi=250)
# 回転角度: 'degXx,degYy,degZz' 形式(例:'0x,45y,0z')
# 原子半径: radii=0.9 前後で調整(0.3〜1.2くらいが目安)
plot_atoms( mof_plus_guest, ax, rotation='0x,45y,0z', radii=0.9, show_unit_cell=2 # セル枠も薄く表示(=2で枠のみ)
)
ax.set_axis_off()
plt.tight_layout()
plt.savefig("uio66_co2_view.png", bbox_inches="tight", pad_inches=0.02)
print("saved: uio66_co2_view.png")

コツ

  • 回転は 'ax,by,cz' の角度指定。吸着サイトが見える方向を探す感覚で何枚か出すと◎

    例:'30x,30y,0z', '0x,60y,0z', '45x,45y,30z'

  • radii は印象が変わりやすいので、0.7–1.0あたりを中心に微調整。

  • show_unit_cell=2セル枠が入り、MOFのポア感が伝わりやすくなります。

  • 複数候補を自動出力するなら、回転角だけforループで回して

    uio66_co2_view_01.png, _02.png, ... として保存しておくと便利 (付録で記載)。

image.png

5. 最終チェック:距離・占有率・セル


ここは“出荷前の検査”。衝突がないか/占有率が健全か/セルが変になってないかを、数十秒で確かめます。

from ase.io import read
import numpy as np
from pymatgen.core import Structure
final_path = "mof_plus_guest_frac_P1.cif" # 確認したい合成CIF
atoms = read(final_path)
# 5-1) 最近接距離(PBC, 最小鏡像)— 衝突の赤信号を消す
D = atoms.get_all_distances(mic=True)
np.fill_diagonal(D, 1e9)
dmin = float(D.min())
print(f"[Min distance] {dmin:.3f} Å ← ~0.61 Å 未満なら衝突疑い・配置を見直す")
# 5-2) セルの基本情報 — “変なセル”になっていないか
a, b, c = atoms.cell.lengths()
alpha, beta, gamma = atoms.cell.angles()
print(f"[Cell lengths] a={a:.3f}, b={b:.3f}, c={c:.3f} Å")
print(f"[Cell angles ] α={alpha:.2f}, β={beta:.2f}, γ={gamma:.2f}°")
# 5-3) 占有率チェック — 実験CIF由来の“半占有”に注意
s = Structure.from_file(final_path)
print("[is_ordered] True=すべて占有率1.0:", s.is_ordered)
if not s.is_ordered: print(" ↳ 注意:無秩序サイトあり(占有率≠1.0)。単一点ならP1運用で実務的にはOK、厳密には展開を検討。") for i, site in enumerate(s.sites): if not site.is_ordered: print(f" - site #{i}: {site.species}") # 例: {'O': 0.5, 'N': 0.5} など

読み取り方(サッと)

  • 最短距離が ~0.61 Å 未満 → どこかがめり込んでる合図。回転・初期高さを少し変えて再出力してください(しきい値 0.61 Å はプレーンのUiO-66の最短距離)。
  • is_ordered = False → 実験CIFあるあるの“半占有”。P1固定で単点を回すだけなら許容だが、厳密な解析では明示展開(どちらかに寄せる)を。
  • セルは UiO-66 らしい立方に近い数値が出ていればOK(細かな差は測定由来のことも多い)。

付録:UMA で単点(E_ads)— “数を出して感触を掴む”


定義(eV)

Eads=E[MOF+CO2]−E[MOF]−E[CO2]

→ 吸着“有利”(発熱)/ → 吸着“不利”(吸熱)

準備

下記のコードを実行してください。

機械学習ポテンシャルUMAの使用許可の取得やトークン作成は詳細は下記の記事を参考にしてください。

MOF吸着エネルギー計算の新手法:DFT精度を瞬時に再現【機械学習ポテンシャル】 – LabCode

!pip install fairchem-core
!huggingface-cli login

A. 最小例(1配置でサクッと試す)

from fairchem.core import FAIRChemCalculator, pretrained_mlip
from ase.io import read
# UMA の読み込み(ODAC: CO2/H2O 吸着向けタスク)
unit = pretrained_mlip.get_predict_unit("uma-s-1p1")
calc = FAIRChemCalculator(unit, task_name="odac") # device は自動。CPU固定なら device="cpu"
# 構造
mof_co2 = read("mof_plus_guest_frac_P1.cif") # UiO-66 + CO₂(P1)
mof_empty = read("mof.cif") # UiO-66(空)
co2 = read("guest_co2.xyz") # CO₂(分子)
for a in (mof_co2, mof_empty, co2): a.calc = calc
E_mof_co2 = mof_co2.get_potential_energy()
E_mof_empty = mof_empty.get_potential_energy()
E_co2 = co2.get_potential_energy()
Eads = E_mof_co2 - E_mof_empty - E_co2
print(f"Eads = {Eads:.3f} eV (negative=adsorption favorable)")

B. 複数候補から“まっとうな”ものを選ぶ(おすすめ)

配置次第で符号すら変わるのが実務。まずは複数配置を作り、最短距離で弾く→Eads最小を採用するとハズレにくい。

import os, numpy as np, itertools, csv, glob
from pymatgen.core import Structure, Molecule, Site
from pymatgen.core.operations import SymmOp
# ---------- 既存の関数(そのまま利用) ----------
def place_molecule_with_clearance(framework: Structure, mol: Molecule, frac_xyz=(0.5,0.5,0.5), min_clear=2.0, tries=300): lat = framework.lattice target_cart = lat.get_cartesian_coords(frac_xyz) for _ in range(tries): m = mol.copy() # ランダム回転 axis = np.random.rand(3); axis /= np.linalg.norm(axis) angle = np.random.rand()*360 m.apply_operation(SymmOp.from_axis_angle_and_translation(axis, angle, [0,0,0])) # COMを目標位置へ平行移動 shift = target_cart - m.center_of_mass m.translate_sites(range(len(m)), shift) # 一時的に合体して最近接をPBCでチェック tmp = framework.copy() start_idx = len(tmp) for sp, xyz in zip(m.species, m.cart_coords): tmp.append(sp, tmp.lattice.get_fractional_coords(xyz)) # PBC-aware ok = True for i in range(start_idx, len(tmp)): # ゲスト原子の近傍にフレーム原子が min_clear 未満で居ないか nns = tmp.get_neighbors(tmp[i], r=min_clear) if any(nn.index < start_idx for nn in nns): ok = False; break if ok: return tmp # 衝突なし → 採用 raise RuntimeError("配置に失敗(min_clearを下げる/位置を変える/triesを増やす)")
# ------------------------------------------------
# 入力(溶媒なし UiO-66 を推奨:CoRE-MOF / Materials Project / QMOF 等から)
framework_path = "/content/4132636.cif" # ここはあなたのUiO-66に合わせて
guest_path = "/content/guest_co2.xyz" # 3章で用意したCO2
mof = Structure.from_file(framework_path)
co2 = Molecule.from_file(guest_path)
# 置いてみる候補の“分率座標”たち(必要に応じて増やす/変更OK)
frac_points = [ (0.50, 0.50, 0.50), (0.25, 0.25, 0.25), (0.75, 0.25, 0.50), (0.25, 0.10, 0.25), (0.40, 0.40, 0.60), (0.60, 0.40, 0.40),
]
min_clear = 0.61 # Å:衝突回避の最小距離
tries = 300 # 試行回数(当たりが少ない座標は増やす)
os.makedirs("/content/candidates", exist_ok=True)
saved = []
for i, frac in enumerate(frac_points, start=1): try: placed = place_molecule_with_clearance(mof, co2, frac_xyz=frac, min_clear=min_clear, tries=tries) out = f"/content/candidates/uio66_co2_safe_{i:02d}.cif" placed.to(filename=out) print("saved:", out, "at frac", frac) saved.append(out) except RuntimeError as e: print(f"[skip] frac={frac}: {e}")
print("----")
print("safe candidates:", len(saved), "files")

作成したファイルを計算します。

import glob, csv
import numpy as np
from ase.io import read
from fairchem.core import FAIRChemCalculator, pretrained_mlip
# UMAの読み込み
unit = pretrained_mlip.get_predict_unit("uma-s-1p1")
calc = FAIRChemCalculator(unit, task_name="odac") # task_name=odac: gas adsorption向け
# 参照系(空MOFとCO2)
mof_empty = read("/content/4132636.cif")
co2 = read("/content/guest_co2.xyz")
for a in (mof_empty, co2): a.calc = calc
E_mof_empty = mof_empty.get_potential_energy()
E_co2 = co2.get_potential_energy()
print(f"E_mof_empty = {E_mof_empty:.3f} eV")
print(f"E_co2 = {E_co2:.3f} eV")
# 候補フォルダ内のCIFを探索
paths = sorted(glob.glob("/content/candidates/uio66_co2_safe_*.cif"))
print("Found", len(paths), "candidates.")
rows = []
for path in paths: a = read(path) a.calc = calc E_mof_co2 = a.get_potential_energy() Eads = E_mof_co2 - E_mof_empty - E_co2 rows.append((path, Eads)) print(f"{path.split('/')[-1]:30s} Eads = {Eads:7.3f} eV")
# 吸着エネルギーで並べ替え
rows.sort(key=lambda x: x[1])
# 保存
with open("/content/candidates/Eads_scan.csv", "w", newline="") as f: w = csv.writer(f) w.writerow(["path","Eads_eV"]) w.writerows(rows)
print("→ saved: /content/candidates/Eads_scan.csv")
# 最も安定な候補
best_path, best_E = rows[0]
print(f"\n✅ 最も安定: {best_path} (Eads = {best_E:.3f} eV)")

出力

  • uio66_co2_safe_01.cif Eads = -1.399 eV
  • uio66_co2_safe_02.cif Eads = -1.551 eV
  • uio66_co2_safe_03.cif Eads = 92.727 eV
  • uio66_co2_safe_04.cif Eads = 1.492 eV
  • uio66_co2_safe_05.cif Eads = -1.307 eV
  • uio66_co2_safe_06.cif Eads = -1.310 eV`

どう読む?

  • 初期(“デフォルト”配置)Eads ≈ -1.399 eV(非常に強い吸着)

  • 位置調整後 ex. uio66_co2_safe_03.cif → Eads ≈ +92.727 eV(明確に不利)

    • 恐らくめり込んでいる。
  • つまり 配置(姿勢・高さ)の違いだけで符号が反転することがあります。

    “1配置で結論を出さない” が鉄則。複数候補+(必要なら)ごく軽い緩和最小Eadsを採用するのが現実解。

目安:UiO-66×CO₂なら、文献や既知の“妥当帯域”は –0.3 〜 –0.6 eV 付近に落ちることが多いです。

−1 eV 級の強い値や +1 eV の正値は、初期配置のバイアス局所衝突/反発の影響を疑って、構造最適化行い、配置や姿勢を見直してください。

最後に


いかがでしたか?本記事で紹介した分子構造の作り方を一度試していただき、機械学習ポテンシャルを使って計算を回していただくと、計算化学がより身近に感じられると思います。Cifファイルは論文などによく記載されているので、ゲスト分子を入れずに計算するだけでも面白いと思いますので是非試してみてください。

参考文献


  1. K. Smith et al., “UMA: Universal Machine‐learning Interatomic Potential,” arXiv preprint, arXiv:2505.08762 (2025). https://arxiv.org/abs/2505.08762
  2. FAIRchem Team, “FAIRChem: FAIR Chemistry Toolkit,” GitHub Repository (2025). https://github.com/facebookresearch/fairchem
  3. Meta FAIR Chemistry, “facebook/UMA,” Hugging Face Model Card (2025). https://huggingface.co/facebook/UMA
  4. B. M. Wood et al., “UMA: A Family of Universal Models for Atoms,” arXiv preprint, arXiv:2506.23971 (2025). https://arxiv.org/abs/2506.23971
  5. S. Kitagawa, R. Kitaura, and S. Noro, “Functional Porous Coordination Polymers,” Angew. Chem. Int. Ed. 43, 2334–2375 (2004). https://doi.org/10.1002/anie.200300610
  6. S. Horike, S. Shimomura, and S. Kitagawa, “Soft porous crystals,” Nature Chem. 1, 695–704 (2009). https://doi.org/10.1038/nchem.444
  7. H. Furukawa, K. E. Cordova, M. O’Keeffe, and O. M. Yaghi, “The chemistry and applications of metal–organic frameworks,” Science 341, 1230444 (2013). https://doi.org/10.1126/science.1230444
  8. J. H. Lee et al., “Design strategies for metal–organic frameworks in direct air capture of CO₂,” Coord. Chem. Rev. 463, 214536 (2022). https://doi.org/10.1016/j.ccr.2022.214536
  9. J. H. Cavka et al., “A new zirconium inorganic building brick forming metal–organic frameworks with exceptional stability,” J. Am. Chem. Soc. 130, 13850–13851 (2008). https://doi.org/10.1021/ja8057953 PubMed
  10. Crystallography Open Database (COD), Entry 4132636: UiO-66 (accessed 2025-11-03). https://www.crystallography.net/cod/4132636.cif crystallography.net

The post Colabで分子モデリングからMLPで計算【MOF編】 first appeared on LabCode.

]]>
https://labo-code.com/materials-informatics/mof-cif/feed/06653
MOF吸着エネルギー計算の新手法:DFT精度を瞬時に再現【機械学習ポテンシャル】https://labo-code.com/materials-informatics/mof-mlp-uma/https://labo-code.com/materials-informatics/mof-mlp-uma/#respondTue, 23 Sep 2025 08:43:11 +0000https://labo-code.com/?p=6994

機械学習ポテンシャル UMA を用いることで、MOF の吸着エネルギーを DFT 並みの精度で、100~10,000 倍高速 に評価できます。本記事では、Mg-MOF-74 と WOBHEB を題材に、Colab 上で実 ...

The post MOF吸着エネルギー計算の新手法:DFT精度を瞬時に再現【機械学習ポテンシャル】 first appeared on LabCode.

]]>

機械学習ポテンシャル UMA を用いることで、MOF の吸着エネルギーを DFT 並みの精度で、100~10,000 倍高速 に評価できます。本記事では、Mg-MOF-74 と WOBHEB を題材に、Colab 上で実際に吸着エネルギーを計算・可視化する方法を解説します。

動作検証済み環境

Google Colab (2025-05-26), Python 3.10, Torch 2.3.0+cu118, TorchANI 2.2.4, ASE 3.22.1, Matplotlib 3.7.1

1. 機械学習 (ML) ポテンシャルとは?


DFT計算で毎回数時間待つのは大変ですよね。この記事ではその時間を一瞬に変える方法をお伝えします!

※ 今回、モデルアーキテクチャは解説しません。気になる方は参考文献を参照してください。

MLポテンシャル (Machine-Learning Interatomic Potential) とは、

「量子化学計算(DFT / ab initio)が返すエネルギーと力を、ニューラルネットなどの統計モデルでほぼ同精度・桁違い高速に近似するもの」 です[1]。

以下でもう少し詳しく見ていきます。

  1. なぜ速いのか
    • DFT は電子波動関数を自洽的に解くため計算量が O(N³) 以上。
    • ML ポテンシャルは 原子座標 → ニューラルネットへの順伝播 だけなので O(N) に近い。
    • その結果、10²〜10⁴ 倍 速い評価が可能になります。
  2. 精度は大丈夫?
    • 学習データを高精度 DFT / CCSD(T)など で網羅的にサンプリング。
    • 多くの有機分子での誤差 (MAE) は < 1 kcal mol⁻¹[2]
    • ただし、訓練集合の化学空間から外れると外挿誤差が発生しやすい点に注意が必要です(データセットは機械学習ポテンシャルのGithubなどに後悔されていることが多いので精度が気になる場合はチェックしましょう)。

2. UMA とは 〜“分子も固体も 1 つのモデルで”〜


ポイント先取り

  • Universal:有機分子・イオン・結晶まで 1 つのチェックポイントで対応
  • Machine-learning:ニューラルネットによる end-to-end ポテンシャル
  • Interatomic Potential:エネルギー E と原子ごとの力 F = –∇E を高速出力

2.1 誕生の背景 — 「モデル乱立問題」への 1 つの解

これまでの ML ポテンシャルは “タスク別/元素系別” に細分化され、

モデル得意分野
ANIH, C, N, O の有機分子医薬探索
CHGNet金属間化合物2D 材料
GAP-SOAPSi, Ge, Cu など単一元素半導体

「データセットごとにモデルを切り替える」 必要がありました。

そこで Meta/FAIR Chemistry が提唱したのが UMAUniversal Machine-learning interatomic potentialです。UMAは“83 元素/分子〜固体/中性〜イオン まで 1 つで捌ける汎用モデル” を掲げ、モデル乱立問題 を緩和することを狙っています [1]。

2.2 どうして “Universal” を名乗れるのか?

❶ 1 億構造規模のトレーニングセット

  • OMol25 + OMat25 + OBulk25 など、DFT で計算した 約 1 × 10⁸ 構造を学習
  • 凝縮相から気相、表面吸着、荷電状態までを網羅

❷ “タスク名” で出力層を切替

UMA には 5つのサブヘッド があります。

  • omol:有機/無機分子
  • omat:クラスター/多原子イオン(無機材料)
  • oc20:触媒表面反応(OC20)
  • odac:MOF(金属–有機構造体)
  • omc:分子結晶

ユーザーは task_name="omol" などと指定するだけで、

「同じ重み+異なる最終層」へのスイッチが内部で行われます。

UMAの各タスク

UMAは理論レベルの異なる5種類のDFTデータセットで訓練されており、各タスクに対応する埋め込みを学習します。推論時には、出力に使いたい理論レベル(タスク)を指定してください。

評価したい系に対してどのモデルを使ったら良いかは下記を参考にして下さい!

タスクデータセットDFT理論レベル主な用途注意事項
omolOMol25ORCA6実装の wB97M-V/def2-TZVPD(非局所分散含む)※溶媒和は明示的に扱う生物学、有機化学、タンパク質フォールディング、低分子医薬品、有機液体物性、均一系触媒総電荷・スピン多重度を指定必須。不明時は注意。非周期系データのみ。無機材料には不向き。
omcOMC25VASP実装の PBE+D3医薬品包装、バイオインスパイア素材、有機エレクトロニクス、有機LED電荷・スピン多重度は学習せず、total_charge=0・spin=0を想定。
omatOMat24VASP実装の PBE/PBE+U(Materials Project設定、VASP 5.4疑似ポテンシャル)※分散相互作用なし無機材料探索、太陽光発電、先進合金、超電導体、電子・光学材料電荷・スピン多重度は学習せず、total_charge=0・spin=0を想定。スピン偏極効果は含むが状態選択不可。訓練データでは全スピン状態をサンプリングせず。
oc20OC20VASP実装の RPBE(VASP5.4疑似ポテンシャル)※分散相互作用なし再生可能エネルギー、触媒、燃料電池、エネルギー変換、持続可能肥料生産、化学精製、プラスチック合成・アップサイクリング電荷・スピン多重度は学習せず、total_charge=0・spin=0を想定。酸化物・溶媒は非対応。遷移状態探索は良好だが注意。大規模系では分散が重要。
odacODAC23VASP実装の PBE+D3(VASP5.4疑似ポテンシャル)直接空気回収、CO₂回収・貯留、CO₂変換、触媒電荷・スピン多重度は学習せず、total_charge=0・spin=0を想定。CO₂/H₂O吸着データのみ。MOF内炭化水素は不正確の可能性、大規模MOFは注意。

※OC20は元データを総エネルギー出力用に再計算済み。

2.4 モデルファミリと精度ベンチマーク

下記がモデルのベンチマークです。私も最初、このMAE値を見たときは二度見しました…!“短時間でこんなに精度が出るの!?”と驚いたことを覚えています[4]。

チェックポイント対象エネルギー MAE (eV/atom)力 MAE (eV Å⁻¹)
UMA-S-1有機分子中心0.0350.070
UMA-C-1結晶・固体0.0410.083
UMA-I-1イオン・溶媒系0.0380.076

※ Meta/FAIRChem が公開した OMol25/OBulk25 テストセットでの値

2.5 長所と短所を整理

観点強み注意点
適用範囲分子〜固体を 1 モデルで超高温・超高圧など外挿領域は未検証
速度GPU で 10⁴ 構造/s大規模表面 (>2 000 原子) ではメモリ要件増
精度DFT PBE 同等の MAE長距離クーロン・分極は過小評価の傾向
導入難度HF トークン 1 行セットオフライン使用はライセンス確認が必要

ワンポイント

  • イオン系charge, spinAtoms.info に必ず設定
  • 未知化学空間:最初の 10 ステップだけ DFT を回し、Δラーニングで誤差補正する手法が有効

2.6 はじめて使う人へ “つまずきポイント” チェックリスト

はじめてUMAを使った際には下記のポイントで躓きました。皆さんも注意してください。

チェックWhy?How?
HF_TOKEN 設定した?認証失敗で重みが落ちてこないprint(os.getenv("HF_TOKEN"))
task_name 合ってる?omolcbulk を誤ると誤差大サンプルコードをコピペ
元素対応?UMA は 83 元素、だが U を超える超重元素は未学習pred.can_handle(element) で確認

2.7 UMAのライセンス

ここではUMAを使う際のライセンスについて解説します。有用なモデルですが、しっかりライセンスを遵守して使用してください。

ライセンス概要

項目内容
ライセンスタイプFAIR Chemistry License v1
主な利用条件モデル自体および派生モデルの非営利/営利利用可- 再配布・頒布時にライセンス文を同梱
再配布・商用利用追加の書面での許諾が必要(Hugging Face上で申請)
引用義務論文・技術資料に “UMA: Universal Machine‐learning Interatomic Potential” を明記
免責事項モデルの予測結果に関する責任は利用者が負う

2.7.1 FAIR Chemistry License v1 の入手方法

  1. Hugging Face 上のリポジトリページ(facebook/UMA)を開く
  2. “License” セクションで FAIR Chemistry License v1 リンクをクリック
  3. 表示された条文をダウンロード・保存
# 例:コマンドラインでライセンスファイルを取得
wget <https://raw.githubusercontent.com/facebookresearch/fairchem/main/LICENSE>

2.7.2 ライセンス条項のポイント解説

  1. 利用権許諾(Grant of Rights)
    • モデルの 推論実行研究目的の再学習評価 は無償で許可
  2. 再配布条件(Redistribution)
    • モデルファイルを丸ごと再配布する場合、必ず LICENSE ファイルを同梱
    • 派生モデル(ファインチューニング後)を配布する際も同様
  3. 商用利用(Commercial Use)
    • 製品やサービスに組み込む際は、別途 書面による許可 を取得
    • 許可申請は Hugging Face のフォームから行い、承認まで 1–2週間程度
  4. 帰属表示(Attribution)
    • ドキュメントや論文に “UMA: Universal Machine‐learning Interatomic Potential” を明記
    • 可能であればオリジナル論文 [arXiv:2505.08762] を引用
  5. 免責(Disclaimer)
    • モデルの精度や適用結果について保証なし
    • 事故や損害が発生しても著作権者は責任を負わない

2.7.3 利用前チェックリスト

チェック項目確認方法
LICENSE ファイルを取得・同梱しているかHugging Face からダウンロードし、プロジェクトルートに配置
❏ 商用利用の承認申請が完了しているかHugging Face のライセンス同意フォームに入力後、承認メールを待機
❏ ドキュメントへの帰属表示を追加済みかREADME や報告書の冒頭にUMAの名称・論文情報を記載
❏ 派生モデルの再配布条件を満たしているかファインチューニング後に配布する際も LICENSE を必ず同梱し、READMEで明示

概要は理解できましたか?それでは次は実際に手を動かして試してみましょう。小さな分子から始めるのがおすすめです。

3 . Hugging Face 準備:モデル利用許可&トークン取得


UMA モデルは Hugging Face Hub 上の facebook/UMA リポジトリから配布されていますが、ファイル取得前に以下の手順が必要です[3]。モデルの使用許可が下りるまでは約1-2日ほど掛かります。

ステップ詳細
① 利用許可の同意1. https://huggingface.co/facebook/UMA にアクセス 2. 「You need to agree to share your contact information…」のフォームを開く 3. 氏名・生年月日・所属組織名などを正確に入力し、FAIR Chemistry License v1 への同意を完了
② トークン発行プロフィール右上 → SettingsAccess TokensNew tokenName: 任意(例: for_private_UMA) – Role: Fine-grainedRead 権限のみ

ステップ①:利用許可の同意と申請(2025年7月1日付)

ステップ②:アクセストークンの発行

モデルの使用許可が出たらGoogle Colabでpipをインストールしてください。

!pip install fairchem-core

インストールが終わり次第ログインを行います。ログインではステップ②トークン発行で出力された文字列を使用します。

!huggingface-cli login

下記のように入力コンソールが出力されるので、トークンを入力してください。

これでモデルの使用準備は完了しました。

4. 実践チュートリアル:MOF 吸着エネルギー計算で素材探索ストーリーを体験する


4.0 MOF とは?—“穴だらけ結晶”の魅力とブリージング現象

  • Metal–Organic Framework (MOF) =金属ノードと有機リンカーで組んだ多孔性結晶のことで、有機無機ハイブリッド材料です。比表面積は活性炭の数倍〜十倍あるとされています。
  • 一部の MOF はガス・温度・圧力など外部刺激で フェーズが可逆変形し、これを ブリージング現象 と呼ばれます。学術的には “flexible MOF” や “soft porous crystal” が用語として定着しています [5]。
  • 吸着エネルギー$E_{ads}$
    • $E_{ads}$ < 0 →吸着が自発的。
    • $E_{ads}$ が大きいほどキャッチ力↑、ただし再生(脱着)に要するエネルギーも↑。
    • CO₂ 回収 (DAC):–0.30 〜 –0.50 eV が「捕まえてすぐ離す」理想帯域 [6]
    • ブリージング MOF では $E_{ads}$ =$E_{int}$ +$E_{deform}$ と分解することで「相互作用強化」か「骨格変形」どちらが効いているか定量評価できます[7]。

4.1 秒速 DFT を実現する UMA × ODAC23

UMA と ODAC23 を組み合わせることで、DFT で数時間かかるポテンシャルエネルギー評価を 数ミリ秒 で実行できます。

  • ODAC23 は、MOF と CO₂/H₂O の組み合わせ約8,400系統から得られた 17.6 万構造の DFT データセットです。
  • UMA-s-1p1 は、ODAC23 を含む5種類のデータセットで学習された GNN ポテンシャル。DFT 相当の精度を ms オーダーで推論することができます。

4.2 ケース①:硬い Mg-MOF-74 で CO₂ 捕集力を測る

4.2.1 処理の流れの説明

まずは剛直構造の代表格である Mg-MOF-74 を使い、CO₂ 捕集性能を評価します。

  1. モデル初期化:UMA-s-1p1 + ODAC23 タスク
  2. 構造読み込み:空フレームワーク/CO₂ 封入/参照 CO₂
  3. エネルギー差分$E_{ads}$ を差分計算

この流れで算出した$E_{ads}$ が、既報の –0.40 ~ –0.45 eV と一致すれば、以降のスクリーンングにおける信頼度が担保されます。

from fairchem.core import FAIRChemCalculator, pretrained_mlip
from ase.io import read
# 1. モデル&計算器の初期化
unit = pretrained_mlip.get_predict_unit("uma-s-1p1")
calc = FAIRChemCalculator(unit, task_name="odac")
# 2. 構造読み込み&計算器設定
paths = ["OPAGIX_w_CO2.cif", "OPAGIX.cif", "co2.xyz"]
mof_co2, mof_empty, co2 = [read(p) for p in paths]
for atoms in (mof_co2, mof_empty, co2): atoms.calc = calc
# 3. エネルギー差分で吸着エネルギーを算出
Eads = ( mof_co2.get_potential_energy() - mof_empty.get_potential_energy() - co2.get_potential_energy()
)
print(f"CO₂@Mg-MOF-74 → Eads = {Eads:.3f} eV")

ココがポイント

  • ODAC23 用の CIF はすでに高精度 DFT 最適化済み。追加の緩和計算は不要。
  • 推論は ms オーダーなので、数千候補を短時間でスクリーニング可能。

4.2.2 結果と考察

  • 実行例:
E_ads ≈ – 0.41 eV
  • 文献値 :– 0.44 eV とほぼ一致 → UMA+ODAC23 の再現性良好
  • 示唆:以上の結果、Mg-MOF-74 は「理想的な CO₂ 捕集帯域 (–0.30 ~ –0.50 eV)」の中心に位置し、再生可能な吸着剤候補として有望だと考えられます。また、この結果は、UMA が剛直 MOF において DFT と同等の吸着エネルギーを再現できることを示し、柔軟 MOF の解析に進む前の “ベースライン確認” として有用と考えることが出来ます。

4.3 ケース②:骨格呼吸を持つ柔軟 WOBHEB で吸着能を深掘り


剛直なフレームワークで精度を確認した後は、柔軟性を持つ MOF で一歩進んだ解析を行います。ここでは「ブリージング (骨格の可逆変形)」が吸着力にどう寄与するかを定量化します。

4.3.1 ブリージング寄与の分解手法

吸着エネルギー $E_{ads}$ を、

  • $ E_{int} $:ホスト–ゲスト相互作用(骨格固定時の寄与)

  • $E_{deform}$:骨格変形による寄与2つに分解します。

  1. 空 MOF を最適化 → $E_{mof-empty}$
  2. MOF+H₂O を最適化 → $E_{combo}$
  3. H₂O を抜いて再緩和 → $E_{mof-rerelax}$
  4. H₂O 単体 → $E_{H_2O}$
  5. 差分で $E_{ads}, E_{int}, E_{deform}$ を計算
from ase.io import read
from ase.optimize import BFGS
# 1. 空 MOF
mof = read("WOBHEB_0.11.cif"); mof.calc = calc
BFGS(mof).run(fmax=0.05)
E_mof_empty = mof.get_potential_energy()
# 2. MOF + H₂O
mof_h2o = read("WOBHEB_H2O.cif"); mof_h2o.calc = calc
BFGS(mof_h2o).run(fmax=0.05)
E_combo = mof_h2o.get_potential_energy()
# 3. ゲスト抜き MOF
mof_deformed = mof_h2o[:-3]; mof_deformed.calc = calc
BFGS(mof_deformed).run(fmax=0.05)
E_mof_rerelax = mof_deformed.get_potential_energy()
# 4. 水分子単体
h2o = mof_h2o[-3:]; h2o.calc = calc
E_H2O = h2o.get_potential_energy()
# 5. 吸着エネルギーと寄与分解
E_ref = min(E_mof_empty, E_mof_rerelax)
Eads = E_combo - E_ref - E_H2O
Eint = E_combo - E_mof_rerelax - E_H2O
Edeform = E_mof_rerelax - E_mof_empty
print(f"H₂O@WOBHEB → Eads = {Eads:.2f} eV " f"(Eint = {Eint:.2f}, Edeform = {Edeform:.2f})")

ココがポイント

  • min(E_mof_empty, E_mof_rerelax) を基準に取ることで、最も安定な骨格状態からの吸着を評価できます。
  • BFGS 最適化は fmax=0.05 で十分だと思います。このようにすることで、過剰最適化を防ぎつつ高速化できます。

4.3.2 結果と考察

E_ads = – 0.72 eV, E_int = –0.52 eV, E_deform= – 0.20 eV
  • つまり相互作用寄与が約 70 %, ブリーチング(骨格変形)が約 30 %となります。
  • 示唆:ブリージングによる「おまけ寄与」が大きいほど、湿度変動下でも強固なガス捕集が期待できます。
  • 応用:今回のようにブリージング寄与を定量化することで「相互作用主導型」か「骨格変形主導型」かを分類でき、分離膜設計やサイクル寿命予測といった応用研究に活かすことができます[8]。

最後に


いかがでしたか?本記事で紹介した 機械学習ポテンシャル UMA は、MOF のような大規模系にも適用でき、これまで計算コストの壁で得にくかった知見を短時間で引き出せる強力な手段です。

機械学習ポテンシャルの進化は LLM と同様に非常に速いため、研究で分子動力学シミュレーションや量子化学計算に中ン黙している方は、ぜひこの機会に試してみてください。

参考文献


  1. K. Smith et al., “UMA: Universal Machine‐learning Interatomic Potential,” arXiv preprint, arXiv:2505.08762 (2025). https://arxiv.org/abs/2505.08762
  2. FAIRchem Team, “FAIRChem: FAIR Chemistry Toolkit,” GitHub Repository (2025). https://github.com/facebookresearch/fairchem
  3. Meta FAIR Chemistry, “facebook/UMA,” Hugging Face Model Card (2025). https://huggingface.co/facebook/UMA
  4. B. M. Wood et al., “UMA: A Family of Universal Models for Atoms,” arXiv preprint, arXiv:2506.23971 (2025). https://arxiv.org/abs/2506.23971
  5. S. Kitagawa, R. Kitaura, and S. Noro, “Functional Porous Coordination Polymers,” Angew. Chem. Int. Ed. 43, 2334–2375 (2004). https://doi.org/10.1002/anie.200300610
  6. S. Horike, S. Shimomura, and S. Kitagawa, “Soft porous crystals,” Nature Chem. 1, 695–704 (2009). https://doi.org/10.1038/nchem.444
  7. H. Furukawa, K. E. Cordova, M. O’Keeffe, and O. M. Yaghi, “The chemistry and applications of metal–organic frameworks,” Science 341, 1230444 (2013). https://doi.org/10.1126/science.1230444
  8. J. H. Lee et al., “Design strategies for metal–organic frameworks in direct air capture of CO₂,” Coord. Chem. Rev. 463, 214536 (2022). https://doi.org/10.1016/j.ccr.2022.214536

The post MOF吸着エネルギー計算の新手法:DFT精度を瞬時に再現【機械学習ポテンシャル】 first appeared on LabCode.

]]>
https://labo-code.com/materials-informatics/mof-mlp-uma/feed/06994
Pharmitを使ったファーママコフォア類似検索による新薬候補の発見【In silico創薬】https://labo-code.com/bioinformatics/pharmit/https://labo-code.com/bioinformatics/pharmit/#respondMon, 22 Sep 2025 09:33:12 +0000https://labo-code.com/?p=6988

本記事は、ファーマコフォアを用いて化合物を効率的に探索するツール、Pharmitについての解説です。創薬において、タンパク質の特定の機能(例えば、酵素活性を阻害する、特定の受容体に結合するなど)を誘発する化合物を探索する ...

The post Pharmitを使ったファーママコフォア類似検索による新薬候補の発見【In silico創薬】 first appeared on LabCode.

]]>

本記事は、ファーマコフォアを用いて化合物を効率的に探索するツール、Pharmitについての解説です。創薬において、タンパク質の特定の機能(例えば、酵素活性を阻害する、特定の受容体に結合するなど)を誘発する化合物を探索する際、膨大な数の化合物ライブラリの中から、有望な候補を絞り込む必要があります。ファーマコフォアをうまく使用することで、有望な候補を簡単に絞ることができます。今回は、ファーマコフォアの概念から、その作成、そしてPharmitを用いた検索方法までを解説します。

動作検証済み環境

Mac M1, Sequoia 15.6

ファーマコフォアとは?


ファーマコフォア(Pharmacophore)とは、特定の生体分子と相互作用するために不可欠な、分子の3次元的な特徴の集合体のことです。簡単に言うと、「薬として働くために必要な、化合物の形と化学的性質のパターン」を抽象的に表現したものです。

例として、薬とタンパク質が結合する際に、水素結合の供与体・受容体、疎水性相互作用、正の電荷、負の電荷といった、特定の化学的性質を持つ原子の配置が重要になります。ファーマコフォアは、これらの「重要な特徴」と「特徴間の距離」をモデル化することで、構造が全く異なる化合物であっても、同じファーマコフォアを持つものを効率的に探し出すことを可能にします。

Pharmitとは?


Pharmitは、ファーマコフォアモデルに基づいて、化合物の探索を高速に行うためのツールです。タンパク質の立体構造情報から、リガンドが結合するポケット(結合サイト)の特徴を抽出し、その特徴を満たす化合物をデータベースから見つけ出すことができます。

Pharmitの利用法(ブラウザからの利用)


PharmitはWebサーバーとして公開されているため、環境構築なしでブラウザからすぐに利用できます。これにより、初心者でも手軽にファーマコフォア検索を体験することができます。

Pharmitを使ったファーマコフォア検索の実行


PharmitのWebサイトで、実際にファーマコフォアを作成し、化合物を探索する手順を解説します。

今回は、PDBからダウンロードしたタンパク質–リガンド複合体(例: PDB ID 2OQV、DPP4とその阻害薬)の構造を例に、リガンドの構造を基にファーマコフォアを作成します。

まず、Pharmitのサイトにアクセスします。お好きなタンパク質のPDB ID(例: PDB ID 2OQV)を入れます。その横にはリガンドの名前(ここではMA9があります)

サイト中央のSubmit ボタンをクリックします。

読み込みが完了すると、タンパク質とリガンド(阻害剤)の複合体が表示されます。

スクロールして、タンパク質の全体を見ることもできます。

見えにくいので、受容体表面は見えやすいようにします。Receptor Surface Ppacityの値を小さくしてください。

左側のPharmacophoreの部分から残しておきたいPharmacophoreをONしておきます。これにより、リガンドの化学的特徴が自動的に抽出され、ファーマコフォアの点(feature points)として可視化されます。

  • 水素結合供与体(Hydrogen Bond Donor, HBD)
  • 水素結合受容体(Hydrogen Bond Acceptor, HBA)
  • 疎水性(Hydrophobic)
  • 芳香環(Aromatic) といった特徴点が自動的に認識されます。リガンドの中の緑や紫の丸の部分です。

ファーマコフォアが作成できたら、Search タブに移動します。

Databases では、検索対象となる化合物データベースを選択できます。ここでは、ZINC データベースの購入可能なものを使用します。

Search ZINC Purchasable ボタンをクリックして、検索を開始します。

検索が完了すると、ファーマコフォアに適合する化合物が結果として表示されます。表示された化合物のリストから、それぞれの3D構造を確認し、同じような場所に同じようなファーマこフォアがあることが確認できます。この名前をZINCで検索し、化合物を取得してみてください。

※上記では設定しておいたファーマコフォアの数が多かったので、あまり化合物がヒットしませんでしたが、もう少しファーマコフォアの数を少なくすると、化合物ライブラリも構築可能です。

検索結果のフィルタリング


Pharmitの検索結果には、作成したファーマコフォアに適合した化合物がリストアップされ、それぞれに以下の項目が表示されます。

項目名意味補足
Name化合物の識別子ZINCデータベースにおける化合物のIDです。このIDを使って、ZINCデータベースから化合物の詳細情報を確認できます。
RMSD重ね合わせのずれの度合いを示す値Root-Mean-Square Deviationの略で、ファーマコフォアの点と、化合物の対応する化学的特徴の点の位置的なずれ(ばらつき)を数値化したものです。値が小さいほど、ファーマコフォアモデルと化合物の立体配置がよく一致していることを意味します。
Mass化合物の質量(分子量)化合物の分子量(単位:Da, ダルトン)です。医薬品開発においては、一般的に分子量が500 Da以下であることが望ましいとされています(リピンスキーの法則)。
RBnds回転可能な結合の数Rotatable Bondsの略で、分子内の自由に回転できる結合の数を示します。この数が多いと、分子の柔軟性が高まり、ターゲットタンパク質に結合する際に多くのコンフォメーション(立体配置)を取り得ます。柔軟性が高すぎると、エントロピー的に結合が不利になることがあります。

RMSDについて

RMSDは、検索結果を評価する上で特に重要な指標です。ファーマコフォア検索では、化合物のどの部分がファーマコフォアの各点(水素結合受容体、疎水性部位など)に適合しているかを判断します。RMSDが小さい化合物は、ファーマコフォアの形状と化学的性質を高い精度で満たしているため、より有望な候補であると考えられます。

図の例では、ZINC000000827984 のRMSDが0.461であるのに対し、ZINC00020781551 は0.719であり、前者の方がファーマコフォアとの適合性が高いことが分かります。

また以下のMinimizeからも検索できます。

以下のように出てきます。

項目名意味
Name化合物の識別子。ZINCデータベースのIDです。
Score結合エネルギーの予測値(Autodock Vina)。Pharmitが計算した、化合物とタンパク質の間の結合親和性を示すスコアです。スコアは負の値がより安定な結合を示し、値が小さいほど結合親和性が高い(=強力に結合する)と予測されます。
mRMSDファーマコフォア検索で見つかった化合物の3D構造が、結合ポケット内で最適化された後でも、どれだけ元のファーマコフォアモデルに忠実であるかを示す指標です。

ライブラリ構築の際はScoreが低いもの順やmRMSDが低いもの順で上位何個かを取ってスクリーニングすると良いでしょう。

以下のような論文に使用されているので、ご参考にしてみてください。

In Silico Exploration of Novel EGFR Kinase Mutant-Selective Inhibitors Using a Hybrid Computational Approach

最後に


Pharmitは、ファーマコフォアという概念を視覚的に理解し、実際に探索を体験する上で非常に優れたツールです。環境構築が不要で、初心者でも直感的に操作できるため、in silico創薬の一歩として、ぜひ活用してみてください。

本記事で解説したファーマコフォア検索は、創薬研究の初期段階で非常に重要な役割を果たします。効率的な化合物探索を通じて、新たな医薬品の発見に貢献できることを願っています。

参考文献


Pharmit: interactive exploration of chemical space

GitHub – dkoes/pharmit: Open-source online virtual screening tools for large databases

the BSD 3-clause license and the GNU Public License version 2


The post Pharmitを使ったファーママコフォア類似検索による新薬候補の発見【In silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/pharmit/feed/06988
PRODIGYを用いた環状ペプチド-タンパク質結合エネルギーの予測【In silico創薬】https://labo-code.com/bioinformatics/prodigy/https://labo-code.com/bioinformatics/prodigy/#respondTue, 16 Sep 2025 11:34:49 +0000https://labo-code.com/?p=5176

本記事は、タンパク質複合体におけるタンパク質間相互作用の結合親和性を予測するPRODIGYについての記事です。 今回は前回の記事で作成した環状ペプチドとタンパク質の複合体を例に、相互作用を予測する過程をご紹介します。 自 ...

The post PRODIGYを用いた環状ペプチド-タンパク質結合エネルギーの予測【In silico創薬】 first appeared on LabCode.

]]>

本記事は、タンパク質複合体におけるタンパク質間相互作用の結合親和性を予測するPRODIGYについての記事です。

今回は前回の記事で作成した環状ペプチドとタンパク質の複合体を例に、相互作用を予測する過程をご紹介します。

動作検証済み環境

・ブラウザでの利用
Windows 11, Microsoft Edge バージョン 139.0.3405.86 (公式ビルド) (64 ビット)

・コマンドラインでの利用
Windows 11, WSL2(Ubuntu 20.04), Python3.9(Micromamba 管理),bash(Micromamba 初期化済)

PRODIGYとは?


PRODIGY(PROtein binDIng enerGY prediction)は、タンパク質間相互作用における結合親和性を予測するためのツールです。

タンパク質–タンパク質複合体の立体構造から、その結合親和性(binding affinity)を高精度に予測し、ギブス自由エネルギーや解離定数 Kdとして親和性を計算するツールで、ブラウザからもコマンドラインからも使用することができます。

こちらのツールは、主にタンパク質–タンパク質間相互作用に対応していますが、拡張版としてPRODIGY-LIG(タンパク質と小分子リガンドの場合)や、PRODIGY-CRYSTAL(生物学的インターフェース vs 結晶インターフェースの分類)も提供されています。ですが、今回はタンパク質–タンパク質間相互作用の予測を用いて、タンパク質-環状ペプチドの結合予測について解説していきます。

PRODIGYのアルゴリズム


PRODIGY のアルゴリズムは、タンパク質複合体の立体構造から結合親和性を予測するために、界面接触というものに着目しています。界面接触とは、(それぞれ異なるタンパク質上にある)分子同士の接触のことを言い、この数が多いほど結合強度が強くなると知られています。PRODIGYではこの界面接触の数と質から結合強度を計算しています。

具体的には、まず、残基間で 5.5Å 以内の原子対を「接触」としてカウントし、それを性質ごとに分類します(荷電・極性・疎水性など)。これにより、複合体界面の相互作用の質と量を数値化できます。さらに、相互作用に関与しない残基表面(NIS: Non-Interacting Surface)の特徴も加えることで、単に接触数だけでは捉えられない安定性の要因を補正します。最終的に、これらの特徴量を説明変数とする回帰モデルにより、自由エネルギー変化(ΔG)や解離定数(Kd)を予測します。このアプローチは物理化学的計算より軽量で、かつ大規模データから得られた統計的関係を利用するため、高速かつ精度の高い予測を実現しています。

PRODIGYの利用法(ブラウザからの利用)


PRODIGY はコマンドラインからも利用が可能ですが、 Web サーバーとしても公開されているため、主要なブラウザ(Google Chrome, Firefox, Safari, Microsoft Edge など)からも利用可能です。

ブラウザからの利用は、多くの立体構造を評価するのには向きませんが、とても簡単にPRODIGYを利用できます。(一方、コマンドラインからの利用は一度に多くの立体構造を評価する際に便利です。コマンドラインからの利用法は後半で紹介します。)

環境構築


ブラウザからの利用は特別な環境は不要で、すぐに使用できます。(筆者は Microsoft Edgeで利用。)

注意点があるとすれば、JavaScript を有効にしておく必要があるようです。もしも無効になっている場合は有効化しておきましょう。

PRODIGYを使った環状ペプチド-タンパク質の結合予測の実行


では、実際にPRODIGYを用いて環状ペプチド-タンパク質結合エネルギーの予測を行っていきます。

今回は、以前の記事でAutodock CrankPepで使った環状ペプチドとタンパク質の立体構造ファイル(example1_omm_rescored_out.pdb)を例に行なっていきます。

  1. まずはPRODIGYのサイトへ。
  2. サイト中央の以下の箇所に移動。

  1. 上記で赤枠でmarkしたタブでPRODIGY (protein-protein)を選択していることを確認し、Structure(s)から環状ペプチドとタンパク質の立体構造ファイル(example1_omm_rescored_out.pdb)を選択。
  2. アップロードした PDB/mmCIF ファイルには複数のタンパク質が含まれています。その中から 相互作用を評価したいタンパク質ペアを Interactor 1 と Interactor 2 に指定します。 今回はexample1_omm_rescored_out.pdbの中身に併せて、Interactor 1 にB、 Interactor 2 にZを入力します。 例:もし Chain A と Chain B が結合を予測するなら、Interactor 1 = A、Interactor 2 = B。今回利用したファイルには2つのタンパク質しか含まれませんが、3つ以上のタンパク質が含まれているファイルを選択した場合でも、ここで予測したいペアをしていることが出来ます。
  3. Temperatureでは結合強度を予測するうえで、どの温度条件での結合強度を予測するかを設定できます。今回は25℃を入力しておきます
  4. Job IDにはサーバーに投げるjobの名前を入力でき、Emailにメールアドレスを入力しておくと結果がメールにも転送されます。
  5. 私はロボットではありません。のチェックボックスに入力し、Submit Prodigyをクリック。

実行結果


2~3分ほどで以下のような結果が返ってきます。

今回アップロードしたファイルには受容体タンパク質と環状ペプチドの結合の複合体のモデルが5つ含まれていたので、その5つのモデルそれぞれの結合の強さが計算されました。

  • 表の各列の意味

-Protein-protein complex

解析したファイル名。複数モデル(1〜5)をアップロードしたので、それぞれ行に分かれています。

-ΔG (kcal mol⁻¹)

結合自由エネルギー変化(binding free energy)の予測値。

値が 負(小さいほど強い結合) になるほど、結合親和性が高いことを意味します。

例:-7.9 kcal/mol → 強い相互作用が予測される。

-Kd (M) at °C

平衡解離定数(dissociation constant)の予測値。

単位はモル濃度(M)。

値が 小さいほど強い結合を意味します。

例:1.5e-06 M(マイクロモルオーダー) → 比較的強いタンパク質間結合。

-ICs charged-charged

界面での「荷電残基–荷電残基」の接触数。

-ICs charged-polar

「荷電残基–極性残基」の接触数。

-ICs charged-apolar

「荷電残基–疎水性残基」の接触数。

-ICs polar-polar

「極性残基–極性残基」の接触数。

-ICs polar-apolar

「極性残基–疎水性残基」の接触数。

-ICs apolar-apolar

「疎水性残基–疎水性残基」の接触数。

疎水性相互作用はタンパク質複合体の安定化に重要。

-NIS charged

界面にある荷電残基の割合を示す指標(Normalized Interface Score)。

表のΔGやKdを見てみると、モデル5やモデル4の値が小さく、強い結合であると予測されたようです。逆にモデル1や2の結合はそれよりも弱いと予測されました。

結果の画面の下部から結果をダウンロードすることもできます。

コマンドラインを使った方法


実用的には、一度に大量の立体構造を評価することが多く、その際はコマンドラインを利用してPRODIGYを利用するのが良いでしょう。

先ほどと同様に環状ペプチドとタンパク質の立体構造ファイル(example1_omm_rescored_out.pdb)を例に行なっていきます。

こちらを参考に進めていきます。

環境構築


環境構築をしていきます。今回はWindowsのWSLを利用していきます。WSLの利用方法は前回の記事に記載してあるので、そちらを参考にしてください。

WSLで以下のコードを実行して、環境構築をしていきます。

# micromamba をインストールするディレクトリを作成
mkdir -p ~/micromamba_env
# micromamba をインストール(-b: バッチモード, -p: インストール先指定)
curl -Ls https://micro.mamba.pm/install.sh | bash -s -- -b -p ~/micromamba_env
# bash 設定ファイルを読み込み直す(PATH 設定などを反映)
source ~/.bashrc
# PRODIGY用の環境を作成
micromamba create -n prodigy_env python=3.9 -y
# 作成した環境をアクティベート
micromamba activate prodigy_env
# PRODIGYとその他に必要なパッケージのインストール
micromamba install -n prodigy_env -c conda-forge freesasa freesasa-python -y
pip install --upgrade pip
pip install prodigy-prot biopython

コードの詳細説明

mkdir -p ~/micromamba_env curl -Ls https://micro.mamba.pm/install.sh | bash -s -- -b -p ~/micromamba_env source ~/.bashrc

micromambaを使った環境構築をしていきます。これらはそのmicromambaをインストールするコマンドです。すでにインストールしている場合は、不要です。

micromamba create -n prodigy_env python=3.9 -y

micromambaで「prodigy_env」という名前の仮想環境を作成しています。

  • micromamba create : 新しい環境を作成するコマンド
  • n prodigy_env : 環境の名前を prodigy_env とする
  • python=3.9 : Python 3.9 をインストール(PRODIGYはPython 3.7以上が必要です。)
  • y : ユーザー確認なしで自動的に進める

👉 これで prodigy_env という独立した環境ができ、Python 3.9 が入ります。

micromamba activate prodigy_env

micromambaで作られた「prodigy_env」という名前の仮想環境(パッケージや設定がまとまった作業用スペース)を「有効化(activate)」します。

これを実行すると、その環境の中に入って、その環境にインストールされたツールやライブラリが使える状態になります。

micromamba install -n prodigy_env -c conda-forge freesasa freesasa-python -y

micromambaでBSA計算に必要なパッケージ(freesasa)をインストールします。

  • micromamba install : 環境にパッケージを追加、micromambaでインストールすることで他の環境を汚さずに、指定した環境のみにインストールすることができます。
  • -n prodigy_env : 追加先を prodigy_env に指定
  • -c conda-forge : conda-forge チャンネル(オープンソースのパッケージリポジトリ)から取得

pip install --upgrade pip

インストールに使用する関数pipをアップグレードしておきます。pip install prodigy-prot biopython

pipでPRODIGY本体(prodigy-prot)とそれを動かすのに必要なパッケージ(biopython)をインストール

PRODIGYの実行


前回作成した立体構造ファイル(example1_omm_rescored_out.pdb)を作業したいフォルダにコピーします。(私はdocuments下に作ったPRODIGYというフォルダに入れました)

コピーした後は、以下のコマンドで作業したいフォルダに移動します。/documents/PRODIGYは、ご自身が作業したいフォルダの名前に合わせて変更して下さい。

cd /mnt/c/users/(あなたのWondowsのユーザー名)/documents/PRODIGY

そして以下を実行します。

# ファイルを立体構造モデル1つ1つにバラバラにする
awk ' /^MODEL/ { if (out) close(out); count++; out = sprintf("model_%03d.pdb", count) } { print > out } /^ENDMDL/ { close(out) }
' example1_omm_rescored_out.pdb
# PRODIGY を実行
prodigy model_001.pdb
# いくつかのオプションをつけて実行
prodigy model_001.pdb --distance-cutoff 5 --acc-threshold 20 --temperature 25 --contact_list --pymol_selection --selection B Z

コードの詳細説明

awk ' /^MODEL/ { if (out) close(out); count++; out = sprintf("model_%03d.pdb", count) } { print > out } /^ENDMDL/ { close(out) } ' example1_omm_rescored_out.pdb

example1_omm_rescored_out.pdbのファイルには複数の立体構造モデルが含まれていますが、コマンドからPRODIGYを利用する場合、モデルを1つずつ与える必要があります。このコマンドでファイルをモデルごとに分割しておきます。

prodigy model_001.pdb

こちらのコマンドで指定のファイル(model_001.pdb )の結合親和性を予測できます。PDB形式以外にもmmFIC形式でも実行できます。また、

prodigy <directory_with_molecules>

この様にファイル名だけでなく、ディレクトリ名を指定することでディレクトリ内の全てのファイルに対して解析をすることができます。

prodigy model_001.pdb --distance-cutoff 5 --acc-threshold 20 --temperature 25 --contact_list --pymol_selection --selection B Z

また、コマンドラインから使用すると、この様にオプションを利用してより詳細な解析ができます。

利用可能なオプションの説明は以下の通りです:

  • -distance-cutoff DISTANCE_CUTOFF相互作用をカウントする際の距離カットオフを指定。
  • -acc-threshold ACC_THRESHOLDBSA(Buried Surface Area)解析の際のアクセスしやすさの閾値設定。
  • -temperature TEMPERATURE解離定数(Kd)予測時に使用する温度(℃)を指定。
  • -contact_listインターモレキュラー接触のリストを出力。
  • -pymol_selectionPyMOL 用の選択・ハイライトスクリプトを出力。
  • -q, --quiet出力を結合親和性値のみ等の簡素な形に抑える。prodigy -q input_dir/こちらのコマンドのように複数のファイルを一括で処理する際に利用すると便利です。
  • -selection A B [A,B C ...]特定のチェーン間でのみ接触計算したい場合に使用。 コロンで区切られた複数チェーンのグループとして扱えます。
    • -selection A B → チェーン A と B の間のみ
    • -selection A,B C → A と C、B と C の接触計算
    • -selection A B C → A–B、B–C、A–C すべて計算

実行結果


prodigy model_001.pdb

こちらを実行させたところ、以下のような結果になりました。

(prodigy_env) ~~~~ $ prodigy model_001.pdb
[+] Parsed structure file model_001 (2 chains, 143 residues)
[+] No. of intermolecular contacts: 39
[+] No. of charged-charged contacts: 4.0
[+] No. of charged-polar contacts: 4.0
[+] No. of charged-apolar contacts: 14.0
[+] No. of polar-polar contacts: 1.0
[+] No. of apolar-polar contacts: 4.0
[+] No. of apolar-apolar contacts: 12.0
[+] Percentage of apolar NIS residues: 36.52
[+] Percentage of charged NIS residues: 33.91
[++] Predicted binding affinity (kcal.mol-1): -6.9
[++] Predicted dissociation constant (M) at 25.0˚C: 8.3e-06

ブラウザ版のmodel1と同じ結果が得られました。

最後に


いかかでしたでしょうか。

PRODIGYはwebから使えることもあり、簡単に使用することが出来ました!

前回の記事では結合力とドッキングポーズを評価しましたが、今回はそれをもとにもうちょっときちんとした評価指標ΔGとKdで立体構造を評価していきました。

実際には、こちらの論文https://chemrxiv.org/engage/chemrxiv/article-details/63c7a4da23c13b2e4813aa5bのように両方を相互的にみて最終的な判断をすることが多いようです。

参考文献


GitHub – haddocking/prodigy: Predict the binding affinity of protein-protein complexes from structural data

Apache License v2.0

PRODIGY: a web server for predicting the binding affinity of protein–protein complexes

The post PRODIGYを用いた環状ペプチド-タンパク質結合エネルギーの予測【In silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/prodigy/feed/05176
【AstroImageJ】AstroImageJでのトランジット観測【天文解析】https://labo-code.com/imagej/astroimagej-transit/https://labo-code.com/imagej/astroimagej-transit/#respondThu, 04 Sep 2025 00:13:31 +0000https://labo-code.com/?p=6884

ImageJを使った画像解析入門の技術書を販売中! 初心者でも始められるわかりやすい解説画像処理や統計解析をImageJで手軽にやってみよう 技術書ページへ ImageJを使った画像解析入門の技術書を販売中! 初心者でも ...

The post 【AstroImageJ】AstroImageJでのトランジット観測【天文解析】 first appeared on LabCode.

]]>

今回の記事では天文画像解析ソフトのAstroImageJ(AIJ)を用いた、トランジット法を用いた太陽系外惑星(WASP-12b)の観測を紹介します。

太陽系外惑星を探す際に用いられるトランジット観測ですが、AstroImageJを用いることで、直感的に解析を行うことができます。

動作検証済み環境
macOS Sequoia(15.5), ImageJ 1.54m1, AstroImageJ 5.5.1.00

トランジット法とは


惑星が恒星の前面を通過(トランジット)すると、その間だけ恒星の見かけの明るさがわずかに減少します。時間に対する明るさの記録が光度曲線(light curve)です。下図のように、トランジットが起きるたびに光度曲線にはU字型のディップ(谷)が現れ、その深さ幅(継続時間)から惑星系の多くの情報が読み取れます。

トランジットの深さは、近似的に惑星と恒星の見かけの面積比に等しく、

$$ \Delta L / L \approx (R_p/R_*)^2 $$

で表されます(周辺減光や他天体光の混入が小さい場合)。$R_p$は惑星半径、$R_*$は恒星半径。例えば、恒星が太陽サイズ、惑星が木星サイズなら減光は約1%です。

一方で、地上観測では、大気の揺らぎや薄雲などの影響で単独の星の明るさは刻々と変化します。そのため、解析をする場合は比較星を用いた相対測光(差分測光)を行い、外的要因を打ち消します。実際には、同一視野内で明るさが安定し、できれば色がターゲットに近い星を1つ以上選び、ターゲット星(今回は WASP‑12)のフラックスを比較星のフラックスで割った相対フラックスを求めます。比較星も同じ大気条件下にあるため、比をとることで大気による共通の減光が相殺され、ターゲット固有の変動(ここでは惑星通過による減光)が際立ちます。

さらに複数の比較星を用いて合計(あるいは重み付き平均)フラックスとターゲットの比をとるアンサンブル測光により、光度曲線の安定性と精度が向上します。つまり、”一つの星だけだと大気に振られるが、周囲の星と一緒に比べれば本当に暗くなったかが分かる”という発想です。

今回は、AIJを利用してトランジット観測による光度曲線を解析する方法を紹介します。

AIJの前準備


必要な画像データのダウンロード

次にサンプル用のデータをダウンロードします。先ほどブラウザで開いたAstroImageJのサイトから下記の「Example data for User Guide Chapter 10 tutorial (4.5 GB tar.gz or zip file)」をクリックします。

下記の画面に遷移するので、必要なファイルをダウンロードします。

今回はキャリブレーション済みの画像を使用します。どちらか一方を取得してください。

  • WASP-12b_example_calibrated_images.tar.gz
  • WASP-12b_example_calibrated_images.zip

ダウンロードしたファイルを解凍し、作業用に WASP-12b というフォルダを用意して、展開された FITS をすべて入れておきます。

AIJでのWASP-12bの観測画像を読み込み

まずAIJを起動し、File -> Import -> Image Sequence を選びます。

すると次のようなImport Image Sequenceが起動するので、先ほど作成したWASP-12bフォルダを選択します。

フォルダ設定が完了したら、他の設定値は触らずに、右下のOKをクリックします。

フォルダ内の FITS ファイル名の数値順に取り込まれ、下図のように連番スタックとして表示されます。

表示されたスタックを対象に、ターゲット星と比較星を配置 → Multi‑Aperture で測光 → Multi‑Plot でライトカーブを作成、という順で進めます。

AIJでのトランジット法による観測


測光アパーチャの設定

今回はキャリブレーション済みの画像データを用いるため、さっそく解析に進みます。

AIJツールバーの二重円アイコンをクリックしてアパーチャ設定を開きます。

Multi-Aperture Measurementsウィンドウが開くので、まずは仮の値として設定値は触らずに、Place Apertures をクリックします。

画像ウィンドウに戻ったら、下図の位置にあるターゲットの WASP‑12 をクリックします。

Seeing Profile ウィンドウが開き、上部に例として FWHM: 12.30 pixels と表示されます。FWHM(Full Width at Half Maximum=半値全幅)は、今回の例では星像(PSF)の広がりを表す指標で、以後の半径設定の基準になります。

つづいて Multi‑Aperture Measurements に戻り、以下の目安で半径を設定します。値は厳密でなくて構いませんが、星像を十分に覆いつつ、不要な空背景をできるだけ含まないことが大切です。

  • Fixed/Base radius of photometric aperture約 1.5 × FWHM

    例)FWHM ≃ 12.3 px → 18 px 前後

  • Fixed/Base radius of inner background annulus約 3 × FWHM

    例)36 px 前後

  • Fixed/Base radius of outer background annulus内側半径 + (1~2) × FWHM を目安

    例)50~60 px 前後(周囲に星が少なく余裕がある場合は ~70 px 程度まで広げても可)

背景環に他の星が入ると測定が不安定になります。混入がある場合は半径を調整するか、後述の星除去オプションを有効にしてください。

あわせて、設定画面で次のオプションが有効になっていることを確認します。

  • Centroid apertures:各フレームで星位置を再計算して、アパーチャを自動追従させる。
  • Remove stars from background:背景環に入った星を自動検出して除去する。

これらを有効にしておけば、多少の追尾ズレがあっても毎フレームで再センタリングでき、背景測定の邪魔になる星の影響も低減できます。設定が整ったら Place Apertures を押して配置に進みます。

ターゲット星と比較星の選定・配置

画像ウィンドウ上でカーソルが赤い十字に変わったら、まずターゲット(WASP‑12)をクリックします。選択した星に円形アパーチャが描かれ、通常はT1のラベルが付きます。

選択された星に緑の円形アパーチャが描画され、ラベル「T1」が付きます。また、自動的に赤色のアパーチャが描画され、「C1」「C2」…とラベルが配置されていると思います。これは先ほど設定したパラメータに基づき、比較星が自動的に選定されたことを意味します。

比較星は自分で選択することもでき、その場合はターゲットと明るさが近いものを選びます。

配置が済んだら、画像ウィンドウで Enter キー を押します。スタック全フレームに対して差分測光が一括実行され、いくつかのウィンドウが開きます。

測定結果は 下図のPlot of Measurements などに表示され、相対光度(例:rel_flux_T1)の時系列が描画されます。

トランジットモデルのフィット

次に、トランジット曲線をフィットして物理量を推定します。

  1. Multi-plot Y-dataウィンドウを開き、Y-data タブで Data Set 1Y列に相対光度(例:rel_flux_T1)を指定します。

  2. 同じ行の Fit ModeTransit に変更します。

  3. 自動的に Data Set 1 Fit Settings が開きます。ここで

    • Enable Transit Fit にチェック

    • Auto Update Priors にチェック(今回は自動設定で進める)

      必要に応じて分散や外れ値処理、デトレンド項(airmass, FWHM, sky など)も指定します。

  4. Plot of Measurements上に近似曲線が引かれます。

補足:モデルと時刻がずれる場合は、タイムスタンプの列(例:BJD_TDB / JD_UTC)やタイムゾーン設定、時刻原点を確認してください。比較星の選び直し(色や混入の見直し)やアパーチャ・背景環の再調整で、残差が改善することもよくあります。

トランジット曲線から惑星半径を求める

先ほどのフィッティングをしたグラフから$(R_p/R_*)^2=0.0114$と表示されています。

これを平方根すれば半径比が得られます。

$$ k=\sqrt{0.0114} \approx 0.1068 $$

恒星のWASP-12の半径$R_*$は約$1.657R_\odot$(Wikipedia)であるため、惑星であるWASP-12bの半径$R_p$は、

$$ R_p=0.1068\times1.657R_\odot \approx 0.177R_\odot $$

木星半径へ換算($1 R_J\approx0.103 R_\odot$)すると、

$$ R_p= \frac{0.177}{0.103}R_\odot\approx1.72R_J $$

つまり今回の惑星のWASP-12bは、木星の約1.72倍程度の半径を持つと推定されます。

最後に


本記事では AstroImageJ を例に、データ読み込みから相対測光・トランジットフィット、半径推定までを一気にたどりました。AIJ は GUI 操作に加えてマクロ/スクリプト自動化にも対応しており、同じ手順をテンプレート化すれば繰り返しの解析と処理速度を両立できます。観測ごとに比較星やデトレンド項などの解析パラメータを調整しつつ、データ解析を進めてみましょう。


The post 【AstroImageJ】AstroImageJでのトランジット観測【天文解析】 first appeared on LabCode.

]]>
https://labo-code.com/imagej/astroimagej-transit/feed/06884
【AstroImageJ】天文観測にImageJを利用する【天文観測】https://labo-code.com/imagej/astroimagej-abst/https://labo-code.com/imagej/astroimagej-abst/#respondTue, 02 Sep 2025 21:55:35 +0000https://labo-code.com/?p=6846

フリー画像解析ソフトのImageJには天文学用途にカスタマイズされたAstroImageJがあります。特に天文観測で撮影された画像データの解析に使用できます。本記事ではAstroImageJのインストールから機能の紹介を ...

The post 【AstroImageJ】天文観測にImageJを利用する【天文観測】 first appeared on LabCode.

]]>

フリー画像解析ソフトのImageJには天文学用途にカスタマイズされたAstroImageJがあります。特に天文観測で撮影された画像データの解析に使用できます。本記事ではAstroImageJのインストールから機能の紹介を行います。

通常のImageJについてはこちらの記事を参照してください。

動作検証済み環境

macOS Sequoia(15.5), ImageJ 1.54m1, AstroImageJ 5.5.1.00

AstroImageJとは?

AstroImageJ(AIJ)は、天体画像の処理・解析に特化した無償のソフトウェアです。生命科学・医学分野で広く使われている画像解析ソフト ImageJ を基盤に、天文学向けの機能を追加した派生版です。


AstroImageJの主な用途

AIJが特に力を発揮するのは、次のような研究・観測分野です。

小惑星や彗星の測光: 小惑星の自転に伴う明るさの変化から自転周期を求めたり、彗星の活動度の変化を追跡するなどの解析に利用できます。

系外惑星のトランジット観測: 系外惑星が主星の手前を横切る(トランジット)際の、わずかな減光を捉えて光度曲線(ライトカーブ)を作成します。そこから惑星の存在や半径、公転周期などを推定できます。アマチュアによる発見・追観測にも広く用いられています。

変光星の観測: 周期的または不規則に明るさが変化する変光星の光度変化を記録・解析します。周期や振幅の測定を通じて、恒星の物理的性質の解明に役立ちます。

主な機能

AIJは、観測で得られた生データ(FITS など)から、科学的に有用な光度曲線を得るまでのワークフローを、ほぼ一つの環境で完結できます。

  • データ較正(キャリブレーション) ダーク、バイアス、フラットといった必須の前処理を効率的に実行できます。
  • 画像の位置合わせ(アライメント/レジストレーション) 長時間観測で得た多数のフレームを、星像の位置を基準に精密にそろえます。
  • 開口測光(Aperture Photometry) 対象星と比較星を指定するだけで自動測光を行い、大気や透明度の変動を補正した相対光度(差分等級)を算出します。
  • 光度曲線の作成と解析 測光結果をリアルタイムでプロットし、横軸に時刻、縦軸に等級や相対フラックスを設定できます。トランジットモデルのフィッティングなど、解析機能も備えています。
  • WCS情報の付与(プレートソルビング) 画像内の星の配置から、天球上の座標(赤経・赤緯)を自動特定し、FITSヘッダにWCS(World Coordinate System)として書き込めます。

AstroImageJの強み

  • オールインワン:前処理から測光・解析まで一貫して行えるため、複数ツールを切り替える手間を減らせます。
  • 無償で利用可能: 研究者、学生、アマチュア天文家など、誰でも無料で利用できます。
  • クロスプラットフォーム:Javaベースのため、Windows/macOS/Linuxで動作します。
  • 直感的なGUI:コマンドラインではなく、分かりやすいグラフィカル操作で作業できます。

AstroImageJ(AIJ)のインストール方法

下記のリンクをクリックしてAstroImageJのトップページにアクセスします。 https://www.astro.louisville.edu/software/astroimagej/

下記のトップページが開くので、下にスクロールしていきます。

ページの下の方にある「Download an installation package of AstroImageJ」をクリックします。

次のページに遷移するので、お使いのOSにあったものをクリックしてダウンロードします。

AppleSiliconのMacをお使いの方は末尾がmac-arm_64Bit.dmgファイルをダウンロードするように注意してください。

ダウンロードしたファイルの案内に従ってインストールすれば完了です。

インストール後、下記のアイコンのアプリをクリックしてAstroImageJを起動します。

ImageJとの違い

AstroImageJを起動したら下記のようなウィンドウが立ち上がります。

次のImageJと比較するとツールバーの右に色々なツールが追加されているかと思います。

これらのAIJに追加された機能の中で、特に解析に用いる左の5つのアイコンについて紹介していきます。

Aperture Photometry Tool

ツールバー右側の 「円が1つ」 のアイコン(Aperture Photometry Tool)をクリックします。

Aperture Photometry Settings ウィンドウが開きます。

このウィンドウでは、AIJ の開口測光に関わる “測光アルゴリズムの挙動” を一括設定します。主に次の4カテゴリを扱います。

  1. アパーチャ形状の定義
  2. 背景(空)推定の方法
  3. 測定時の演算オプション
  4. 誤差計算・品質チェック用パラメータ

ウィンドウ内の冒頭の3つの項目はアパーチャ形状の定義設定に関係します。

  • Radius of object aperture:星像のフラックスを積分する円半径 (px)
  • Inner / Outer radius of background annulus:星を囲む背景リングの内外半径(px)

設定後、画像ウィンドウに戻ると、マウスカーソルが3本の同心円(青)に変わります。これがアパーチャ(内側の円)と背景リング(外側2本)の大きさを表し、測光と背景推定に使うピクセル範囲が決まります。

Multi-Aperture Measurements

隣の 「円が2つ」 のアイコンをクリックすると、Multi-Aperture Measurements の設定画面が開きます。

この画面では、同一画像または画像スタックに複数のアパーチャを配置し、ターゲット(T1 = Target 1)と比較星(comp stars)の選定・配置・追尾・演算方法を指定します。通常は、ターゲットと同一フレーム内の複数の比較星を同様に測光し、ターゲット/比較星の比(相対フラックス)や差分等級をとることで、大気揺らぎ・透明度変動などの共通成分を相殺します。

1. Aperture Geometry(アパーチャ形状・基本半径)

項目意味実務上のポイント
Aperture Shapeアパーチャ形状(円形/矩形など)。PSF(点像拡散関数)に合わせる通常は Circular(円形) を使用
Fixed/Base radius of photometric / inner / outer background annulusそれぞれ:星フラックス積分半径、背景リング内半径/外半径目安:オブジェクト半径 = FWHM の約 1.3–2×背景リング = 内側 2×FWHM/外側 4×FWHM。可変半径モードでも“基準値”として参照

2. Aperture Size Strategy(半径の固定・自動・可変)

ラジオボタン概要使いどころ
Fixed Apertures as selected above全フレームで同じ半径を適用シーイング変動が小さく S/N の高いデータ
Auto Fixed Apertures from first image T1 radial profile1枚目の T1 の累積光量プロファイルから“指定閾値に達する半径”を決め、全フレームで固定開始直後だけピント調整したい場合
Auto Fixed Apertures from multi‑image T1 radial profile複数枚の平均プロファイルで同様に半径を決定1枚目が特異なピンボケ/シーイングだったときの保険
Auto Variable Apertures from each image T1 radial profile各フレームごとにプロファイル解析して半径を再計算フォーカスドリフトやシーイング変化が大きい夜
Auto Variable Apertures from each image T1 FWHM + FWHM factor各フレームの FWHM を計測し、半径 = FWHM × 係数 とする経験則として 1.3–1.4× が汎用的に良好

Normalized flux cutoff threshold 欄は“累積光量が○%に達した地点”を半径とする場合の閾値(0.01 = 1 %)。可変半径モードで FWHM factor を 0 にするとこちらが有効化。

3. Placement Policy(どの画像にどのアパーチャを置くか)

オプション動作シーン
Place all new aperturesすべてのフレームで新規に自動配置完全自動の一括処理
Place first previously used aperture / Place N previously used apertures直前実行で使ったアパーチャ座標を再利用同一夜の再処理・設定の使い回し
Use RA/Dec to locate aperture positionsWCS 付き画像に対し .radec(RA/Dec 一覧)で自動配置AAVSO などから比較星座標を事前リスト化した場合
T1 is moving objectターゲットのみ追尾して比較星は静止配置移動天体測光(小惑星・彗星)
Use single step mode各フレームを手動で送りつつワンクリック配置自動追尾が難しい悪条件データ

4. Auto Comparison Stars(比較星の自動選定)

項目概要調整パラメータ
Auto comparison starsターゲット周辺で、輝度が近く重ならない星を自動検出Enable log(ログ保存)、Show peaks(候補を画像にオーバーレイ)で検証
Smoothing Filter Radius何 px でガウス平滑してピーク同定するか広視野・星が疎なら 3–5 px 目安
Auto Thresholds下段の Max/Min Peak Value をヒストグラムから自動設定極端に明暗が混在する場合のみ手動調整
Max/Min Peak Value / Brightness %ピーク強度/総光量で候補をふるい分け例:Max Comp Brightness % = 150 → ターゲットの 1.5倍より明るい星を除外
Weight of Distance (slider)0 = 距離優先 / 100 = 輝度優先 の重み付け小視野で輝度が揃うなら距離を 30–50% 程度
Max. Comp. Stars自動採用する比較星の上限数通常 10–15 が実用的

5. Centroid & Background Handling(重心合わせ・背景処理)

チェックボックス内容効果
Centroid aperturesクリック位置からサブピクセル精度で星中心を再計算ガイドずれの吸収に有効
Halt processing on WCS or centroid error星検出や WCS 失敗時に処理を停止長時間バッチの安全弁
Remove stars from background背景リング内の他星をσクリッピングで除去混雑フィールドでの背景過大見積もりを防止
Assume background is a plane背景を一次平面(傾きあり)で近似広視野や月明かり勾配の補正に有効

6. Runtime & UI Aids(実行時の補助)

オプション目的
Prompt to enter ref star apparent magnitude比較星の視等級を入力して、光度曲線を等級スケールで出力
Update plot while running / Update image display while running測定表・ライトカーブをリアルタイム更新
Show help panel during aperture selectionアパーチャ配置中に操作ヒントを表示(初心者向け)

7. 実行ボタン

  • Aperture Settings:アパーチャ半径・誤差設定パネルへ戻るショートカット
  • Place Apertures:ダイアログを閉じて画像上で配置ステップへ移行
  • Cancel / OK:設定を破棄/確定して測光を開始

Clear Overlay Tool

箒アイコンの Clear Overlay は、画像オーバーレイ上のアパーチャ/ラベル/注釈を一括消去します。測定データ(Measurements table)は消えません。

MultiPlot Tool

4番目のMulti-Plot アイコンをクリックすると、測光結果などを多系列でグラフ化できるウィンドウが開きます。グラフのタイトル軸ラベル縮尺凡例、そしてプロットサイズまで一通り設定できます。

クリックすると下記のMulti-plot MainMulti-plot Y-dataウィンドウが開き、グラフの設定ができます。

Measurements table が AIJ で開かれているか、読み込まれている必要があります(下の Read Measurements Table 参照)。テーブルがあれば、直近の設定を用いて自動でプロットを生成します。プロット設定はテンプレートとして保存・再利用可能です。

Read MeasurementTable Tool

5番目のアイコンは、保存済みの Measurements.tbl などの測定テーブルを読み込みます。タブ/カンマ/スペース区切りのテーブルに対応し、読み込んだテーブルは Multi-Plot でそのまま利用できます。

CCD Data Processor Tool, Coordinate Converter Tool

6番目のDPアイコン のCCD Data Processor Toolと、その隣のCoordinate Converter Toolは前処理と一括処理のハブです。主な役割は次のとおり。

CCD Data Processor(DP) は、観測画像の前処理(キャリブレーション)から測光・可視化の自動実行までを一括で支援する AstroImageJ の中核モジュールです。バイアス/ダーク/フラットのマスター生成と適用CCD非線形補正FITS ヘッダー更新オンライン plate solve による WCS 付与、そして各フレームの校正完了後に Multi‑Aperture(多重測光)や Multi‑Plot(多曲線プロット)を自動起動する運用までをまとめて扱えます。DP は後処理モード(Polling Interval=0)でも、撮像中に逐次取り込んで処理するリアルタイムモード(Polling Interval を非ゼロ、例:5 s)でも動作します。

Coordinate Converter は、天体名(SIMBAD 連携)や座標・観測所位置の入力で、J2000/B1950 の赤道座標、黄道座標、銀河座標など各種系への変換と、UTC/ローカル時刻/恒星時(LST)/JD/HJD/BJDといった時刻系の相互変換を行うツールです。さらに、月や主要惑星との位相・近接状況の概略や、SKY‑MAPを使った天域画像の参照も可能で、観測計画立案や結果の整合チェックに広く使われます。

最後に

本記事では AstroImageJのインストールから各種設定パラメータを駆け足で紹介しました。

ImageJと同じようにスクリプトによる操作も可能ですので、GUI の直感性とスクリプトの再現性を組み合わせることで、直感的に観測データ解析を行うことができ、解析へのボトルネックが大幅に削減できます。

参考文献

  • AstroImageJ 2.4.1 User Guide p.33–35
  • AIJ Differential Photometry Tutorial (BAA)(britastro.org)

The post 【AstroImageJ】天文観測にImageJを利用する【天文観測】 first appeared on LabCode.

]]>
https://labo-code.com/imagej/astroimagej-abst/feed/06846
【タンパク質準備】OpenMMを使ったタンパク質のエネルギー最小化とPymolを使ったGrid boxの決定方法【In silico創薬】https://labo-code.com/bioinformatics/openmm-gridbox/https://labo-code.com/bioinformatics/openmm-gridbox/#respondSat, 09 Aug 2025 08:45:55 +0000https://labo-code.com/?p=6691

本記事はin silico screeningにおけるタンパク質準備について書かれた記事です。OpenMMを使って、タンパク質のエネルギー最小化とオープンソース版のPymolを使ったgrid boxの作成方法を記載してい ...

The post 【タンパク質準備】OpenMMを使ったタンパク質のエネルギー最小化とPymolを使ったGrid boxの決定方法【In silico創薬】 first appeared on LabCode.

]]>

本記事はin silico screeningにおけるタンパク質準備について書かれた記事です。OpenMMを使って、タンパク質のエネルギー最小化とオープンソース版のPymolを使ったgrid boxの作成方法を記載しています。企業の方でも使える内容ですので、ぜひご覧ください!

動作検証済み環境

Mac M1, Sequoia 15.3

OpenMMとは


OpenMM(オープンエムエム)は、Python や C++ から呼び出せる GPU対応の分子動力学(MD)シミュレーション・ライブラリです。CUDA または OpenCL を活用でき、数万原子規模の系でも実用的な速度でカスタム計算を行えます。

主な特長:

  • Python API を介して、ForceFieldSimulation、カスタム積分器などを柔軟に組み立て可能です。。
  • GPU 有効化 により、CUDA/OpenCL ベースの高速化が進んでおり、複数GPUでの並列実行もサポートされます。
  • 構造最適化(minimize) やサンプリング、自由エネルギー計算などの基本機能を備えています。

ライセンスは、API や CPU リファレンス部分が MIT ライセンス(商用・改変可)で公開されており、CUDA/OpenCL プラットフォーム部分は LGPL ライセンス です。

総じて、OpenMM は、柔軟なカスタマイズ性とGPUによる高性能を両立し、研究用途から創薬シミュレーションまで幅広く利用できる強力なMDツールキットです。

ここではOpenMMを使って、エネルギーを最小化してみましょう!

過去記事ではGROMACSでもエネルギー最小化をしましたが、OpenMMの方がシンプルにエネルギーを最小化できます。

環境構築


可視化ツールであるPymol(オープンソース版)と共に、OpenMMの環境構築をしましょう!

conda create -n protein_preparation python=3.10 -y
conda activate protein_preparation
conda install -c conda-forge pymol-open-source
conda install -c conda-forge openmm
pymol

詳細コード解説

仮想環境の作成と起動

conda create -n protein_preparation python=3.10 -y
  • 仮想環境 protein_preparation をPython 3.10で作成
  • y:確認なしで自動的にインストールを進める
conda activate protein_preparation
  • 作成した仮想環境を有効化
  • これ以降の操作はこの環境内で行われます

PyMOL オープンソース版のインストール

conda install -c conda-forge pymol-open-source
  • conda-forge チャンネルからPyMOLオープンソース版をインストール
  • 商用ライセンス不要で、拡張機能やスクリプト利用も可

注意点:

  • Schrödinger版とは異なり、GUIの見た目や機能が少しシンプルです
  • Macでは起動時にXQuartz(X11)が必要になることがあります

OpenMMのインストール

conda install -c conda-forge openmm
  • 分子力学シミュレーションエンジン OpenMM をインストール
  • Pythonから呼び出してエネルギー最小化やMDを行うことができます

PyMOLの起動

pymol
  • PyMOLを起動します(GUIが立ち上がります)
  • PyMOLの下部ターミナルでPythonコードやスクリプトを実行できます

Pymolを使ったタンパク質の準備


まずPymolが開かれると、以下の画面になっていると思います。左上のFIleからタンパク質をロードしてください。

まずは水分子を消しましょう。

次に余分なイオンとリガンドを消していきます。

上タブのDisplay→Sequenceを押して、配列を出しましょう。

イオンとリガンドを選択し、右側のremove atomsから消してください。

左上のFile→Export Moleculesを押し、5buf_no_water_ligand.pdb として保存してください。

OpenMMを使ったエネルギー最小化


続いて、OpenMMを使って、エネルギーを最小化していきます・

全コードはこちら

from openmm.app import *
from openmm import *
from openmm.unit import *
from sys import stdout
# 1. PDB読み込み
pdb = PDBFile('/path/to/5buf_no_water_ligand.pdb')
# 2. ForceField定義
forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
# 3. Modellerを使って水素原子を追加
modeller = Modeller(pdb.topology, pdb.positions)
modeller.addHydrogens(forcefield)
# 4. システム構築
system = forcefield.createSystem( modeller.topology, nonbondedMethod=PME, nonbondedCutoff=1*nanometer, constraints=HBonds
)
# 5. 積分器の定義
integrator = LangevinIntegrator(300*kelvin, 1/picosecond, 0.002*picoseconds)
# 6. シミュレーション準備
simulation = Simulation(modeller.topology, system, integrator)
# 7. 位置を設定
simulation.context.setPositions(modeller.positions)
# 8. エネルギー最小化を実行
print("エネルギー最小化を実行中...")
simulation.minimizeEnergy()
# もっとしたい場合はこちら
#simulation.minimizeEnergy(
# tolerance=10 * kilojoule_per_mole / nanometer,
# maxIterations=1000
#)
print("エネルギー最小化完了!")
# 9. 最小化後の構造を取得
positions = simulation.context.getState(getPositions=True).getPositions()
# 10. PDBファイルに出力
with open('minimized.pdb', 'w') as output_file: PDBFile.writeFile(modeller.topology, positions, output_file)
print("最小化された構造を 'minimized.pdb' に保存しました。")

詳細コード


必要なモジュールのインポート

from openmm.app import *
from openmm import *
from openmm.unit import *
from sys import stdout
  • openmm.app:構造データの読み込み・操作、シミュレーション設定に使います。
  • openmm:シミュレーションエンジンそのものです。
  • openmm.unit:温度や長さなどに単位(K, nmなど)を付けるために使います。
  • sys.stdout:ログやメッセージの表示先に使うこともあります(今回は未使用でもOK)。

PDBファイルの読み込み

pdb = PDBFile('/path/to/5buf_no_water_ligand.pdb')
  • PDBFileで構造ファイル(.pdb)を読み込みます。
  • ここでは水やリガンドが除かれたPDBを使用。

ForceFieldの定義

forcefield = ForceField('amber99sb.xml', 'tip3p.xml')
  • amber99sb.xml:タンパク質に使われる力場。
  • tip3p.xml:水分子に対する力場(今回はまだ水は加えていませんが、後で使う可能性あり)。

Modellerを使って水素原子を追加

modeller = Modeller(pdb.topology, pdb.positions)
modeller.addHydrogens(forcefield)
  • PDB構造には通常水素が含まれていないため、自動で水素を追加します。
  • Modellerオブジェクトで、構造の修正を行えます。

システムの構築

system = forcefield.createSystem( modeller.topology, nonbondedMethod=PME, nonbondedCutoff=1*nanometer, constraints=HBonds
)
  • 力場とトポロジー情報から力の計算モデル(System)を生成。
  • PME:長距離の電荷相互作用を正確に扱う方法。
  • HBonds:水素結合のみを固定(計算の高速化と安定化)。

積分器(Integrator)の設定

integrator = LangevinIntegrator(300*kelvin, 1/picosecond, 0.002*picoseconds)
  • 温度を制御しながら時間発展を行うLangevin Dynamicsを使用。
  • 300Kで、1/ps の摩擦係数、2 fs のタイムステップ。

Simulationオブジェクトの作成

simulation = Simulation(modeller.topology, system, integrator)
  • 上記で作成したトポロジー・力場・積分器を使って、シミュレーション本体を準備。

初期構造の設定

simulation.context.setPositions(modeller.positions)
  • 初期の原子座標をシミュレーションに反映させます。

エネルギー最小化を実行

print("エネルギー最小化を実行中...")
simulation.minimizeEnergy()
#もっと厳密にエネルギー最小化をしたい場合はこちら
#simulation.minimizeEnergy(
# tolerance=10 * kilojoule_per_mole / nanometer,
# maxIterations=1000
#)
print("エネルギー最小化完了!")
  • 原子間の衝突や不自然な構造を修正(エネルギー最小化)します。
  • 最小化によって、より現実的な構造へと近づけます。

パラメータを調整することで、さらに厳密にエネルギー最小化を行えます。

maxIterations の値を変更してみてください。


最小化後の構造を取得

positions = simulation.context.getState(getPositions=True).getPositions()
  • 最小化された座標を取得します。
  • この座標を使って新しいPDBファイルを書き出せます。

最小化構造のPDBファイル出力

with open('minimized.pdb', 'w') as output_file: PDBFile.writeFile(modeller.topology, positions, output_file)
print("最小化された構造を 'minimized.pdb' に保存しました。")
  • writeFile() でPDB形式として保存します。
  • これにより、水素付き&最小化済みの構造が minimized.pdb に出力されます

PymolでのGridBoxの作り方


ketanne さんが記事にまとめてくれていました。この通りにGridBoxを作ります。

PyMOLでDocking Simulationできるのか -gridboxを作る編-

今回はわかりやすいようにDPP4(PDB: 5YP2)を用いて、すでに結合しているinhibitor周辺のGrid boxを見ていきます。

左上にあるFile→Get PDB File→PDB IDに5YP2を入れて、Downloadを押してください。

その後、上タブのDisplay→Sequenceを押して、配列を出し、水分子を消してください。

次にリガンドを一つのみ(今回は8YC)残し、残りは消してください。

以下のPythonのスクリプトをgrid.py として、保存してください。

grid.py

from pymol import cmd
from pymol.cgo import *
import itertools
from random import randint
def search_space(selection="enabled and organic", padding=4.0): ([minX, minY, minZ], [maxX, maxY, maxZ]) = cmd.get_extent(selection) print("Box dimensions (%.2f, %.2f, %.2f)" % (maxX - minX, maxY - minY, maxZ - minZ)) center_of_mass = [(minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2] print("Center of mass (%.2f, %.2f, %.2f)" % tuple(center_of_mass)) minX = minX - float(padding) minY = minY - float(padding) minZ = minZ - float(padding) maxX = maxX + float(padding) maxY = maxY + float(padding) maxZ = maxZ + float(padding) size_x = maxX - minX size_y = maxY - minY size_z = maxZ - minZ center_x = (minX + maxX) / 2 center_y = (minY + maxY) / 2 center_z = (minZ + maxZ) / 2 return size_x, size_y, size_z, center_x, center_y, center_z print("\nSmina Options:") print("--center_x %.3f," % center_x, "--center_y %.3f," % center_y, "--center_z %.3f," % center_z, "--size_x %.3f," % size_x, "--size_y %.3f," % size_y, "--size_z %.3f," % size_z)
cmd.extend("search_space", search_space)
# draw gridbox
def grid(selection="enabled and organic", padding=4.0, lw=1.5, r=0.5, g=0.5, b=0.8): ([minX, minY, minZ], [maxX, maxY, maxZ]) = cmd.get_extent(selection) print("Box dimensions (%.2f, %.2f, %.2f)" % (maxX - minX, maxY - minY, maxZ - minZ)) center_of_mass = [(minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2] print("Center of mass (%.2f, %.2f, %.2f)" % tuple(center_of_mass)) minX = minX - float(padding) minY = minY - float(padding) minZ = minZ - float(padding) maxX = maxX + float(padding) maxY = maxY + float(padding) maxZ = maxZ + float(padding) box = [ LINEWIDTH, float(lw), BEGIN, LINES, COLOR, float(r), float(g), float(b), VERTEX, minX, minY, minZ, VERTEX, maxX, minY, minZ, VERTEX, minX, maxY, minZ, VERTEX, maxX, maxY, minZ, VERTEX, minX, minY, maxZ, VERTEX, maxX, minY, maxZ, VERTEX, minX, maxY, maxZ, VERTEX, maxX, maxY, maxZ, VERTEX, minX, minY, minZ, VERTEX, minX, maxY, minZ, VERTEX, maxX, minY, minZ, VERTEX, maxX, maxY, minZ, VERTEX, minX, minY, maxZ, VERTEX, minX, maxY, maxZ, VERTEX, maxX, minY, maxZ, VERTEX, maxX, maxY, maxZ, VERTEX, minX, minY, minZ, VERTEX, minX, minY, maxZ, VERTEX, maxX, minY, minZ, VERTEX, maxX, minY, maxZ, VERTEX, minX, maxY, minZ, VERTEX, minX, maxY, maxZ, VERTEX, maxX, maxY, minZ, VERTEX, maxX, maxY, maxZ, END ] boxName = "box_" + str(randint(0, 10000)) while boxName in cmd.get_names(): boxName = "box_" + str(randint(0, 10000)) cmd.load_cgo(box, boxName) return boxName
cmd.extend("grid", grid)

このスクリプトは、PyMOLで指定した分子(デフォルトではリガンド)の空間範囲(search space)を計算し、その範囲にグリッドボックスを描画するものです。AutoDock VinaやSminaのドッキングに必要なcenter座標sizeも取得できます。


詳細コード


必要なモジュールのインポート

from pymol import cmd
from pymol.cgo import *
import itertools
from random import randint
  • cmd:PyMOLの内部コマンドにアクセスするためのインターフェース
  • cgo:Custom Graphics Object(線などの3Dオブジェクトを描画)
  • randint:重複のないボックス名を作成するための乱数生成

search_space関数:ドッキング空間の座標情報を取得

def search_space(selection="enabled and organic", padding=4.0): ([minX, minY, minZ], [maxX, maxY, maxZ]) = cmd.get_extent(selection) print("Box dimensions (%.2f, %.2f, %.2f)" % (maxX - minX, maxY - minY, maxZ - minZ)) center_of_mass = [(minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2] print("Center of mass (%.2f, %.2f, %.2f)" % tuple(center_of_mass)) minX -= float(padding) minY -= float(padding) minZ -= float(padding) maxX += float(padding) maxY += float(padding) maxZ += float(padding) size_x = maxX - minX size_y = maxY - minY size_z = maxZ - minZ center_x = (minX + maxX) / 2 center_y = (minY + maxY) / 2 center_z = (minZ + maxZ) / 2 return size_x, size_y, size_z, center_x, center_y, center_z
  • cmd.get_extent(selection) で分子のXYZの範囲を取得
  • padding 値を加えて、グリッドボックスを少し大きく設定
  • size_x, size_y, size_z:ボックスのサイズ
  • center_x, center_y, center_z:ボックスの中心(ドッキングに使う座標)

🔧 PyMOL上で search_space() を呼び出すと、コンソールに中心座標とサイズが出力されます。


PyMOLコマンドとして拡張

cmd.extend("search_space", search_space)
  • PyMOL内で search_space コマンドとして呼び出せるようにします。

grid関数:グリッドボックスの描画

def grid(selection="enabled and organic", padding=4.0, lw=1.5, r=0.5, g=0.5, b=0.8): ([minX, minY, minZ], [maxX, maxY, maxZ]) = cmd.get_extent(selection) print("Box dimensions (%.2f, %.2f, %.2f)" % (maxX - minX, maxY - minY, maxZ - minZ)) center_of_mass = [(minX + maxX) / 2, (minY + maxY) / 2, (minZ + maxZ) / 2] print("Center of mass (%.2f, %.2f, %.2f)" % tuple(center_of_mass)) minX -= float(padding) minY -= float(padding) minZ -= float(padding) maxX += float(padding) maxY += float(padding) maxZ += float(padding) box = [ LINEWIDTH, float(lw), BEGIN, LINES, COLOR, float(r), float(g), float(b), VERTEX, minX, minY, minZ, VERTEX, maxX, minY, minZ, VERTEX, minX, maxY, minZ, VERTEX, maxX, maxY, minZ, VERTEX, minX, minY, maxZ, VERTEX, maxX, minY, maxZ, VERTEX, minX, maxY, maxZ, VERTEX, maxX, maxY, maxZ, VERTEX, minX, minY, minZ, VERTEX, minX, maxY, minZ, VERTEX, maxX, minY, minZ, VERTEX, maxX, maxY, minZ, VERTEX, minX, minY, maxZ, VERTEX, minX, maxY, maxZ, VERTEX, maxX, minY, maxZ, VERTEX, maxX, maxY, maxZ, VERTEX, minX, minY, minZ, VERTEX, minX, minY, maxZ, VERTEX, maxX, minY, minZ, VERTEX, maxX, minY, maxZ, VERTEX, minX, maxY, minZ, VERTEX, minX, maxY, maxZ, VERTEX, maxX, maxY, minZ, VERTEX, maxX, maxY, maxZ, END ]
  • cmd.get_extent()で選択領域の空間を取得し、paddingを加えて拡張
  • PyMOLのCGO(Custom Graphics Object)で12本の辺からなる立方体(グリッドボックス)を描画
  • 色(RGB)や線の太さ(lw)も指定可能

グリッドオブジェクトの登録と表示

 boxName = "box_" + str(randint(0, 10000)) while boxName in cmd.get_names(): boxName = "box_" + str(randint(0, 10000)) cmd.load_cgo(box, boxName) return boxName
  • randintを使って一意なボックス名(例:box_4928)を生成
  • cmd.load_cgo()でCGOオブジェクトをPyMOLに読み込む

PyMOLコマンドとして拡張

cmd.extend("grid", grid)
  • PyMOL上で grid コマンドを使えるようにします(例:grid ligand

使い方まとめ

▶ リガンドのドッキング領域のサイズと中心を調べたい場合:

search_space ligand
  • ligand はオブジェクトや選択の名前
  • 結果はPyMOLのターミナルに表示されます

▶ グリッドボックスを表示したい場合:

grid ligand
  • 選択された領域を囲むボックスがPyMOL上に描画されます

💡補足

  • padding=4.0 を調整するとボックスサイズが変わります
  • selection="ligand""resn ATP" などに変えると特定の残基にも対応可能

保存したファイルをFile→RunScript…でrunさせておきます。

gridとコマンドプロンプトに入力し、Enterを押すと、Box dimensionsなど出てきます!

このCenter of massを後のスクリーニングで記入すると良いでしょう。

最後に


過去記事では、UCFS Chimeraでのタンパク質のエネルギー最小化とgrid boxの作成についても記載しています。Windowsかつアカデミアの方についてはこの記事に従った方が少し楽かもしれません。やっていることはどちらでも変わらないので、お好きな方でお試しください!

参考文献


GitHub – openmm/openmm: OpenMM is a toolkit for molecular simulation using high performance GPU code.

License: MIT, LGPL

DrawGridBox – PyMOLWiki

Centroid – PyMOLWiki

License: BSD-2-Clause

macOS/Ubuntu 22.04へのオープンソース版PyMOL 3.0のインストール方法 – Qiita


The post 【タンパク質準備】OpenMMを使ったタンパク質のエネルギー最小化とPymolを使ったGrid boxの決定方法【In silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/openmm-gridbox/feed/06691