LabCodehttps://labo-code.com研究で使えるプログラミングをSun, 01 Feb 2026 20:41:43 +0000jahourly1https://labo-code.com/wp-content/uploads/2022/02/labcode_symbolmark_color_220208-150x150.pngLabCodehttps://labo-code.com3232 173295403【環状ペプチド】機械学習と強化学習を使ったIn silico環状ペプチドスクリーニングの開発【In silico創薬】https://labo-code.com/bioinformatics/ml-rl-cyclic-peptide-screening/https://labo-code.com/bioinformatics/ml-rl-cyclic-peptide-screening/#respondSat, 31 Jan 2026 23:11:22 +0000https://labo-code.com/?p=7088

この記事は機械学習と強化学習を使用して、さらに結合力の高い環状ペプチドを発見するin silicoペプチドスクリーニングの記事です。 すでに結合がわかっている環状ペプチド(既存もしくはRF PeptideとProtein ...

The post 【環状ペプチド】機械学習と強化学習を使ったIn silico環状ペプチドスクリーニングの開発【In silico創薬】 first appeared on LabCode.

]]>

この記事は機械学習と強化学習を使用して、さらに結合力の高い環状ペプチドを発見するin silicoペプチドスクリーニングの記事です。

すでに結合がわかっている環状ペプチド(既存もしくはRF PeptideとProteinMPNNから判明)をベースにさらに結合力の高い環状ペプチドを予測することができます。

最先端の機械学習モデル、強化学習モデルを組み合わせた手法になっているので、ぜひ参考にしてみてください!

【この記事のまとめ】

創薬研究者やバイオインフォマティクスに関心がある方に向けて、機械学習(ML)による活性予測と強化学習(RL)を組み合わせ、膨大な探索空間から「高活性な環状ペプチド」を自律的に効率よく特定する手法を解説します。

  • 強化学習による知的探索の自動化:単なるランダムスクリーニングではなく、強化学習エージェントが「より高い報酬(活性)」を求めて配列を最適化する高度な探索プロセスを学べます。
  • ML代理モデルによる高速評価:ドッキングシミュレーション等の重い計算を機械学習モデルで近似(代替)し、計算コストを抑えつつ膨大な数の配列をスクリーニングするパイプラインを構築します。
  • Pythonによる実践的ワークフロー:環境構築から報酬設計(Reward Design)、学習曲線の可視化まで、実際のコードを交えてハンズオン形式で紹介しています。

この記事を読むことで、AIが自ら「最適な配列」を学習・提案する次世代のスクリーニング環境を、自身のPCやクラウド環境に構築できるようになります。

動作検証済み環境

Windows 11 Home, 13th Gen Intel(R) Core(TM) i7-13700,
CPU: Corei7-13700F, メモリ:32GB
GPU: GeForce RTX 4070 VENTUS 2X 12G OC

分子ドッキングを使ったIn silico screening


インシリコスクリーニングとは、コンピューター上で多数の化合物を扱い、標的となるタンパク質などに結合しそうな分子を効率よく探し出す手法です。実験を行う前段階として用いられ、創薬研究における探索工程を大幅に高速化できる点が特徴です。

その代表的な方法の一つが分子ドッキングを用いたインシリコスクリーニングです。分子ドッキングでは、化合物が標的分子のどこに、どのような姿勢で結合するかを計算機上で予測し、その結合の強さをスコアとして評価します。

このスコアを指標にすることで、数万〜数百万といった膨大な化合物の中から、標的に対して結合力が高いと予測される候補分子を効率的に絞り込むことが可能になります。分子ドッキングを用いたインシリコスクリーニングは、「まず当たりをつける」ための手法として、現在の創薬研究において欠かせないアプローチとなっています。

分子ドッキングを用いたインシリコスクリーニングは強力な手法ですが、一方で課題も存在します。特に、スクリーニングに用いる化合物がランダムに生成されたものである場合、膨大な候補の中から高い結合力を持つ化合物に到達するまでに多くの計算資源と時間を要します。つまり、「当たり」を引くまでの効率が必ずしも高くないという問題があります。

機械学習、強化学習を使ったIn silico screening


この課題に対して有効なのが、機械学習や強化学習を用いたインシリコスクリーニングです。これらの手法では、過去の評価結果(例えば分子ドッキングスコア)をもとに学習を行い、「次に高い結合力を示しそうな化合物」や「有望な配列」を意図的に提案することができます。

さらに、機械学習や強化学習によって提案された化合物を分子ドッキングで評価することで、計算機上での予測と実測(ドッキング評価)を組み合わせた効率的な探索が可能になります。

これまで環状ペプチドの機械学習・強化学習には Mobiusというパッケージを紹介してきましたが、実運用の面では扱いづらい点もありました。そこで本記事では、環状ペプチドのインシリコスクリーニングをより直感的かつ柔軟に行えるよう、新たに一から開発した手法を紹介します。

この手法を用いることで、読者の皆さんが興味を持つ環状ペプチドと標的分子の組み合わせに対して、機械学習・強化学習と分子ドッキングを組み合わせたスクリーニングを実践し、結合力の高い候補分子を効率よく見つけることが可能になります。

環境構築


仮想環境の構築

こちらに開発したコードを記載しています。

以下を行い、In_silico_screening環境をセットアップしてみてください。

#githubレポジトリのダウンロード
git clone https://github.com/Barashin/In_silico_screening_of_macrocyclic_peptides.git
#In_silico_screening_of_macrocyclic_peptidesフォルダへ
cd /home/shizuku/In_silico_screening_of_macrocyclic_peptides
#GNN + Active Learning環境の設定
bash setup_in_silico_screening.sh
# AutoDock CrankPep環境の設定
bash adcpsuite_micromamba.sh

また以下でテストを行なってください。

#環境のアクティベート
micromamba activate in_silico_screening
#環境テスト
python test_environment.py

インプットファイルの設定

以下のディレクトリ構造を参考に

Inputフォルダ:標的タンパク質(例:1O6K_noligand.pdb)、結合ペプチド(例:Peptideligand.pdbqt)

docking_setupフォルダ:結合場所の内容が入ったファイル(例:1O6K.trg)

を作成してください。

Research_Linux/
├── Research/ # Pythonモジュール(必須)
│ ├── active_learning_gnn.py
│ ├── transformer_models.py
│ └── adcp_interface.py
│
├── Input/ # 入力ファイル(.trg作成時に必要)
│ ├── 1O6K_noligand.pdb
│ └── Peptideligand.pdbqt
│
├── docking_setup/ # ターゲットファイル(必須)
│ └── 1O6K.trg
│
├── result/ # 初期ドッキング結果(自動作成)
├── result_active_learning/ # AL結果(自動作成)
└── al_output/ # 最終出力(自動作成)

全実装概要


1. リード入力: 最適化の起点となる親配列を決定する。

2. データ洗浄: 既存ファイルを走査し、外れ値を自動除外する。

3. 初期収集: 有効データが50件(変更可能)に達するまで、自動変異とドッキング(Autodock CrankPep)を繰り返す。

4. モデル選定: 9種類のアルゴリズムを比較し、最も予測精度の高いモデルを採用する。

5. 能動学習: AIが選んだ有望候補をドッキングし、10回ループで精度と活性を磨き上げる。

6. 結果出力: 改良されたTop 10配列と、進捗を可視化した最終レポートを生成する。

コードの実行


コードは以下で実行できる

python active_learning_from_lead.py --lead "htihswqmhfkin"

デフォルト設定だと、50個の環状ペプチドを—lead に記入した配列から自動生成し、その後の分子ドッキング→機械学習→強化学習へと進む

以下のような引数で、いろいろなパラメータを設定できる。

| 引数 | 短縮 | デフォルト | 説明 |
|------|------|-----------|------|
| `--lead` | `-l` | (必須) | リード配列 |
| `--existing-dir` | | result/ | 既存結果のディレクトリ |
| `--iterations` | `-i` | 10 | ALイテレーション数 |
| `--batch-size` | `-b` | 5 | 各イテレーションの配列数 |
| `--runs` | `-N` | 5 | MC探索回数 |
| `--evals` | `-e` | 100000 | 評価ステップ数 |
| `--timeout` | | 600 | ドッキングタイムアウト(秒) |
| `--acquisition` | | EI | 獲得関数 (EI/UCB/PI) |
| `--min-usable-samples` | | 50 | 学習に必要な最小サンプル数(外れ値除く) |
| `--auto-select-model` | | False | 最良モデルを自動選択 |
| `--production` | | | 本番設定 (timeout=1200) |
| `--quick` | | | クイックテスト (N=1, n=5000, min_usable=20) |
| `--no-confirm` | | | 確認スキップ |

結果


ペプチドライブラリの生成

まずleadの配列をランダムに変異させた50個(デフォルト値変更可能)の配列が生成する

モデルの比較

次にその配列と結合力を使用し、様々な機械学習モデルが作成され、比較される。

評価指標(R2)を用いて、Bestなものが自動的に選ばれるが、ぜひ目で見て確認してほしい。(CatBoostが過学習気味ではあるが、結構良さそうな感じでもある)

1. グラフニューラルネットワーク (GNN) 系化合物を「原子=ノード」「結合=エッジ」とするグラフ構造として捉えるモデル群です。

  • GIN / GCN / GAT: グラフ上のノード情報を近傍から集約する標準的な手法。画像ではGATの精度が低く、このタスクへの適性は慎重な判断が必要です。
  • GraphSAGE: 近傍ノードのサンプリングと集約を行う手法。
  • MPNN (Message Passing Neural Network): 原子間のメッセージ伝達を模した、化学分野で非常に強力なモデルです。

2. トランスフォーマー (Transformer) 系自然言語処理で使われる「注目機構(Attention)」を応用したモデルです。

  • SeqTransformer: ペプチドのアミノ酸配列(文字列情報)をシーケンスとして処理します。
  • GraphTransformer: グラフ構造にAttention機構を導入し、原子同士の遠距離の相関も考慮します。

3. その他(CNN・勾配ブースティング)

  • CNN1D: 1次元の畳み込みニューラルネットワーク。主に配列情報の局所的なパターン抽出に使用されます。
  • CatBoost: 決定木ベースの勾配ブースティングアルゴリズム。Train $R^2 = 0.998$ と非常に高いですが、Testスコアとの乖離が大きく、過学習(Overfitting)の傾向が見て取れます。

ペプチドの探索

モデルを選ぶと、

  1. さらに結合力が高い配列が提案(5個)
  2. 実際に分子ドッキング
  3. モデルの学習へ
  4. 1-4のループ

がなされる。最終的に結合力の高い配列が提案されます。

最終結果で結合力が高すぎるものはFalse positiveな感じもしますが、出てきたものについては、PRODIGYや実験でValidationするとよいでしょう。

最後に


以前紹介したRFPeptide→ProteinMPNNでDe novo環状ペプチドの合成した後の配列を使用すれば、

さらなる結合力の向上も可能です。ぜひ試してみてください!

今後は非天然アミノ酸の導入や膜透過性の指標も入れて、様々な指標でよい結果がなるような環状ペプチドの合成を試そうと思います!


The post 【環状ペプチド】機械学習と強化学習を使ったIn silico環状ペプチドスクリーニングの開発【In silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/ml-rl-cyclic-peptide-screening/feed/07088
【環状ペプチド】ProteinMPNNを利用した環状ペプチド配列の創出https://labo-code.com/bioinformatics/proteinmpnn-cyclic-peptide-design/https://labo-code.com/bioinformatics/proteinmpnn-cyclic-peptide-design/#respondSat, 31 Jan 2026 23:00:38 +0000https://labo-code.com/?p=7084

今回は前回の記事でRFPeptideで作成した環状ペプチド骨格に対して、その骨格に一致するアミノ酸配列をProteinMPNNで探索していきます。また、MPNNで予測したアミノ酸配列の構造をAlphaFold2を利用して ...

The post 【環状ペプチド】ProteinMPNNを利用した環状ペプチド配列の創出 first appeared on LabCode.

]]>

今回は前回の記事でRFPeptideで作成した環状ペプチド骨格に対して、その骨格に一致するアミノ酸配列をProteinMPNNで探索していきます。また、MPNNで予測したアミノ酸配列の構造をAlphaFold2を利用して確認することまで行います。

この記事を読むことで、ProteinMPNNを最新のアミノ酸配列推定方法とAlphaFold2の実行方法を知ることが出来ます。

【この記事のまとめ】

本記事では、創薬研究者やバイオインフォマティクス初学者に向けて、最先端の配列設計AI「ProteinMPNN」を駆使して、高い構造安定性を持つ環状ペプチドの配列を精密にデザインする方法を解説します。

  • 高精度な配列最適化:骨格構造(バックボーン)に最適なアミノ酸配列を数秒で生成し、設計の成功率を従来の物理化学的手法よりも大幅に向上させます。
  • 環状構造への特化設定:N末端とC末端を連結させる環状ペプチド特有のパラメータ設定や、計算を効率化するための「タイリング(Tying)」の手法を習得できます。
  • 実践的な実行フロー:Google Colab等での環境構築から、実際のコマンド入力、設計結果の評価まで、ステップバイステップで詳しくガイドします。

この記事を読むことで、最新のAI技術を自身の研究に取り入れ、標的タンパク質に強く結合する「次世代の環状ペプチド候補」を効率的に創出できるようになります。

動作検証済み環境

Windows 11, WSL2(Ubuntu 20.04),bash(Micromamba )

PCスペック
CPUメモリ: 16GB
GPU: NVIDIA GeForce RTX 2070 SUPER(8GB)
GPUドライバー: 581.29-desktop-win10-win11-64bit-international-dch-whql

ProteinMPNNとは?


ProteinMPNN は、タンパク質の立体構造(バックボーン座標)からアミノ酸配列を設計するための深層学習モデルです。簡単に言うと、「構造からその構造にマッチする最適な配列を予測するAI」です。

Message Passing Neural Network (MPNN)を用いることで、従来法(Rosetta Design等)に比べ、速く、正確で、構造に忠実な配列設計ができる可能性があるツールです。こちらも前回のRFPeptide同様GPUを利用するツールです。もしもGPUドライバーがインストールされていない場合は、前回の記事を参考にインストールしておきましょう。

以下で、少しだけこのツールの仕組みを深堀します。MPNNとはグラフ構造データを扱うためのニューラルネットワークの一種で、簡単に言うと、ノード(点)とエッジ(線)で表される構造情報をもとに、各ノードの状態を更新して特徴を学習する仕組みです。 このMPNNで、ノードをアミノ酸、エッジを残基間の距離や結合に見立てて、グラフ構造としてタンパク質の立体構造を扱うことで、遠くのアミノ酸から付近のアミノ酸までを自然な形で重みをつけて考慮することが可能になっています。

ProteinMPNNでは、このMPNNによってアミノ酸配列と立体構造の関係が学習されており、これをタンパク質設計に応用しています。

ProteinMPNNの実装方法


では早速、ProteinMPNNでこちらの記事で作成した環状ペプチド骨格に最適なアミノ酸配列を予測していきます。

こちらを参考に環境構築から行っていきます。今回もWindowsのWSLを利用していきます。WSLの利用方法がわからない場合は、こちらの記事に記載してあるのでそちらを参考にしてください。

前回の記事と同様に、環境構築はmicromambaで行います。WSLで以下を実行してください。途中で [Y/n] の入力を求められたら、Yを入力してください。

# GitHub から ProteinMPNN をクローン
git clone https://github.com/dauparas/ProteinMPNN.git
cd ProteinMPNN
# micromambaで環境を用意
micromamba create -n mlfold python=3.10 -y
# 環境の有効化
micromamba activate mlfold
# 必要なパッケージをインストール
micromamba install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch
# 学習済みのモデルをダウンロード
wget https://github.com/dauparas/ProteinMPNN/blob/main/vanilla_model_weights/v_48_002.pt
wget https://github.com/dauparas/ProteinMPNN/blob/main/vanilla_model_weights/v_48_010.pt
wget https://github.com/dauparas/ProteinMPNN/blob/main/vanilla_model_weights/v_48_020.pt
wget https://github.com/dauparas/ProteinMPNN/blob/main/vanilla_model_weights/v_48_030.pt

プログラムを実行する

これでProteinMPNNを実行する用意が整いました。実際にこれから実行をしていきます。

私は前回の記事で作成したdesign_0.pdbファイルの構造に対して、ProteinMPNNを実行します。そのため、pdbファイルを保存していたフォルダ内にMPNNoutputというフォルダを作成し、そのフォルダにProteinMPNNの結果が保存されるように指定して実行しました。もしも、別のファイルを対象にProteinMPNNを実行したい場合や、別の保存場所を利用したい場合は、--pdb_path--out_folder に関して、ご自身の保存場所や指定したいファイルに合わせて変更してください。

前回の記事を参考に進めていただいている場合は、上記のパス設定はそのままで、アウトプットの保存先として、/Documents/RFPeptide/samplesフォルダ内にMPNNoutputという名前のフォルダを作成してから、以下を実行してください。

# ProteinMPNNを実行
python ProteinMPNN/protein_mpnn_run.py \ --pdb_path documents/RFdiffusion/samples/design_0.pdb \ --pdb_path_chains "B" \ --out_folder /documents/RFdiffusion/samples/MPNNoutput \ --model_name v_48_020 \ --num_seq_per_target 2 \ --sampling_temp 0.1 \ --seed 42 \ --batch_size 1

実行結果

MPNNoutputフォルダに/documents/RFPeptide/samples/MPNNoutputdesign_0.faseqsというフォルダが出来、その中にdesign_0.faというファイルができてその中身がいれば成功です!

このファイルはメモ帳などで開くことができます。実際に確認してみると以下の様になっていました。指定通りに、“ESGIIDIETGERIP”と“ESGIIDIETGEKIP”の2種類のアミノ酸配列が予想されたことが分かります。ESGIIDIETGERIPこのファイルをメモ帳などで開くと以下の様になっているはずです。この3行目以降がProteinMPNNで予測された、骨格構造に沿ったアミノ酸配列です。指定通りに2種類の配列が予測されました。

design_0, score=3.7456, global_score=1.9113, fixed_chains=['B'], designed_chains=['A'], model_name=v_48_020, git_hash=8907e6671bfbfc92303b5f79c4b5e6ce47cdef57, seed=42
GGGGGGGGGGGGGG
T=0.1, sample=1, score=0.8211, global_score=1.6212, seq_recovery=0.1429
ESGIIDIETGERIP
T=0.1, sample=2, score=0.7738, global_score=1.6172, seq_recovery=0.1429
ESGIIDIETGEKIP

AlphaFold2での実行結果の確認


では、ここからAlphaFold2でのMPNNの出力物の確認を行っていきます。AlphaFold2を自身のPCで実行するのは要求されるPCスペックが非常に高いことから現実的ではないのですが、今回はブラウザ環境でAlphaFold2が実行できるGoogleColab環境を利用することで実行していきます。また、通常のAlphaFoldは環状ペプチドの構造予測には対応していないので、GoogleColabを使って環状ペプチドの構造予測にAlphaFoldを対応させてあるこちらで公開されているツールを利用していきます。

先ずはこちらのリンクへ移動してください。ここから先ほどのツールによるGoogleColabでのAlphaFold2による環状ペプチドの構造予測を簡単に行うことが出来ます。リンク先のブラウザ画面からは環状ペプチドの構造予測の設定をいじることが出来ますが、今回変更が必要なのは3か所のみです。

先ずは、①**query_sequence:** のカラム内に今回ProteinMPNNで作成した配列を入力してください。さらに②**jobname:** カラム内はアウトプットファイルの名前を指定できるので、お好きな名前を入力してください。

私は**query_sequence:** にはMPNNが予測した1番目の配列”ESGIIDIETGERIP”を、jobname: には”Sample1”と入力しておきました。

最後に、③ページを下にスクロールしたところにある**Save settings**のチェックボックスにチェックをつけて、実行結果を保存できるようにしておきましょう。(上記の設定箇所はスクリーンショット内に赤枠でマークしてありますので、見つかりにくい場合の参考にしてください。)

上記の設定が終わったらページ左上の”全てのセルを実行”(スクリーンショット1枚目の赤枠)をクリックすると、AlphaFold2が実行できます。この時に以下の警告が表示されると思いますが、気にせず実行してしまって構いません。

すると、しばらくするとページをスクロールした先に、このように予測された立体構造が表示されます。

今回のアミノ酸配列がplDDTが90–100という高い精度で、狙い通りの環状ペプチド構造を形造ることが確認できました。

上記は切れているように見えますが、Pymolで読み込み、Sticksで表示すると、きちんとした環状ペプチドになっています!

コードの解説


上に書いたソースコードの解説をしていきます。

# GitHub から ProteinMPNN をクローン
git clone https://github.com/dauparas/ProteinMPNN.git
cd ProteinMPNN
# micromambaで環境を用意
micromamba create -n mlfold python=3.10 -y
# 環境の有効化
micromamba activate mlfold
# 必要なパッケージをインストール
micromamba install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch
# 学習済みのモデルをダウンロード
wget https://github.com/dauparas/ProteinMPNN/blob/main/vanilla_model_weights/v_48_002.pt
wget https://github.com/dauparas/ProteinMPNN/blob/main/vanilla_model_weights/v_48_010.pt
wget https://github.com/dauparas/ProteinMPNN/blob/main/vanilla_model_weights/v_48_020.pt
  • git clone は、GitHub にあるプロジェクト(この場合は ProteinMPNN)を自分のパソコンにコピーするコマンドです。

  • https://github.com/dauoaras/ProteinMPNN.git はコピー元の URL です。

    実行すると、カレントディレクトリ(今いるフォルダ)に ProteinMPNN という名前のフォルダが作られ、その中にプロジェクトのファイルが全部入ります。

    イメージ: 「インターネット上の本棚(GitHub)から、本を丸ごと借りて自分の机に置く」ような感じです。

  • cd ProteinMPNN で先ほどクローンしたディレクトリへ移動します。

  • micromamba create -n mlfold python=3.10 -y では、micromambaを使って、mfoldという名前の環境を作成し、pythonをインストールしています。環境の名前はなんでもOKです。

  • micromamba activate mlfold で先ほど作った環境を有効化します。これで先ほどインストールしたpythonが入っている環境が立ち上がりました。

  • micromamba install pytorch torchvision torchaudio cudatoolkit=11.3 -c pytorch で、立ち上がった環境内にさらに必要なパッケージをインストールしていきます。

  • wget はオンライン上のファイルをダウンロードするコマンドです。ここではGitHub上にある、ProteinMPNNで利用する学習済みモデルの重みを3種類ダウンロードしています。これでProtein MPNNが利用可能になりました。

# ProteinMPNNを実行
python ProteinMPNN/protein_mpnn_run.py \ --pdb_path documents/RFdiffusion/samples/design_0.pdb \ --pdb_path_chains "B" \ --out_folder /documents/RFdiffusion/samples/MPNNoutput \ --model_name v_48_020 \ --num_seq_per_target 2 \ --sampling_temp 0.1 \ --seed 42 \ --batch_size 1
  • このコードで実際にProteinMPNNを実行しています。各オプションの意味は以下の通りです。

-pdb_path:デザインの元になるタンパク質構造(PDBファイル)の場所を指定。

-pdb_path_chains "B" :PDBの中のどのチェーンをデザイン対象にするか指定。

今回のファイルには、環状ペプチドと結合ターゲットとなるタンパク質の2種類の鎖が含まれているため、環状ペプチドのチェーンの方(私のファイルの場合はB)を指定した。

-out_folder :MPNN が生成した配列をどこに保存するかを指定。

-model_name :使いたい学習済みモデルの重みを指定。

  • ProteinMPNN には複数モデルがあり、どのモデルを利用するかを指定できる。

今回はvanilla_model_weights/v_48_020.ptで一般的な ProteinMPNN の基本モデルを利用。その他には、水溶性の大型タンパク質のためのモデルや、より簡易的な予測をするための軽量モデルなどが選択できる。

-num_seq_per_target 2 :1つの構造に対して何本のアミノ酸配列を生成するかを指定。今回は、簡易に2本の配列を予測するように指定。多すぎても、計算に時間がかかる為、10本ほど予測させておくと良いかもしれない。

-sampling_temp 0.1 :生成モデルの温度パラメーターを指定する。温度パラメーターとは、“ランダム性(探索の広さ)” を決めるパラメータ。

  • 0.1:保守的(モデルがアミノ酸配列を1アミノ酸ずつ予測する際に、より確率の高いもアミノ酸候補の中から選択する)
  • 1.0:ランダム性高い(比較的確率が低いアミノ酸も選択肢に入れて、アミノ酸候補を選択する。予想されるアミノ酸配列に多様な配列が生まれる。)

最適な数値は、実際に試しながら探っていく必要があるが、今回の用途で使い場合は0.1~0.3ぐらいの保守的な予測が適切な可能性が高い。

-seed 42 :実行ごとのランダム性を固定するためのシード設定。今回のような生成モデルは、たとえ同様のpdbファイルを対象にした場合でも実行するごとに予測結果が変動する。シード設定として適当な値を設定しておくことで、再度プログラムを実行したときに前回と同様のシード値を設定することで、前回と同じ結果を予測することができる。予測ファイルを誤って消去してしまった際などや、結果の再現性を確保したい際のために設定しておくと便利。

-batch_size 1 :一度にいくつの構造を処理するかを指定する。余程の高性能マシンでない限り、 1 のままでOK。

最後に


ProteinMPNNの解説は以上になります。相変わらずGPUは必要ですが、ツール自体は意外と簡単に利用できたのではないでしょうか。AlphaFoldも加えて、構造もきちんと確認できるととても面白いですね!

参考文献


Protein MPNN

https://github.com/dauparas/ProteinMPNN?tab=MIT-1-ov-file MIT License

AlphaFold2

https://github.com/google-deepmind/alphafold?tab=Apache-2.0-1-ov-file Apache License

環状ペプチド用のAlphaFold2

くろたんくLab様より開発

くろたんくLab

https://colab.research.google.com/github/blacktanktoplab/ColabFold/blob/cyclic/AlphaFold2.ipynb


The post 【環状ペプチド】ProteinMPNNを利用した環状ペプチド配列の創出 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/proteinmpnn-cyclic-peptide-design/feed/07084
RFPeptideを用いたDe novo環状ペプチドの創出【In silico創薬】https://labo-code.com/bioinformatics/rfpeptide-denovo-cyclic-peptide/https://labo-code.com/bioinformatics/rfpeptide-denovo-cyclic-peptide/#respondSat, 31 Jan 2026 22:43:34 +0000https://labo-code.com/?p=7080

今回は注目の環状ペプチド探索・生成法であるRFPeptideについて解説をしていきます。RFPeptideの概要・インストール方法・使い方を合わせて説明します。 RFPeptideを使えるようになると、ニューラルネットワ ...

The post RFPeptideを用いたDe novo環状ペプチドの創出【In silico創薬】 first appeared on LabCode.

]]>

今回は注目の環状ペプチド探索・生成法であるRFPeptideについて解説をしていきます。RFPeptideの概要・インストール方法・使い方を合わせて説明します。

RFPeptideを使えるようになると、ニューラルネットワークを使った非常に高精度な環状ペプチドのDe novo生成が可能になります。一緒にマスターしていきましょう!

【この記事のまとめ】

創薬研究者やバイオインフォマティクスに関心がある方に向けて、拡散モデル(Diffusion Model)を活用して高精度な環状ペプチドを新規設計(De novo生成)できるツール「RFPeptide」の使い方を解説します。

  • 拡散モデルによる高度な構造最適化:ノイズ除去のプロセスを通じて、ターゲットタンパク質に最適に結合するペプチド骨格を、従来の物理シミュレーションより高速かつ高精度に生成します。
  • 環状ペプチドに特化した設計:創薬において安定性が高く重要な「環状構造」の生成にフォーカスし、具体的なパラメータ設定や実行手順を詳しく紹介します。
  • WSL2/GPU環境での実践ガイド:環境構築から実際のPDBファイルを用いた実行、結果の確認まで、ハンズオン形式で迷わず進められるワークフローを網羅しています。

この記事を読むことで、最先端の生成AI技術を創薬ワークフローに取り入れ、PC一台で独自の高品質なペプチドライブラリを創出するスキルが身につきます。

動作検証済み環境

Windows 11, WSL2(Ubuntu 20.04),bash(Micromamba 初期化済)

PCスペック
CPUメモリ: 16GB
GPU0: NVIDIA GeForce RTX 2070 SUPER(専用メモリ 8GB)
GPU1: Intel UHD Graphics 630(内蔵 GPU)
GPUドライバー: 581.29-desktop-win10-win11-64bit-international-dch-whql

RFPeptideとは?


RFPeptideとは、ディープラーニングを用いてペプチドの立体構造や結合を設計・予測するためのツールです。ターゲットタンパクの構造を渡すと、その構造に対して結合する最適化されたペプチド骨格を生成してくれます。

以下でもう少し詳しく説明します。

RFPeptideは、拡散モデル(diffusion model)に基づく生成技術を利用して開発された手法で、ペプチドの構造最適化(標的タンパク質に対する結合ペプチドの構造設計)を目的としています。

従来の物理シミュレーションやランダム探索に比べ、拡散モデルを活用することで高速かつ高精度に候補を生成できる点が特徴であり、このRFPeptideはペプチドに特化(短いアミノ酸配列の立体構造予測・最適化)しています。

仕組みについて(より詳しく知りたい方向け)


先ほどの説明では物足りなかった方向けにこのツールの内部をより詳しくご説明します。

RFPeptideは、拡散モデル(diffusion model)に基づく生成技術を利用する手法と言いましたが、拡散モデルという言葉は初めて聞いた方も多いのではないでしょうか。

拡散モデルとは、確率的なノイズ除去の過程を利用してデータを生成する深層生成モデルです。

もう少し詳しく説明すると、拡散モデルは、以下の2stepに分けられます。

  1. 前向き過程(noising process)
    • 元のデータ(例:ランダムなペプチド構造)に少しずつガウスノイズを加えていき、最終的に「純粋なノイズ」に変換するステップ。
  2. 逆過程(denoising process)
    • 学習済みのニューラルネットワーク(NN)を用いて、ノイズから徐々に元のデータを復元していくステップ。(この過程で多様な復元像が生成されうる。)

RFPeptideではこの「ノイズを段階的に入れて壊してから、逆に段階的に直す」プロセスを利用し、ノイズから無数の新しいペプチド構造(ペプチドライブラリ)が生み出され、その中からより最適な立体構造に収束する形でノイズが除去されていきます。

拡散モデルを利用することのはメリットは、

①破壊と修復を段階的に行う点と、②ライブラリ生成に学習済みNNを用いる点です。

まず、1stepではなく段階的に破壊と修復を行うことで、より安定的に多様なペプチドライブラリを探索できます。さらに、逆過程において既存のペプチド構造を学習したNNモデルを利用することで、物理的に妥当で自然なペプチドライブラリを探索でき、またNNでの条件付き生成という形でユーザーが指定した条件(ターゲットタンパクに結合しやすい様にや、特定構造を含む様になど)を自然とライブラリ探索に活かせるために、より高品質なライブラリを高速で探索できるというメリットがあります(ランダム変異のような形でペプチドライブラリを生成する場合と比較して)。

RFPeptideはこれらのメリットから、最近注目されるペプチド構造探索法となっています。

RFPeptideの実装方法


では早速、注目のペプチド骨格構造探索法であるRFPeptideを動かしていきます。

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

今回のRFPeptideはGPUを利用するツールのため、まずはこちらのサイトでお使いのPCに搭載されているGPUに 対応したドライバ(Windows11用・Linux用ではありません)をDLして、Windows 上でインストーラを実行し、再起動して有効化してください。また、どのドライバーが良いのか分からない場合は、こちらのNDIVIA appをインストールすると最適なドライバーをインストールしてくれるようです(既にインストール済みの場合は不要です。)

次に、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
# GitHub から RFPeptide をクローン
git clone https://github.com/RosettaCommons/RFdiffusion.git
# 学習済みモデルの重みをダウンロード
cd RFdiffusion/scripts
bash download_models.sh ../models
# フォルダを移動
cd ~/RFdiffusion
# micromambaで環境を用意
micromamba env create -f env/SE3nv.yml --channel-priority flexible
# 環境の有効化
micromamba activate SE3nv
# GPU利用に必要なパッケージをインストール
micromamba install -c nvidia -c pytorch -c conda-forge pytorch torchvision torchaudio pytorch-cuda=12.1 -y
# SE3Transformer のインストール
cd env/SE3Transformer
pip install --no-cache-dir -r requirements.txt
python setup.py install
cd ../..
# RFPeptide のインストール
pip install -e .

プログラムを実行する

まずは、作業したいフォルダを決めます(私はWindowsのdocuments下に作ったRFPeptideというフォルダで作業します)。

次に、RFPeptideに渡すターゲットタンパクの立体構造のPDBファイルを用意します。利用する立体構造はご興味に合わせてどのようなものでも良いですが、私はこちらの論文内で利用されていたタンパクファイル(7zkr_GABARAP.pdb)をダウンロードして、ターゲットタンパクとしました。 (既に目的のタンパク構造ファイルがある方も同様に、ここで立体構造ファイルをコピペで作業フォルダ内に置いておきましょう)。

7zkr_GABARAP.pdbのファイルはこちらからダウンロードできます。ダウンロードしたファイル(rfd_macro.tar.gz)のexamples>input_pdbs内にあるので、こちらを作業フォルダ内に移動しておきましょう。

次は、以下のコマンドで作業したいフォルダに移動します

# 作業フォルダへ移動
cd /mnt/c/users/(あなたのWondowsのユーザー名)/documents/RFPeptide

/documents/RFPeptideは、ご自身が作業したいフォルダの名前に合わせて変更して下さい。あとは以下のコマンドを実行するだけです。

/home/(あなたのWSLのユーザー名)/RFdiffusion/scripts/run_inference.py\ inference.input_pdb=7zkr_GABARAP.pdb\ 'contigmap.contigs=[12-18 A3-117/0]'\ inference.num_designs=5\ inference.cyclic=true\ diffuser.T=25

実行結果

作業していたフォルダにoutputとsampleというフォルダが出来ているはずです。

outputには実行時のログが入っており、生成された環状ペプチドはsamplesに保存されています。

samplesフォルダ内はこのようになっていますdesign_0から4までの5種類の立体構造ファイル(pdb)と生成条件に関するファイル(trb)、生成過程の様子に関するファイルが入っているフォルダ(traj)が作成されています。

この様にオプションで指定した通りに、5つの環状ペプチド構造を作成することに成功しました!

早速、Mol* Viewerを利用してdesign_0と標的タンパク質を可視化してみましょう!

Mol*Viewerを開き、以下からdesign_0.pdbを開いてみてください。

茶色の受容体タンパクと緑の環状ぺプチドが、確かに結合されていることがわかりますね!

これら立体構造ファイルをこちらで紹介したAutoDockなどの結合評価ツールで利用すれば、そのデザインの性能を評価出来るでしょう。

また、今回作成した環状ペプチドの配列自体は全てグリシンから構成されていることもわかるかと思います。これは、あくまでRFeptideは立体構造のみを生成するツールであり、配列までは決定できないためです。配列の決定自体は別のツール(ProteinMPNN)を利用してやる必要があります(配列の決定に関しては、次回の記事で解説していきます)。

コードの解説


上に書いたソースコードの解説をしていきます。

# 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

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

# GitHub から RFPeptide をクローン
git clone https://github.com/RosettaCommons/RFdiffusion.git
# 学習済みモデルの重みをダウンロード
cd RFdiffusion/scripts
bash download_models.sh ../models
  • git clone は、GitHub にあるプロジェクト(この場合は RFdiffusion(RFpeptideのもとになるツールです))を自分のパソコンにコピーするコマンドです。

  • https://github.com/RosettaCommons/RFdiffusion.git はコピー元の URL です。

    実行すると、カレントディレクトリ(今いるフォルダ)に RFdiffusion という名前のフォルダが作られ、その中にプロジェクトのファイルが全部入ります。

    イメージ: 「インターネット上の本棚(GitHub)から、本を丸ごと借りて自分の机に置く」ような感じです。

  • cd は「Change Directory(ディレクトリを移動)」の略です。

  • RFdiffusion/scripts は、先ほどクローンしたフォルダの中の scripts というサブフォルダに移動します。

  • bash は Linux/Mac の「シェル」というコマンド実行環境でスクリプトを動かす命令です。

  • download_models.sh は、学習済みのモデルの重み(RFPeptide のニューラルネットが計算に使うデータ)をダウンロードするためのスクリプトです。

  • ../models は「1つ上のフォルダに models という名前で保存してね」という意味です。

    .. は「1つ上の階層」を指します。なので RFdiffusion/scripts の上の階層(つまり RFdiffusion フォルダ)に models フォルダが作られます。

# フォルダを移動
cd ~/RFdiffusion
# micromambaで環境を用意
micromamba env create -f env/SE3nv.yml --channel-priority flexible
# 環境の有効化
micromamba activate SE3nv
# GPU利用に必要なパッケージをインストール
micromamba install -c nvidia -c pytorch -c conda-forge pytorch torchvision torchaudio pytorch-cuda=12.1 -y
# SE3Transformer のインストール
cd env/SE3Transformer
pip install --no-cache-dir -r requirements.txt
python setup.py install
cd ../..
# RFPeptide のインストール
pip install -e .

ここでは、RFPeptide用の環境を作成し、その中に必要なパッケージやライブラリをインストールしています。

  • micromanmba env create は新しい仮想環境を作るコマンドです。

  • f env/SE3nv.yml は、先ほどGitHubからコピーしたプロジェクトの中に用意されていた「env/SE3nv.yml という設定ファイル」を使って環境を作るという意味です。

    この yml ファイルには、必要な Python のバージョンやライブラリが書かれています。

  • -channel-priority flexible は「依存関係を柔軟に解決してくれる」という意味です。

    イメージとしては「RFPeptide 専用の別の作業部屋(環境)を作って、その中に必要な道具(ライブラリ)を揃える」感じです。

  • micromamba install -c nvidia -c pytorch -c conda-forge pytorch torchvision torchaudio pytorch-cuda=12.1 -yこちらは、GPU を使って計算するために必要なパッケージをインストールします。

    これらのパッケージは、通常は先ほどのenv/SE3nv.ymlからの環境構築でインストールされているはずですが、私の場合なぜか上手くいっていなかったので、こちらでやり直しています。皆様も念のためやり直しておくとよいと思います。

  • -c は「このチャンネルからライブラリを取ってきてね」という意味です。

    nvidia → GPU 関連

    pytorch → PyTorch(ディープラーニング用ライブラリ)

    conda-forge → その他便利ライブラリ

  • pytorch torchvision torchaudio pytorch-cuda=12.1 はインストールするライブラリです。

    pytorch-cuda=12.1 は CUDA 12.1 という GPU 計算用のバージョンを指定しています。

  • -y は「途中で確認しなくても自動で Yes にする」という意味です。

  • cd env/SE3Transformer

    これは RFPeptide が使う特別なモジュールです。

    SE3Transformer というサブフォルダに移動します。

  • pip install --no-cache-dir -r requirements.txt

    requirements.txt に書かれた必要な Python ライブラリをインストールします。

    -no-cache-dir は「古いキャッシュを使わずに新しくインストールする」という意味です。

  • python setup.py install

    SE3Transformer モジュールを Python 環境にインストールします。

  • cd ../..

    元の RFdiffusion フォルダに戻ります。

  • pip install -e .

    -e は editable(編集可能)モード の意味です。

    このモードでインストールすると、フォルダ内のファイルを直接編集しても、そのまま環境に反映されます。

    . は「今いるフォルダ(RFdiffusion)をインストール対象にする」という意味です。

    つまり、RFPeptide 自体を installして、利用できるように読み込んでいます。

# 作業ファルダへ移動
cd /mnt/c/users/(あなたのWondowsのユーザー名)/documents/RFPeptide

ここのコードでは、実際に作業したいWindows上のフォルダ(私の場合はdocuments/RFPeptide)に移動しています。

/home/(あなたのWSLのユーザー名)/RFdiffusion/scripts/run_inference.py\ inference.input_pdb=7zkr_GABARAP.pdb\ 'contigmap.contigs=[12-18 A3-117/0]'\ inference.num_designs=5\ inference.cyclic=true\ diffuser.T=25

先ほどインストールしたRFPeptideのメインスクリプトであるrun_inference.pyを呼び出して、構造生成を行っています。

  • inference.input_pdb=7zkr_GABARAP.pdb

    設計対象の タンパク質構造ファイル を指定しています。

    7zkr_GABARAP.pdbは先ほどダウンロードした PDB ファイルです。ここで指定したタンパク質構造に対してペプチド結合設計が行われます。

  • 'contigmap.contigs=[12-18 A3-117/0]’ターゲットタンパクのうちのどのアミノ酸領域に、何塩基のペプチドを結合させたいかを指定しています。

    意味: [結合させたい部分のペプチドの塩基数の範囲/ターゲットタンパク上の結合させたい場所/結合させない部分のペプチドの塩基数の範囲]

    [12-18 A3-117/0] は:ターゲットタンパク質の A鎖の3〜117番目残基に対して長さ12〜18のペプチドを設計するという意味です。

  • inference.num_designs=5

    作成するペプチドデザインの数を指定しています。この場合 5種類のペプチドデザイン が出力されます。

  • inference.cyclic=true設計するペプチドを 環状(ループ状)にするかどうか を指定しています。

    true → 環状ペプチドを設計、false → 直鎖ペプチドを設計

  • diffuser.T=25ペプチド設計の際に使われる 拡散モデルのステップ数 を指定しています。数字が大きいほど設計精度が上がる場合がありますが、計算時間も長くなります。

    環状ペプチドの場合は25スッテプが良いとの論文もありますが、調整の余地があると思われます。

その他には設計に関わる以下のようなオプションが存在し、細かく指定することでより詳細な構造探索が行えます。

オプションの使用例意味補足
ppi.hotspot_res=[A30,A33,A34]contigmap.contigsで設定した範囲うちで、特に結合してほしい箇所を示す。contigmap.contigsで大まかな範囲を、こちらでより細かい範囲(特に結合してほしい塩基)を指定できます。
inference.cyc_chains=’a’環状にしたい鎖の指定。chain aを環状にするという意味
‘contigmap.contigs=[150-150]’環状ペプチドの塩基数のみを指定するやり方。(結合させたいタンパクを指定しない場合)150塩基を指定する場合は ‘150-150’。’10-20’の場合は10~20塩基のいずれかで作成。
inference.output_prefix=~~~結果の出力フォルダの名前を指定できるなしだとoputputというフォルダ名になる

最後に


今回は、最新の強力なペプチド構造探索法である RFPeptide を利用しました。GPU前提の計算量を必要とするツールですが、使用するとより大規模かつ多様なペプチドライブラリから高速かつ高精度な探索が可能です。

実践的には、よくあるのがタンパク質ータンパク質相互作用面に結合するペプチドをデザインし、その相互作用を阻害する利用法です。その際はターゲット部位を見つけることがミソになりそうです。

今後より一層使われていくであろうツールの一つだと思いますので、ぜひ一度お試しください。

参考文献


RF Peptide

https://github.com/RosettaCommons/RFdiffusion?tab=readme-ov-file BSD License


The post RFPeptideを用いたDe novo環状ペプチドの創出【In silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/rfpeptide-denovo-cyclic-peptide/feed/07080
【環状ペプチド】In silico screeningのためのin silico環状ペプチドライブラリの構築【in silico創薬】https://labo-code.com/bioinformatics/insilico-cyclic-peptide-library/https://labo-code.com/bioinformatics/insilico-cyclic-peptide-library/#respondSat, 31 Jan 2026 22:30:56 +0000https://labo-code.com/?p=7076

本記事は環状ペプチドのin silicoスクリーニングの前段階の環状ペプチドライブラリを構築する記事です。HELM表記を使って、簡単にライブラリを構築することができます。ぜひ挑戦してみてください! 自宅でできるin si ...

The post 【環状ペプチド】In silico screeningのためのin silico環状ペプチドライブラリの構築【in silico創薬】 first appeared on LabCode.

]]>

本記事は環状ペプチドのin silicoスクリーニングの前段階の環状ペプチドライブラリを構築する記事です。HELM表記を使って、簡単にライブラリを構築することができます。ぜひ挑戦してみてください!

【この記事のまとめ】

創薬研究やバイオインフォマティクスに従事する方に向けて、HELM形式を活用してin silicoスクリーニング用の「環状ペプチドライブラリ」を効率的に構築・可視化する方法を解説します。

  • HELM形式による複雑な構造記述:非天然アミノ酸や環状構造を機械可読な形式で表現する標準フォーマット「HELM」の基礎と、Pythonでの変換手法を習得できます。
  • 変異体生成の自動化:アラニンスキャニングやホモログスキャニングを実装し、リード配列から多様なライブラリを自動生成するワークフローを紹介します。
  • 3D可視化からドッキング準備まで:RDKitやpy3Dmolを用いた3D構造の生成・確認、さらにAutoDock等のシミュレーションに不可欠なPDBQT形式への保存手順までを網羅しています。

この記事を読むことで、手間のかかる環状ペプチドのライブラリ作成を自動化し、より高度なin silico創薬シミュレーションへスムーズに移行できるようになります。

動作検証済み環境

動作検証済み環境

Google Colab

ライブラリとは?


ペプチドライブラリは、さまざまな配列を持つペプチドの集合で、in silico創薬においては特定の標的タンパク質に対する結合能を評価するために使用されます。スクリーニングでは、各ペプチドの3D構造を予測し、ドッキングや分子動力学シミュレーションを用いて、結合エネルギーや安定性を比較します。多様な配列を効率的に評価するため、バッチ処理・自動化が重要です。

HELM形式とは?


HELM(Hierarchical Editing Language for Macromolecules)は、ペプチド、核酸、糖鎖などの複雑な生体高分子を機械可読な形式で表現するための標準フォーマットです。特にin silico創薬やバイオライブラリのデータ管理で重要な役割を担います。

特徴:

  • モノマー単位で階層的に記述(アミノ酸やヌクレオチドが基本単位)
  • 非天然アミノ酸・化学修飾・分岐構造も記述可能
  • 構造の一貫性や相互運用性を保ちながら、データベースやツール間で利用可能

ペプチドの基本構文

PEPTIDE1{A.C.G.Y.R}$$$$
  • PEPTIDE1: 分子の種類(ここではペプチド)
  • {}: アミノ酸配列(モノマーコード)
  • $$$$: 接続や末端の情報がない場合の終端記号

非天然アミノ酸の表現

HELMでは、非天然アミノ酸もカスタムモノマーとして表現できます。モノマー辞書に登録すれば自由な名前で記述可能です。

PEPTIDE1{A.Dap.Cit.Nle}$$$$
  • Dap: 2,3-ジアミノプロピオン酸
  • Cit: シトルリン
  • Nle: ノルロイシン

これらはすべて非天然(standard amino acid ではない)ですが、辞書に定義しておけば扱えます。こちらを使った方法についてはまた別記事で書きます。今回は天然アミノ酸に絞ります。


環状ペプチドの記述

環状構造は末端をリンクで接続することで表現します。たとえば、1番目と5番目をペプチド結合で環化する場合:

PEPTIDE1{A.C.G.D.E}$$$V2.0$$$PEPTIDE1,1:R3-5:R2$$
  • PEPTIDE1,1:R3-5:R2: モノマー1のR3とモノマー5のR2を結合(N-C末端環化など)

この記述により、主鎖環状ペプチド(例:シクロスポリンなど)も構造的に正確に表現できます。

アラニンスキャニング、ホモログスキャニングとは?


アラニンスキャニング(Alanine Scanning)

アラニンスキャニングは、タンパク質やペプチドの特定残基をアラニンに一つずつ置換し、その機能や結合能への影響を評価する手法です。アラニンは小さく中性なため、置換によって立体構造の変化を最小限に抑えつつ、その残基の役割を明らかにできます。in silicoでは、各変異体の結合エネルギー(ΔΔG)を計算することで、重要な結合残基(ホットスポット)を同定できます。M

ホモログスキャニング(Homologue Scanning)

ホモログスキャニングは、特定の残基をアミノ酸の中で物理化学的に近い他の残基に置換し、機能や安定性への影響を調べる方法です。たとえばリジンをアルギニンやヒスチジンに、フェニルアラニンをチロシンに変えるなど、類似性を保った変異を試みます。アラニンスキャニングよりもより自然に近い変異探索ができるため、機能改変や最適化設計に適しています。

どちらもin silicoでのスクリーニングにより、実験前の候補絞り込みタンパク質改変戦略の立案に活用されます。

環境構築


今回のコードはGoogle Colabで実装しました!

こちらから実行してみてください。環境構築は不要です。

上のランタイムすべてのセルを実行で実行できます

実装コード


全コードはこちら

!pip install rdkit py3Dmol
!pip install meeko
!pip install gemmi
import rdkit
from rdkit import Chem
from rdkit.Chem import AllChem
import py3Dmol
from typing import List
import re
# 必要なライブラリをインポートしています
# rdkit: 化学構造の操作や3D生成を行うためのライブラリ
# py3Dmol: 分子の3D構造をブラウザ上で可視化するためのライブラリ
# re: 正規表現を使って文字列処理を行うための標準ライブラリ
# --- Helper Functions (補助関数) ---
def convert_FASTA_to_HELM(seq: str, cyclic: bool = True) -> List[str]: """ FASTA形式の配列(例: 'ACDEF')をHELM形式(階層的編集言語)に変換する関数です。 cyclic=True の場合、先頭と末尾を結合して環状ペプチドにします(バックボーン環化)。 """ # 1. 配列の文字をドット区切りにします(例: H.M.T...) polymer = ".".join(list(seq)) # PEPTIDE1という名前のポリマーとして定義します helm = f"PEPTIDE1{{{polymer}}}" if cyclic: # 2. 環状化の処理 # N末端(R1)とC末端(R2)を結合させる記述を追加します n = len(seq) # 接続の構文: SourcePoly,TargetPoly,SourceAtom:Att-TargetAtom:Att connection = f"PEPTIDE1,PEPTIDE1,1:R1-{n}:R2" helm += f"${connection}$$$$" else: # 環状化しない場合は終了記号のみ追加 helm += "$$$$" return [helm]
def parse_helm_to_seq(helm: str) -> str: """HELM文字列からアミノ酸配列のみを抽出する関数です。""" # 正規表現を使って PEPTIDE1{...} の中身を取り出します match = re.search(r'PEPTIDE1\{(.*?)\}', helm) if match: # ドットを取り除いて文字列として返します(例: H.M.T -> HMT) return match.group(1).replace('.', '') return ""
def alanine_scanning(helm_str: str) -> List[str]: """ アラニンスキャニングを行う関数です。 ペプチドの各アミノ酸を1つずつアラニン(A)に置換した変異体を作成します。 特定のアミノ酸が活性に重要かどうかを調べるためによく使われます。 """ seq = parse_helm_to_seq(helm_str) variants = [] for i in range(len(seq)): # 元々がアラニンの場合はスキップ if seq[i] == 'A': continue # i番目のアミノ酸を'A'に置き換えた新しい配列を作成 new_seq = seq[:i] + 'A' + seq[i+1:] # HELM形式に変換してリストに追加 variants.append(convert_FASTA_to_HELM(new_seq)[0]) return variants
def homolog_scanning(helm_str: str) -> List[str]: """ ホモログスキャニングを行う関数です。 各アミノ酸を、性質が似ている別のアミノ酸(ホモログ)に置換した変異体を作成します。 """ seq = parse_helm_to_seq(helm_str) # 置換ルール(辞書): キーのアミノ酸を、値のリストにあるアミノ酸に置換します homologs = { 'H': ['K', 'R'], 'K': ['R', 'H'], 'R': ['K', 'H'], # 塩基性アミノ酸間での置換 'D': ['E'], 'E': ['D'], # 酸性アミノ酸間 'N': ['Q'], 'Q': ['N'], # アミド基を持つもの同士 'S': ['T'], 'T': ['S'], # 水酸基を持つもの同士 'V': ['I', 'L'], 'L': ['I', 'V'], 'I': ['L', 'V'], # 疎水性アミノ酸間 'F': ['Y'], 'Y': ['F'], # 芳香族アミノ酸間 'A': ['G'], 'G': ['A'], # 小さいアミノ酸間 'M': ['L'] } variants = [] for i in range(len(seq)): aa = seq[i] # そのアミノ酸に対する置換ルールが存在する場合 if aa in homologs: for sub in homologs[aa]: # 置換して新しい配列を作成 new_seq = seq[:i] + sub + seq[i+1:] variants.append(convert_FASTA_to_HELM(new_seq)[0]) return variants
def helm_to_3d_mol(helm_str: str): """ HELM文字列をRDKitの分子オブジェクト(3D構造込み)に変換する関数です。 RDKitを使って直鎖ペプチドを作成し、化学的に結合させて環状にします。 """ # 1. 配列情報を取得 seq = parse_helm_to_seq(helm_str) if not seq: return None # 2. 配列から直鎖状のペプチド分子を作成 mol = Chem.MolFromSequence(seq) if mol is None: return None # 3. 環状化(Head-to-Tail cyclization)の処理 # 分子を編集可能な状態(RWMol)にします rwmol = Chem.RWMol(mol) # N末端(アミノ基)とC末端(カルボキシ基)の原子を探します # SMARTS記法というパターンマッチングを使っています n_matches = rwmol.GetSubstructMatches(Chem.MolFromSmarts("[NH2,NH3]")) # N末端 c_matches = rwmol.GetSubstructMatches(Chem.MolFromSmarts("C(=O)[OH]")) # C末端 if not n_matches or not c_matches: print(f"Could not identify termini for {seq}") return None # N末端の窒素原子のインデックス n_atom_idx = n_matches[0][0] # C末端の炭素原子と、脱離するOH基の酸素原子を特定します c_term_indices = c_matches[-1] # 最後に見つかったものをC末端と仮定 c_atom_idx = -1 leaving_o_idx = -1 for idx in c_term_indices: atom = rwmol.GetAtomWithIdx(idx) if atom.GetSymbol() == 'C': # 炭素に結合している酸素(OH)を探す for bond in atom.GetBonds(): neighbor = bond.GetOtherAtom(atom) if neighbor.GetSymbol() == 'O' and bond.GetBondType() == Chem.BondType.SINGLE: c_atom_idx = idx leaving_o_idx = neighbor.GetIdx() break if c_atom_idx != -1: break # ペプチド結合の形成(脱水縮合のシミュレーション) if c_atom_idx != -1 and leaving_o_idx != -1: # OH基を削除 rwmol.RemoveAtom(leaving_o_idx) # N末端のNとC末端のCを単結合でつなぐ rwmol.AddBond(n_atom_idx, c_atom_idx, Chem.BondType.SINGLE) # 編集を確定して通常の分子オブジェクトに戻す mol_cyclic = rwmol.GetMol() try: # 化学的な整合性をチェック Chem.SanitizeMol(mol_cyclic) # 水素原子を付加(3D構造生成に必要) mol_h = Chem.AddHs(mol_cyclic) # 4. 3Dコンフォマー(立体構造)の生成 # ETKDGというアルゴリズムを使って3D座標を計算します AllChem.EmbedMolecule(mol_h, AllChem.ETKDG()) return mol_h except Exception as e: print(f"Error generating 3D for {seq}: {e}") return None return None
# ----------------------------------------------------
# STEP 1: リードペプチドの定義
# ----------------------------------------------------
# ここでは探索の起点となるペプチド配列(リードペプチド)を定義します。
# FASTA形式('HMTEVVRRC')からツールで扱いやすいHELM形式に変換しています。
lead_peptide = convert_FASTA_to_HELM('HMTEVVRRC')[0]
print(f"リードペプチド(HELM形式): {lead_peptide}")
# ----------------------------------------------------
# STEP 2: シードライブラリの生成
# ----------------------------------------------------
# リードペプチドを元に、少しだけ配列を変えたペプチド群(ライブラリ)を作ります。
seed_library = [lead_peptide]
# アラニンスキャニング: 各アミノ酸をアラニンに変えたものを作成
for seq in alanine_scanning(lead_peptide): seed_library.append(seq)
# ホモログスキャニング: 各アミノ酸を似た性質のアミノ酸に変えたものを作成
for seq in homolog_scanning(lead_peptide): seed_library.append(seq) # デモ用に数を制限しています(最大10個追加でストップ) if len(seed_library) >= 10: print('Reach max. number of peptides allowed.') break
print(f"Total peptides generated: {len(seed_library)}")
print("First 5 peptides:")
for p in seed_library[:5]: print(p)
# ----------------------------------------------------
# STEP 3: 3D Visualization (3D可視化)
# ----------------------------------------------------
print("Generating 3D structures for the first 3 peptides...")
# 生成したライブラリの最初の3つだけを可視化してみます
for i, helm in enumerate(seed_library[:3]): print(f"\nPeptide {i+1}: {helm}") # 定義した関数を使ってHELM文字列から3D構造データを生成 mol = helm_to_3d_mol(helm) if mol: # py3Dmolを使ってブラウザ上で分子を表示 view = py3Dmol.view(width=400, height=300) # 分子データを渡す view.addModel(Chem.MolToMolBlock(mol), 'mol') # 表示スタイルをスティック(棒)モデルに設定 view.setStyle({'stick': {}}) # 分子が画面に収まるようにズーム view.zoomTo() view.show() else: print("Failed to create 3D structure.")
# ----------------------------------------------------
# STEP 4: PDBQTファイルの保存
# ----------------------------------------------------
from google.colab import drive
import os
# Google Driveをマウント(接続)します。
# これにより、作成したデータを自分のDriveに保存できるようになります。
drive.mount('/content/drive')
# 出力先のディレクトリ(フォルダ)パスを定義します
output_dir = '/content/drive/MyDrive/Cyclic_peptide_screening'
# ディレクトリが存在しない場合は作成します(exist_ok=Trueで既存の場合のエラーを回避)
os.makedirs(output_dir, exist_ok=True)
print(f"Output directory created/verified at: {output_dir}")
from meeko import MoleculePreparation
from rdkit import Chem
import requests
def save_mol_to_pdbqt(mol, name, output_dir): """ RDKitの分子オブジェクトをPDBQT形式で保存する関数です。 PDBQTはドッキングシミュレーション(AutoDockなど)で使われる形式です。 """ try: # Meekoを使って分子の前処理(プレパレーション)を行います # これにより、結合の回転などを設定したPDBQTデータが作られます preparator = MoleculePreparation() preparator.prepare(mol) pdbqt_string = preparator.write_pdbqt_string() # ファイルとして保存 filename = os.path.join(output_dir, f"{name}.pdbqt") with open(filename, 'w') as f: f.write(pdbqt_string) return True except Exception as e: print(f"Error converting {name}: {e}") return False
print("Starting PDBQT conversion for peptide library...")
success_count = 0
# ライブラリ内の全ペプチドについて処理を実行します
for i, helm in enumerate(seed_library): # ファイル名用に配列を取得 seq_name = parse_helm_to_seq(helm) base_name = seq_name if seq_name else f"peptide_{i+1:03d}" name = f"Cyclic_{base_name}" # 3D構造を生成 mol = helm_to_3d_mol(helm) if mol: # 分子に名前プロパティを追加 mol.SetProp("_Name", name) # PDBQT形式で保存 if save_mol_to_pdbqt(mol, name, output_dir): success_count += 1 else: print(f"Failed to save {name}") else: print(f"Failed to generate 3D for {name} ({helm})")
print(f"\nSuccessfully saved {success_count}/{len(seed_library)} peptides to {output_dir}") 

コード詳細解説


!pip install rdkit py3Dmol
!pip install meeko
!pip install gemmi
import rdkit
from rdkit import Chem
from rdkit.Chem import AllChem
import py3Dmol
from typing import List
import re

まずは、以下のように必要なライブラリをインストールします。

!pip install rdkit py3Dmol
  • rdkit:分子構造の読み込み、編集、描画、化学構造に基づく演算(化学フラグメント検索、構造変換など)を行う強力なライブラリ。
  • py3Dmol:3D分子構造をWebベースで可視化するためのインターフェース。3Dmol.js というJavaScriptライブラリをPythonから操作できるようにしたもの。

💡 rdkit は in silico創薬やQSAR解析で頻繁に使われる定番ライブラリです。


!pip install meeko
  • meeko:AutoDock Vinaの前処理ツールである prepare_ligand を Python で扱うためのラッパー。
  • リガンドのフォーマット変換やプロトン化状態の調整、トーションの指定など、分子ドッキング前の処理が行えます。

!pip install gemmi
  • gemmi:結晶構造(PDB / mmCIF)ファイルを高速かつ正確に読み書きできるバイオインフォマティクスライブラリ。
  • pdb構造の取り扱い電子密度マップとの連携にも強く、研究現場での使い勝手が高いです。

モジュールのインポート

次に、インストールしたライブラリをインポートしていきます。

import rdkit
from rdkitimport Chem
from rdkit.Chemimport AllChem
  • rdkit: ライブラリ全体のベース。
  • Chem: 分子(Molオブジェクト)の読み書き、構造の基本操作に使います。
  • AllChem: 3D座標の付加(構造最適化や立体構造生成)や部分構造検索、化学反応の定義など、より高度な機能を提供。
import py3Dmol
  • py3Dmol: 3D構造をWeb上でインタラクティブに可視化するためのライブラリ。
from typingimportList
  • typing モジュールの List は、関数やクラスで**リストの型注釈(型ヒント)**を与えるために使います。

    defprocess_molecules(mols: List[str]):
import re
  • re は **正規表現(regex)**モジュールで、文字列の検索・抽出・置換などができます。
    • 例えば、分子名からIDや化合物情報を抽出する場面で活躍します。

関数の定義

# --- Helper Functions (補助関数) ---
def convert_FASTA_to_HELM(seq: str, cyclic: bool = True) -> List[str]: """ FASTA形式の配列(例: 'ACDEF')をHELM形式(階層的編集言語)に変換する関数です。 cyclic=True の場合、先頭と末尾を結合して環状ペプチドにします(バックボーン環化)。 """ # 1. 配列の文字をドット区切りにします(例: H.M.T...) polymer = ".".join(list(seq)) # PEPTIDE1という名前のポリマーとして定義します helm = f"PEPTIDE1{{{polymer}}}" if cyclic: # 2. 環状化の処理 # N末端(R1)とC末端(R2)を結合させる記述を追加します n = len(seq) # 接続の構文: SourcePoly,TargetPoly,SourceAtom:Att-TargetAtom:Att connection = f"PEPTIDE1,PEPTIDE1,1:R1-{n}:R2" helm += f"${connection}$$$$" else: # 環状化しない場合は終了記号のみ追加 helm += "$$$$" return [helm]
def parse_helm_to_seq(helm: str) -> str: """HELM文字列からアミノ酸配列のみを抽出する関数です。""" # 正規表現を使って PEPTIDE1{...} の中身を取り出します match = re.search(r'PEPTIDE1\{(.*?)\}', helm) if match: # ドットを取り除いて文字列として返します(例: H.M.T -> HMT) return match.group(1).replace('.', '') return ""
def alanine_scanning(helm_str: str) -> List[str]: """ アラニンスキャニングを行う関数です。 ペプチドの各アミノ酸を1つずつアラニン(A)に置換した変異体を作成します。 特定のアミノ酸が活性に重要かどうかを調べるためによく使われます。 """ seq = parse_helm_to_seq(helm_str) variants = [] for i in range(len(seq)): # 元々がアラニンの場合はスキップ if seq[i] == 'A': continue # i番目のアミノ酸を'A'に置き換えた新しい配列を作成 new_seq = seq[:i] + 'A' + seq[i+1:] # HELM形式に変換してリストに追加 variants.append(convert_FASTA_to_HELM(new_seq)[0]) return variants
def homolog_scanning(helm_str: str) -> List[str]: """ ホモログスキャニングを行う関数です。 各アミノ酸を、性質が似ている別のアミノ酸(ホモログ)に置換した変異体を作成します。 """ seq = parse_helm_to_seq(helm_str) # 置換ルール(辞書): キーのアミノ酸を、値のリストにあるアミノ酸に置換します homologs = { 'H': ['K', 'R'], 'K': ['R', 'H'], 'R': ['K', 'H'], # 塩基性アミノ酸間での置換 'D': ['E'], 'E': ['D'], # 酸性アミノ酸間 'N': ['Q'], 'Q': ['N'], # アミド基を持つもの同士 'S': ['T'], 'T': ['S'], # 水酸基を持つもの同士 'V': ['I', 'L'], 'L': ['I', 'V'], 'I': ['L', 'V'], # 疎水性アミノ酸間 'F': ['Y'], 'Y': ['F'], # 芳香族アミノ酸間 'A': ['G'], 'G': ['A'], # 小さいアミノ酸間 'M': ['L'] } variants = [] for i in range(len(seq)): aa = seq[i] # そのアミノ酸に対する置換ルールが存在する場合 if aa in homologs: for sub in homologs[aa]: # 置換して新しい配列を作成 new_seq = seq[:i] + sub + seq[i+1:] variants.append(convert_FASTA_to_HELM(new_seq)[0]) return variants
def helm_to_3d_mol(helm_str: str): """ HELM文字列をRDKitの分子オブジェクト(3D構造込み)に変換する関数です。 RDKitを使って直鎖ペプチドを作成し、化学的に結合させて環状にします。 """ # 1. 配列情報を取得 seq = parse_helm_to_seq(helm_str) if not seq: return None # 2. 配列から直鎖状のペプチド分子を作成 mol = Chem.MolFromSequence(seq) if mol is None: return None # 3. 環状化(Head-to-Tail cyclization)の処理 # 分子を編集可能な状態(RWMol)にします rwmol = Chem.RWMol(mol) # N末端(アミノ基)とC末端(カルボキシ基)の原子を探します # SMARTS記法というパターンマッチングを使っています n_matches = rwmol.GetSubstructMatches(Chem.MolFromSmarts("[NH2,NH3]")) # N末端 c_matches = rwmol.GetSubstructMatches(Chem.MolFromSmarts("C(=O)[OH]")) # C末端 if not n_matches or not c_matches: print(f"Could not identify termini for {seq}") return None # N末端の窒素原子のインデックス n_atom_idx = n_matches[0][0] # C末端の炭素原子と、脱離するOH基の酸素原子を特定します c_term_indices = c_matches[-1] # 最後に見つかったものをC末端と仮定 c_atom_idx = -1 leaving_o_idx = -1 for idx in c_term_indices: atom = rwmol.GetAtomWithIdx(idx) if atom.GetSymbol() == 'C': # 炭素に結合している酸素(OH)を探す for bond in atom.GetBonds(): neighbor = bond.GetOtherAtom(atom) if neighbor.GetSymbol() == 'O' and bond.GetBondType() == Chem.BondType.SINGLE: c_atom_idx = idx leaving_o_idx = neighbor.GetIdx() break if c_atom_idx != -1: break # ペプチド結合の形成(脱水縮合のシミュレーション) if c_atom_idx != -1 and leaving_o_idx != -1: # OH基を削除 rwmol.RemoveAtom(leaving_o_idx) # N末端のNとC末端のCを単結合でつなぐ rwmol.AddBond(n_atom_idx, c_atom_idx, Chem.BondType.SINGLE) # 編集を確定して通常の分子オブジェクトに戻す mol_cyclic = rwmol.GetMol() try: # 化学的な整合性をチェック Chem.SanitizeMol(mol_cyclic) # 水素原子を付加(3D構造生成に必要) mol_h = Chem.AddHs(mol_cyclic) # 4. 3Dコンフォマー(立体構造)の生成 # ETKDGというアルゴリズムを使って3D座標を計算します AllChem.EmbedMolecule(mol_h, AllChem.ETKDG()) return mol_h except Exception as e: print(f"Error generating 3D for {seq}: {e}") return None return None

ぺプチドライブラリのスクリーニングや構造最適化でよく使われる補助関数群を紹介します。特に以下のような作業を自動化できます:

  • ✅ FASTA形式のアミノ酸配列 → HELM形式への変換
  • ✅ アラニンスキャニング・ホモログスキャニングの自動化
  • ✅ HELM構造からの3D分子生成(RDKit使用)

in silico 創薬やペプチド設計の現場で、高速にスクリーニング候補を生成・検討するための便利ツール群です。


1. convert_FASTA_to_HELM: FASTA配列 → HELM形式へ変換

def convert_FASTA_to_HELM(seq: str, cyclic:bool =True) ->List[str]:
  • FASTA形式(例: "ACDEFGHIK")を、HELM形式(例: PEPTIDE1{A.C.D.E.F.G.H.I.K}$PEPTIDE1,PEPTIDE1,1:R1-9:R2$$$$)に変換する関数です。
  • cyclic=True にすると、**環状ペプチド(ヘッド・トゥ・テール環化)**になります。

2. parse_helm_to_seq: HELM文字列 → アミノ酸配列抽出

def parse_helm_to_seq(helm: str) ->str:
  • HELM形式の中身から、アミノ酸配列部分(例: "ACD")だけを取り出す関数です。
  • 正規表現で PEPTIDE1{...} の中身を抽出 → "A.C.D""ACD" に変換します。

3. alanine_scanning: アラニンスキャニング

def alanine_scanning(helm_str: str) ->List[str]:
  • 各アミノ酸を アラニン(A)に1つずつ置換 した HELM 配列のリストを生成します。
  • アラニンスキャニングは、活性に重要な残基の特定に有効です(SAR解析など)。

例:

元:HELM(ACD) →[A→A, C→A, D→A]
結果:[AAD, AAD, ACA]

4. homolog_scanning: ホモログスキャニング

def homolog_scanning(helm_str: str) ->List[str]:
  • 各アミノ酸を**性質の似たアミノ酸(ホモログ)**に置き換えたバリエーションを生成します。
  • 例えば、K(リジン)R(アルギニン) に置換、といった操作です。

置換辞書は生理化学的性質に基づいています:

'K': ['R','H'],# 塩基性アミノ酸間
'F': ['Y'],# 芳香族アミノ酸間
...

5. helm_to_3d_mol: HELM文字列 → RDKitで3D構造生成

defhelm_to_3d_mol(helm_str: str):

この関数は、次の処理をステップバイステップで行います:

▶ 処理の流れ

  1. HELM → アミノ酸配列抽出
  2. 配列から直鎖ペプチドを生成Chem.MolFromSequence
  3. N末端とC末端の原子を検出
  4. 脱水縮合(OH削除+N-C結合)により環化
  5. Sanitize(分子構造チェック)+水素追加
  6. 3D構造生成(ETKDGアルゴリズム使用)

✅ 出力

  • 成功すれば Mol オブジェクト(3D座標付き)
  • 可視化には py3Dmolrdkit.Chem.Draw.MolToImage が使えます。

STEP 1: リードペプチドの定義

# ----------------------------------------------------
# STEP 1: リードペプチドの定義
# ----------------------------------------------------
# ここでは探索の起点となるペプチド配列(リードペプチド)を定義します。
# FASTA形式('HMTEVVRRC')からツールで扱いやすいHELM形式に変換しています。
lead_peptide = convert_FASTA_to_HELM('HMTEVVRRC')[0]
print(f"リードペプチド(HELM形式): {lead_peptide}")

このステップでやっていること

  • 入力:リードペプチドの配列 'HMTEVVRRC'(FASTA形式)
  • 処理convert_FASTA_to_HELM 関数を使って、HELM形式 に変換
  • 出力:環状ペプチドを表す HELM 文字列

なぜHELM形式に変換するのか?

HELM(Hierarchical Editing Language for Macromolecules)は、以下の理由でペプチドや核酸の表現に適した形式です:

  • 修飾残基や環状構造を正確に記述できる
  • 分子設計ツール(Schrödinger、BioViaなど)と互換性が高い
  • 配列ベースと構造ベースを統合した記述が可能

変換の例

FASTA:'HMTEVVRRC'
↓
HELM: PEPTIDE1{H.M.T.E.V.V.R.R.C}$PEPTIDE1,PEPTIDE1,1:R1-9:R2$$$$
  • .join(list(seq)) により、アミノ酸がドット(.)で区切られる
  • 1:R1-9:R2 は、1番目と9番目の残基の末端(R1, R2)を結合 → 環状ペプチド化

STEP 2: シードライブラリの生成

# ----------------------------------------------------
# STEP 2: シードライブラリの生成
# ----------------------------------------------------
# リードペプチドを元に、少しだけ配列を変えたペプチド群(ライブラリ)を作ります。
seed_library = [lead_peptide]
# アラニンスキャニング: 各アミノ酸をアラニンに変えたものを作成
for seq in alanine_scanning(lead_peptide): seed_library.append(seq)
# ホモログスキャニング: 各アミノ酸を似た性質のアミノ酸に変えたものを作成
for seq in homolog_scanning(lead_peptide): seed_library.append(seq) # デモ用に数を制限しています(最大10個追加でストップ) if len(seed_library) >= 10: print('Reach max. number of peptides allowed.') break
print(f"Total peptides generated: {len(seed_library)}")
print("First 5 peptides:")
for p in seed_library[:5]: print(p)

このステップでは、STEP 1 で定義したリードペプチドを基にして、構造が少しだけ異なるペプチド群(変異体)を自動で生成します。

seed_library = [lead_peptide]
  • seed_library というリストを作成し、まずは元のリードペプチド(HELM形式)を追加します。

アラニンスキャニング(alanine_scanning)

for seqin alanine_scanning(lead_peptide): seed_library.append(seq)
  • 各アミノ酸を1つずつ アラニン(A) に置換して、活性に重要な残基を探索するための変異体を生成します。
  • 例えば、HMTEVVRRC の中で MA となると、HATEVVRRC のような変異が作られます。

🧪 研究応用:

アラニンスキャニングは、機能性アミノ酸(酵素活性部位や結合ポケットなど)を特定するための標準的な手法です。


ホモログスキャニング(homolog_scanning)

for seqin homolog_scanning(lead_peptide): seed_library.append(seq)
iflen(seed_library) >=10:
print('Reach max. number of peptides allowed.')
break
  • 各アミノ酸を、性質が似ている別のアミノ酸に置換します(例:H → KF → Y)。
  • 生理化学的性質が近いので、構造や機能を大きく損なわずにバリエーションを広げられます。
  • このコードでは、生成する変異体の数を最大10個に制限しています(チュートリアル用の簡易実装)。

🧪 研究応用:

ホモログスキャニングは、構造保存的な最適化進化的な置換可能性の評価に役立ちます。


結果の確認

print(f"Total peptides generated: {len(seed_library)}")
print("First 5 peptides:")
for pin seed_library[:5]:
print(p)
  • 作成したペプチドライブラリの個数を出力し、先頭5件の HELM 表現を表示します。

実行例(出力)

Total peptidesgenerated:10
First5peptides:
PEPTIDE1{H.M.T.E.V.V.R.R.C}$PEPTIDE1,PEPTIDE1,1:R1-9:R2$$$$
PEPTIDE1{A.M.T.E.V.V.R.R.C}$PEPTIDE1,PEPTIDE1,1:R1-9:R2$$$$
PEPTIDE1{H.A.T.E.V.V.R.R.C}$PEPTIDE1,PEPTIDE1,1:R1-9:R2$$$$
PEPTIDE1{H.M.A.E.V.V.R.R.C}$PEPTIDE1,PEPTIDE1,1:R1-9:R2$$$$
PEPTIDE1{H.M.T.A.V.V.R.R.C}$PEPTIDE1,PEPTIDE1,1:R1-9:R2$$$$

STEP 3: 3D Visualization (3D可視化)

# ----------------------------------------------------
# STEP 3: 3D Visualization (3D可視化)
# ----------------------------------------------------
print("Generating 3D structures for the first 3 peptides...")
# 生成したライブラリの最初の3つだけを可視化してみます
for i, helm in enumerate(seed_library[:3]): print(f"\nPeptide {i+1}: {helm}") # 定義した関数を使ってHELM文字列から3D構造データを生成 mol = helm_to_3d_mol(helm) if mol: # py3Dmolを使ってブラウザ上で分子を表示 view = py3Dmol.view(width=400, height=300) # 分子データを渡す view.addModel(Chem.MolToMolBlock(mol), 'mol') # 表示スタイルをスティック(棒)モデルに設定 view.setStyle({'stick': {}}) # 分子が画面に収まるようにズーム view.zoomTo() view.show() else: print("Failed to create 3D structure.")

STEP 3:ペプチドの3D構造を可視化する(py3Dmol)

このステップでは、STEP 2で作成したペプチドライブラリのうち、最初の3つのペプチドについて、立体構造(3D構造)を自動生成し、インタラクティブに可視化します。

print("Generating 3D structures for the first 3 peptides...")

処理の流れ

for i, helminenumerate(seed_library[:3]):
  • 生成済みのペプチドライブラリの先頭3つを対象にループ処理します。

3D構造の生成:helm_to_3d_mol

mol = helm_to_3d_mol(helm)

この関数では以下の処理が行われています:

  1. HELM文字列からアミノ酸配列を抽出(例:H.M.T...HMTEVVRRC
  2. RDKit で直鎖ペプチドを生成
  3. N末端とC末端の結合を模倣して環状構造化
  4. ETKDGアルゴリズムを用いた3D座標生成

ETKDGアルゴリズムとは、分子の3次元構造(3Dコンフォメーション)を生成するための、RDKitで実装された手法のひとつです。正式には「Experimental-Torsion Knowledge Distance Geometry」の略で、距離幾何法(Distance Geometry)をベースに、以下の3要素を統合して高精度な構造生成を実現しています:

  1. 距離幾何法(DG):原子間の距離制約から3D構造を組み立てる数学的手法。
  2. 実験トーション角データ(ET):X線結晶構造などから得られた実験値を学習し、現実的な回転角(torsion angles)を生成に反映。
  3. 立体障害の回避(KDG):原子間の衝突を避け、化学的に自然な配置を目指す。

ETKDGは、SMILESやHELMのような2D構造情報しか持たない分子に、高速かつ現実的な3D構造を付与するための事実上の標準手法です。特に創薬や分子ドッキング、MDシミュレーションの初期構造生成によく用いられます。

  1. 分子の整合性(Sanitize)と水素の付加

✅ 出力:mol は3D構造を持つ RDKit の Mol オブジェクト


3D可視化:py3Dmol

view = py3Dmol.view(width=400, height=300)
view.addModel(Chem.MolToMolBlock(mol),'mol')
view.setStyle({'stick': {}})
view.zoomTo()
view.show()
  • py3DmolWebベースの3D分子可視化ライブラリ3Dmol.jsのPythonラッパー)
  • 分子の表示スタイル(スティックモデルなど)を簡単に切り替え可能
  • Google Colab や Jupyter Notebook 上で インタラクティブに操作可能

🎯 分子の回転・拡大・色変更など、構造理解が格段にしやすくなります


エラーハンドリング

ifnot mol:
print("Failed to create 3D structure.")
  • 環状構造の結合エラーや構造生成に失敗した場合でも、スクリプトが止まらずにエラーメッセージを表示します。
  • 複雑な構造や端の修飾がある場合は、helm_to_3d_mol が失敗することがあります。

実行結果(例)

以下のような環状ペプチドが生成されます!

STEP 4: PDBQTファイルの保存

# ----------------------------------------------------
# STEP 4: PDBQTファイルの保存
# ----------------------------------------------------
from google.colab import drive
import os
# Google Driveをマウント(接続)します。
# これにより、作成したデータを自分のDriveに保存できるようになります。
drive.mount('/content/drive')
# 出力先のディレクトリ(フォルダ)パスを定義します
output_dir = '/content/drive/MyDrive/Cyclic_peptide_screening'
# ディレクトリが存在しない場合は作成します(exist_ok=Trueで既存の場合のエラーを回避)
os.makedirs(output_dir, exist_ok=True)
print(f"Output directory created/verified at: {output_dir}")
from meeko import MoleculePreparation
from rdkit import Chem
import requests
def save_mol_to_pdbqt(mol, name, output_dir): """ RDKitの分子オブジェクトをPDBQT形式で保存する関数です。 PDBQTはドッキングシミュレーション(AutoDockなど)で使われる形式です。 """ try: # Meekoを使って分子の前処理(プレパレーション)を行います # これにより、結合の回転などを設定したPDBQTデータが作られます preparator = MoleculePreparation() preparator.prepare(mol) pdbqt_string = preparator.write_pdbqt_string() # ファイルとして保存 filename = os.path.join(output_dir, f"{name}.pdbqt") with open(filename, 'w') as f: f.write(pdbqt_string) return True except Exception as e: print(f"Error converting {name}: {e}") return False
print("Starting PDBQT conversion for peptide library...")
success_count = 0
# ライブラリ内の全ペプチドについて処理を実行します
for i, helm in enumerate(seed_library): # ファイル名用に配列を取得 seq_name = parse_helm_to_seq(helm) base_name = seq_name if seq_name else f"peptide_{i+1:03d}" name = f"Cyclic_{base_name}" # 3D構造を生成 mol = helm_to_3d_mol(helm) if mol: # 分子に名前プロパティを追加 mol.SetProp("_Name", name) # PDBQT形式で保存 if save_mol_to_pdbqt(mol, name, output_dir): success_count += 1 else: print(f"Failed to save {name}") else: print(f"Failed to generate 3D for {name} ({helm})")
print(f"\nSuccessfully saved {success_count}/{len(seed_library)} peptides to {output_dir}") 

STEP 4:PDBQTファイルの保存(AutoDock用)

このステップでは、STEP 3で生成したペプチドの3D構造を、AutoDock や AutoDock Vina で使える PDBQT形式 に変換し、Google Drive に保存します。


Google Driveとの接続と出力先の設定

from google.colabimport drive
import os
drive.mount('/content/drive')
output_dir ='/content/drive/MyDrive/Cyclic_peptide_screening'
os.makedirs(output_dir, exist_ok=True)
  • drive.mount:Colab と Google Drive を接続します。
  • os.makedirs(..., exist_ok=True):出力フォルダを作成(既にあってもOK)

💡 これで、変換したファイルを 自分のDriveに自動保存できるようになります。


Meeko を使った PDBQT 変換関数の定義

from meekoimport MoleculePreparation
from rdkitimport Chem
def save_mol_to_pdbqt(mol, name, output_dir):

この関数は次の処理を自動で行います:

  1. Meeko を使って RDKit 分子をプレパレーション
  2. 回転可能な結合情報などを含む PDBQT文字列を生成
  3. 指定フォルダに .pdbqt ファイルとして保存

例:

save_mol_to_pdbqt(mol,"Cyclic_HMTEVVRRC","/content/drive/MyDrive/...")

ライブラリ全体のバッチ変換処理

for i, helminenumerate(seed_library): mol = helm_to_3d_mol(helm) ... save_mol_to_pdbqt(mol, name, output_dir)
  • すべてのペプチドに対して helm_to_3d_mol() を使って 3D構造を生成
  • Meeko に渡して .pdbqt 形式で保存

ファイル名は次のようになります:

Cyclic_HMTEVVRRC.pdbqt
Cyclic_AMTEVVRRC.pdbqt
Cyclic_HATEVVRRC.pdbqt
...

実行結果のログ出力

print(f"\nSuccessfully saved {success_count}/{len(seed_library)} peptides to{output_dir}")

例:

Successfully saved10/10 peptidesto /content/drive/MyDrive/Cyclic_peptide_screening
  • 保存に成功した数を表示してくれるため、エラー検出や進捗確認が容易です。

結果


上記のコードが全てrunされると、設定したoutputディレクトリに環状ペプチドライブラリが出力されます!

最後に


今日はHELM形式という形式を使って、環状ペプチドライブラリの作成を行いました!

非天然アミノ酸も設定により、構築可能なので、あらゆるライブラリに対応可能です。

ぜひお望みのライブラリを設定してみてください!次は本ライブラリを使って、スクリーニングを実行します!


The post 【環状ペプチド】In silico screeningのためのin silico環状ペプチドライブラリの構築【in silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/insilico-cyclic-peptide-library/feed/07076
mobiusによるベイジアン最適化を用いたペプチドin silicoスクリーニング【In silico創薬】https://labo-code.com/bioinformatics/insilico-screening-with-mobius/https://labo-code.com/bioinformatics/insilico-screening-with-mobius/#respondSat, 31 Jan 2026 21:50:27 +0000https://labo-code.com/?p=7053

本記事では、mobiusというペプチド最適化ツールとベイズ最適化(Bayesian Optimization, BO)を組み合わせ、すでにアミノ酸変異によって結合力を予測したPSSM(Position-Specific ...

The post mobiusによるベイジアン最適化を用いたペプチドin silicoスクリーニング【In silico創薬】 first appeared on LabCode.

]]>

本記事では、mobiusというペプチド最適化ツールとベイズ最適化(Bayesian Optimization, BO)を組み合わせ、すでにアミノ酸変異によって結合力を予測したPSSM(Position-Specific Scoring Matrix)を用いてMHCクラスI(HLA-A*02:01)に対する結合親和性を向上させるペプチド配列を効率よく探索する方法を紹介します。

PSSMマトリックスを使用した高速な評価により、各ペプチドの結合スコア(pIC50)を取得し、その結果を基にベイズ最適化を実行することで、最も結合親和性の高いペプチド配列を見つけ出します。

【この記事のまとめ】

バイオインフォマティクスや創薬研究に携わるエンジニア・研究者に向けて、Pythonパッケージ「mobius」とベイズ最適化を活用し、標的タンパク質に対して高い結合親和性を持つペプチド配列を効率的に探索・設計する手法を解説します。

  • 膨大な探索空間の克服:5000億通り以上(9残基の場合)存在するペプチド配列の組み合わせから、ベイズ最適化(BO)を用いて「賢く」次候補を選別し、実験・計算コストを劇的に削減する方法を習得できます。
  • 実践的なモデリングフロー:アミノ酸変異による結合力予測(PSSM)とmobiusを組み合わせ、初期ライブラリの生成(アラニンスキャニング等)からDMTサイクル(設計・作成・試験)の自動化までのプロセスを詳述。
  • 高度なカスタマイズ性:HELM記法によるエンコード、分子フィンガープリント(MAP4)を用いたガウス過程モデルの構築など、非標準アミノ酸や複雑な構造制約にも対応可能な最新の設計プロトコルを紹介。

この記事を読むことで、限られたリソースで最適解にたどり着く「データ駆動型ペプチド創薬」の具体的な実装スキルを身につけることができます。

動作検証済み環境

動作検証済み環境

Mac M1, Sequoia 15.6

mobiusとは?

mobiusは、ベイズ最適化(Bayesian Optimization, BO)を用いてペプチド配列を最適化するためのPythonパッケージです。完全自動化されたDesign-Make-Test(DMT)サイクルの中で、ペプチドの設計と最適化を支援します。

mobiusの主な特徴は以下の通りです。

  • 単一または複数の目的関数の最適化(制約条件付き)
  • 線形および非線形ペプチド配列のサポート(マクロ環状、ラッソ、分岐など)
  • 非標準アミノ酸残基と修飾のサポート
  • デザインプロトコルによる配列最適化のカスタマイズ
  • 独自の分子表現(フィンガープリント、グラフカーネル、GNNなど)の拡張が容易
  • 他のツールとの統合(ドッキング、pyRosetta、Damietta、AlphaFoldなど)

今回は、mobiusのチュートリアルを参考にしつつ、PSSMマトリックスを使用した高速な評価を行う実装を行います。

MHCクラスI(HLA-A*02:01)に対する結合親和性を最適化するペプチド配列を、初期のリードペプチドからアラニンスキャニングホモログスキャニングで96個のペプチドを生成し、それぞれをPSSMマトリックスで評価した後、ベイズ最適化を設定してDMTサイクルを実行し、最も結合親和性の高いペプチド配列とその結合スコアを見つけ出す過程を追っていきます。

ベイズ最適化(Bayesian Optimization)とは?


ベイズ最適化(BO)は、機械学習の一種で、「評価コストが高い関数(実験やシミュレーション)において、どの入力(今回はペプチド配列)を優先的に評価すれば、最も効率よく最適解にたどり着けるか?」を自律的に判断する手法です。

問題設定

ペプチド配列は20種類のアミノ酸から構成され、9残基のペプチドの場合、理論上は20^9 = 5120億通りもの組み合わせがあります。すべてを実験で評価するのは不可能です。

ベイズ最適化の考え方

「賢く選んで、少ない実験回数で最適解を見つける」手法です。

1. 探索と活用のバランス

  • 探索(Exploration): まだ試していない領域を調べる
  • 活用(Exploitation): これまでに良い結果が出た領域を詳しく調べる
  • この2つをバランスよく行うことで、効率的に最適解に近づきます

2. 予測モデル(ガウス過程)

  • 既に評価したペプチドのデータから、未評価のペプチドのスコアを予測します
  • 「このペプチドは良いスコアが出そう」という予測値と、「この予測はどれくらい確実か」という不確実性の両方を提供します

3. 獲得関数(次に何を試すか決める)

  • 予測値が良いペプチド → 試す価値がある
  • 不確実性が高いペプチド → もしかしたら良い結果が出るかもしれない
  • この2つを組み合わせて、次に評価すべきペプチドを選びます

具体例で理解する

従来の方法(ランダム探索):

1. ランダムに100個のペプチドを選ぶ
2. 全部評価する
3. 最良のものを選ぶ
→ 運が良ければ良い結果、運が悪ければ無駄が多い

ベイズ最適化:

1. 初期に少数(96個)のペプチドを評価
2. データから「良いペプチドの特徴」を学習
3. 学習結果を基に、次に試すべき96個を賢く選ぶ
4. 評価して、さらに学習を更新
5. これを繰り返す
→ 少ない評価回数で、より良い結果に到達

BOの役割は以下の通りです。

  1. 初期評価(シードライブラリの生成): まず少数のペプチドを配列ベースの戦略(アラニンスキャニング、ホモログスキャニングなど)で選び、PSSMマトリックスによりその結合親和性(pIC50スコア)を計算(評価)します。
  2. 代理モデルの構築: 評価結果を基に、未評価のペプチド群のスコア(結合親和性)を予測する機械学習モデル(ガウス過程など)を構築します。
  3. 獲得関数に基づく選択: 代理モデルの予測結果から、「最もスコアが良さそう(pIC50スコアが低そう)」または「予測の不確実性が高く、評価すればモデルが大きく改善しそう」なペプチドを、獲得関数(Acquisition Function)を使って優先的に選択します。
  4. 再評価と学習: 選択したペプチドをPSSMマトリックスで実際に評価し、その結果(pIC50スコア)を代理モデルにフィードバック(学習)させることで、モデルの予測精度を向上させます。

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

mobiusは、このBOの仕組みを、ペプチドの設計・評価プロセスに組み込むことを可能にしています。

環境構築


installationの資料はこちら

注意: mobiusは、ガウス過程モデルやグラフニューラルネットワークなどの機械学習モデルを使用するため、GPUがあると計算が大幅に高速化されます。本記事ではCPUのみを使用した実装を行いますが、大規模な最適化を行う場合はGPUの使用を推奨します。GPUを使用する場合は、Linux環境でCUDA対応のPyTorchをインストールしてください。

Miniforge3のインストール

まず、Miniforge3をインストールします(既にインストール済みの場合はスキップしてください)。

# Miniforge3インストーラをダウンロード
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を有効化# macOS (zsh) の場合eval "$(~/miniforge3/bin/conda shell.zsh hook)"
conda init zsh
source ~/.zshrc
# Linux (bash) の場合eval "$(~/miniforge3/bin/conda shell.bash hook)"
conda init bash
source ~/.bashrc

mobiusのセットアップ

  1. mobiusリポジトリのクローン
git clone https://git.scicore.unibas.ch/schwede/mobius.git
cd mobius
  1. 環境ファイルのダウンロード

以下の環境ファイルをダウンロードして、mobiusディレクトリに配置してください。

CPU版(macOS ARM64)environment_cpu.yaml (クローンしたものの中にあるenvironmental.yamlで環境構築もOKですが、私のPCではうまくいかなかったので、修正してます。)

  1. 仮想環境の作成
# CPU版を使用する場合(macOS ARM64 / Apple Silicon)
mamba env create -f environment_cpu.yaml -n mobius
  1. 環境のアクティベートとmobiusのインストール
#eval "$(~/miniforge3/bin/mamba shell hook --shell zsh)"
# 環境をアクティベート
mamba activate mobius

注意:

  • mambaがインストールされていない場合は、conda install mamba -n base -c conda-forge -yでインストールしてください。
  • 新しいターミナルを開いた場合は、mamba activate mobiusの前にeval "$(~/miniforge3/bin/mamba shell hook --shell zsh)"(zshの場合)またはeval "$(~/miniforge3/bin/mamba shell hook --shell bash)"(bashの場合)を実行してください。

データの準備

MHCクラスIのPSSMファイルが必要です。mobiusリポジトリには、IEDB(Immune Epitope Database)から取得したPSSMファイルが含まれています。

PSSMファイルについて:

  • PSSM(Position-Specific Scoring Matrix:位置特異的スコアリングマトリックス)は、ペプチドの各位置に各アミノ酸が現れる際のスコアを表すマトリックスです。

以下のような構造をしています。

NumCols:	8
A	-0.055	-0.024	-0.007	-0.261	0.237	-0.045	-0.050	-0.007
C	0.003	0.085	-0.018	-0.371	0.048	0.005	0.009	-0.020
D	-0.006	-0.195	0.029	0.119	-0.494	-0.022	0.017	-0.010
E	-0.015	-0.099	0.009	0.036	-0.098	0.008	0.012	-0.005
F	0.011	0.304	-0.064	-0.506	0.018	0.100	0.104	-0.091
G	0.002	0.036	0.009	0.014	-0.912	-0.010	-0.040	-0.007
H	0.023	-0.052	0.015	0.205	-0.566	-0.034	-0.014	-0.028
I	-0.004	0.146	-0.056	-0.143	0.312	0.122	0.095	0.098
K	0.018	0.084	0.048	0.233	-0.040	-0.014	-0.040	0.058
L	-0.019	0.303	-0.026	-0.218	0.240	0.074	0.057	0.042
M	-0.005	0.127	-0.039	0.067	-0.083	0.039	0.049	0.028
N	-0.002	-0.148	0.039	0.095	0.075	-0.057	-0.032	-0.007
P	-0.015	0.158	0.070	-0.024	0.005	-0.019	-0.139	0.026
Q	-0.003	-0.041	0.031	0.128	-0.040	-0.031	-0.061	0.036
R	0.019	0.107	0.042	0.369	0.236	-0.035	-0.084	0.007
S	0.001	-0.597	0.007	0.350	0.333	-0.101	-0.055	0.020
T	-0.000	-0.411	0.011	0.170	0.201	-0.053	-0.016	0.015
V	-0.006	-0.091	-0.020	-0.085	0.480	0.045	0.045	0.048
W	0.034	0.054	-0.034	-0.130	0.017	0.023	0.057	-0.056
Y	0.020	0.255	-0.047	-0.048	0.032	0.005	0.086	-0.146
Intercept	4.52761

「8つの位置のそれぞれに、どのアミノ酸が好まれるか」を数値化したものです。

行は20種類のアミノ酸、列はペプチドの位置(1〜8)を表します。

各数値は その位置にそのアミノ酸が入ったときの寄与スコア を意味し、

  • プラス(+) → 好まれる / 結合に有利
  • マイナス(–) → 好まれない / 不利

を示します。

例えば位置5では V(0.480), I(0.312) が高く、

疎水性アミノ酸が強く好まれる位置 と読み取れます。

逆に G(-0.912) は非常に嫌われます。

ペプチド全体のスコアは

各位置のスコアの合計 + 最後の“Intercept(4.52761)”

で計算され、MHC結合予測や免疫原性予測に使われます。

PSSMファイルはmobius/data/IEDB_MHC_I-2.9_matx_smm_smmpmbec/smmpmbec_matrix/ディレクトリに配置されています。

クローンしてきたmobiusのexamplesのhello_world.ipynbを参考に、mobius_test/linear_peptide/linear_peptide.ipynbを作成して実行してください。

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

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

mobiusによるベイズ最適化の実行

全コードはこちらを参考にしています。チュートリアルとほぼ一緒ですが、一部説明を追加しています。

# ----------------------------------------------------
# STEP 1: 準備と環境設定
# ----------------------------------------------------
# 必要なライブラリをインポート
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from gpytorch.priors import NormalPrior
# mobiusの主要なクラスと関数をインポート
from mobius import Planner, SequenceGA # プランナーと遺伝的アルゴリズム最適化器
from mobius import Map4Fingerprint # 分子フィンガープリント(MAP4)
from mobius import GPModel, ExpectedImprovement, TanimotoSimilarityKernel # ガウス過程モデル、獲得関数、カーネル
from mobius import LinearPeptideEmulator # MHCクラスIエミュレーター(PSSMベース)
from mobius import homolog_scanning, alanine_scanning # 配列ベースのスキャニング戦略
from mobius import convert_FASTA_to_HELM # FASTA形式からHELM形式への変換
# ----------------------------------------------------
# STEP 2: LinearPeptideEmulatorの初期化
# ----------------------------------------------------
# MHCクラスI HLA-A*02:01のLinearPeptideEmulatorを初期化
# Position Specific Scoring Matrix (PSSM) ファイルを使用
import os
# PSSMファイルのパス(複数のペプチド長に対応)
pssm_dir = os.path.join('..', '..', 'mobius', 'data', 'IEDB_MHC_I-2.9_matx_smm_smmpmbec', 'smmpmbec_matrix')
pssm_dir = os.path.normpath(os.path.abspath(pssm_dir))
pssm_files = [ os.path.join(pssm_dir, 'HLA-A-02:01-8.txt'), os.path.join(pssm_dir, 'HLA-A-02:01-9.txt'), os.path.join(pssm_dir, 'HLA-A-02:01-10.txt'), os.path.join(pssm_dir, 'HLA-A-02:01-11.txt')
]
# LinearPeptideEmulatorを初期化
# 実際の使用では、このステップを実際のラボ実験に置き換える必要があります
lpe = LinearPeptideEmulator(pssm_files)
# ----------------------------------------------------
# STEP 3: リードペプチドの定義
# ----------------------------------------------------
# 最適化の出発点となるリードペプチドを定義
# FASTA形式('HMTEVVRRC')からHELM形式に変換
# mobiusは内部的にHELM記法を使用してペプチド配列をエンコードします
lead_peptide = convert_FASTA_to_HELM('HMTEVVRRC')[0]
print(f"リードペプチド(HELM形式): {lead_peptide}")
# ----------------------------------------------------
# STEP 4: シードライブラリの生成
# ----------------------------------------------------
# 初期評価用のシードライブラリを生成
# アラニンスキャニングとホモログスキャニングを組み合わせて96個のペプチドを生成
seed_library = [lead_peptide]
# アラニンスキャニング: 各位置をアラニンに置き換えた変異体を生成
for seq in alanine_scanning(lead_peptide): seed_library.append(seq)
# ホモログスキャニング: 各位置を類似アミノ酸に置き換えた変異体を生成
for seq in homolog_scanning(lead_peptide): seed_library.append(seq) if len(seed_library) >= 96: print('Reach max. number of peptides allowed.') break
# ----------------------------------------------------
# STEP 5: シードライブラリの評価
# ----------------------------------------------------
# シードライブラリの各ペプチドをLinearPeptideEmulatorで評価
# HELM形式のペプチドを評価し、pIC50スコアを計算
pic50_seed_library = lpe.score(seed_library)
print(f"評価したペプチド数: {len(seed_library)}")
print(f"平均pIC50スコア: {np.mean(pic50_seed_library):.3f}")
print(f"最良のスコア: {np.min(pic50_seed_library):.3f}")
best_idx = np.argmin(pic50_seed_library)
print(f"最良のペプチド: {seed_library[best_idx]}")
print(f"(スコアが低いほど結合親和性が高い)")
# ----------------------------------------------------
# STEP 6: ベイズ最適化の設定
# ----------------------------------------------------
# 1. 分子フィンガープリント(MAP4)を設定
# HELM形式の入力を受け取り、4096次元のベクトルに変換
# 構造的に類似したペプチドが近いベクトル表現になる
map4 = Map4Fingerprint(input_type='helm', dimensions=4096, radius=1)
# 2. ガウス過程モデルを設定
# Tanimoto類似度カーネルを使用し、MAP4フィンガープリントで変換
# 既に評価したペプチドのデータから、未評価のペプチドのスコアを予測
gpmodel = GPModel(kernel=TanimotoSimilarityKernel(), transform=map4, noise_prior=NormalPrior(loc=0, scale=1))
# 3. 獲得関数(Expected Improvement)を設定
# ガウス過程モデルを使用し、最小化問題(pIC50スコアを小さくする)として設定
# pIC50スコアは低いほど結合親和性が高いため、maximize=False
# 次に評価すべきペプチドを選択するための関数
acq = ExpectedImprovement(gpmodel, maximize=False)
# ----------------------------------------------------
# STEP 7: デザインプロトコルの定義
# ----------------------------------------------------
# YAML形式でデザインプロトコルを定義
# ペプチドの構造制約とフィルター条件を指定
yaml_content = """
design: monomers: default: [A, C, D, E, F, G, H, I, K, L, M, N, P, Q, R, S, T, V, W, Y] APOLAR: [A, F, G, I, L, P, V, W] POLAR: [C, D, E, H, K, N, Q, R, K, S, T, M] AROMATIC: [F, H, W, Y] POS_CHARGED: [K, R] NEG_CHARGED: [D, E] polymers: - PEPTIDE1{X.M.X.X.X.X.X.X.X}$$$$V2.0: PEPTIDE1: 1: [AROMATIC, NEG_CHARGED] 4: POLAR 9: [A, V, I, L, M, T]
filters: - class_path: mobius.PeptideSelfAggregationFilter - class_path: mobius.PeptideSolubilityFilter init_args: hydrophobe_ratio: 0.5 charged_per_amino_acids: 5
"""
# デザインプロトコルをYAMLファイルに保存
with open('design_protocol.yaml', 'w') as f: f.write(yaml_content)
# ----------------------------------------------------
# STEP 8: 最適化器とプランナーの初期化
# ----------------------------------------------------
# 遺伝的アルゴリズム(GA)ベースの最適化器を設定
# period=15: GAの世代数を15に設定
optimizer = SequenceGA(algorithm='GA', period=15, design_protocol_filename='design_protocol.yaml')
# プランナーを初期化(獲得関数と最適化器を組み合わせる)
ps = Planner(acq, optimizer)
# ----------------------------------------------------
# STEP 9: Design-Make-Test(DMT)サイクルの実行
# ----------------------------------------------------
# 評価済みペプチドとスコアを保持するリスト
peptides = seed_library.copy()
pic50_scores = pic50_seed_library.copy()
# 後で分析するためのデータを保存
data = [(0, p, s) for p, s in zip(peptides, pic50_scores)]
# 3回のDMTサイクルを実行
num_cycles = 3
batch_size = 96
for i in range(num_cycles): print(f'\n=== DMTサイクル {i+1}/{num_cycles} ===') # Design: ベイズ最適化に基づいて、次に評価すべきペプチドを推薦 suggested_peptides, _ = ps.recommend(peptides, pic50_scores.reshape(-1, 1), batch_size=batch_size) # Test: 推薦されたペプチドをLinearPeptideEmulatorで評価 # 注意: 実際の使用では、ここで実際のラボ実験を実行します pic50_suggested_peptides = lpe.score(suggested_peptides) # 新しいデータを既存のリストに追加 peptides = np.concatenate([peptides, suggested_peptides]) pic50_scores = np.concatenate((pic50_scores, pic50_suggested_peptides), axis=0) data.extend([(i + 1, p, s) for p, s in zip(suggested_peptides, pic50_suggested_peptides)]) # これまでに見つかった最良のペプチドとそのスコアを表示 best_seq = peptides[np.argmin(pic50_scores)] best_pic50 = np.min(pic50_scores) print(f'\n最良のペプチド: {best_seq}') print(f'最良のスコア: {best_pic50:.3f}') print(f'(スコアが低いほど結合親和性が高い)')
# データをDataFrameに変換(可視化用)
df = pd.DataFrame(data=data, columns=('iter', 'polymer', 'exp_value'))
# ----------------------------------------------------
# STEP 10: 結果の可視化
# ----------------------------------------------------
# 最適化の進行状況を可視化
fig, ax = plt.subplots(figsize=(20, 7.5))
# イテレーション番号を文字列に変換('Init.'は初期シードライブラリ)
df['iter'] = df['iter'].replace({0: 'Init.', 1: '1', 2: '2', 3: '3'})
# 各イテレーションでのpIC50スコアの平均と95%信頼区間をプロット
sns.lineplot(x='iter', y='exp_value', data=df, ax=ax, errorbar=('ci', 95), err_style='bars', linewidth=3.5, err_kws={'lw': 3.5})
# グラフの設定
ax.set_xlim([-0.9, 3.5])
ax.set_ylim([-2, 4.5])
ax.set_ylabel('pIC50', fontsize=30)
ax.set_xlabel('Generations', fontsize=30)
ax.xaxis.set_tick_params(labelsize=30)
ax.yaxis.set_tick_params(labelsize=30)
# グラフのスタイル調整
sns.despine()
plt.tight_layout()
plt.show()
# 最終結果の表示
print('\n' + '='*60)
print('最適化結果のサマリー')
print('='*60)
best_idx = np.argmin(pic50_scores)
best_peptide = peptides[best_idx]
best_score = pic50_scores[best_idx]
print(f'\n最良のペプチド配列(HELM形式):')
print(f' {best_peptide}')
print(f'\npIC50スコア: {best_score:.3f}')
print(f'(スコアが低いほど結合親和性が高い)')
print(f'\n評価したペプチドの総数: {len(peptides)}')
print(f'初期シードライブラリ: {len(seed_library)}')
print(f'DMTサイクルで評価したペプチド: {len(peptides) - len(seed_library)}')
print('='*60)

全体の流れ:AIを使った新しいペプチドの探索

このコードは、既存のリードペプチドをベースに、AI(ベイズ最適化)を使って、ターゲットタンパク質(MHCクラスI)に最もよく結合するであろう新しいペプチド配列を効率的に見つけ出すという、創薬研究のプロセスをシミュレーションしています。

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

  • 準備と初期設定(Step 1〜3):
    • 必要なツールを準備し、MHCクラスIのPSSMマトリックスを読み込んでLinearPeptideEmulatorを初期化します。
    • 最適化の出発点となるリードペプチドを定義し、HELM形式に変換します。
  • シードライブラリの生成と評価(Step 4〜5):
    • リードペプチドからアラニンスキャニングホモログスキャニングを用いて96個の変異体を生成します。
    • 生成したペプチドをPSSMマトリックスで評価し、pIC50スコア(結合スコア)を計算します。これはAIが学習するための最初のデータセットとなります。
  • ベイズ最適化の設定(Step 6〜8):
    • 分子フィンガープリント(MAP4)ガウス過程モデル、**獲得関数(Expected Improvement)**を設定します。
    • デザインプロトコル(YAML形式)で、ペプチドの構造制約とフィルター条件を定義します。
    • 最適化器(遺伝的アルゴリズム)とプランナーを初期化します。
  • Design-Make-Testサイクル(Step 9):
    • AIが学習結果に基づき、「次に計算すれば最も良いスコアが出そう」と予測した最適な96個のペプチドを選び出し、再度PSSMマトリックスで評価します。
    • このサイクルを3回繰り返します。
    • 各サイクル終了時に、これまでに見つかった最良のペプチドとその結合スコアを表示します。
  • 結果の可視化(Step 10):
    • 各イテレーションでのpIC50スコアの分布を可視化し、最適化の進行状況を確認します。
    • 最終的に、最良のペプチド配列とその結合スコアを表示します。

STEP 1: 準備と環境設定


シミュレーションを行うための道具の準備を行います。

  • import numpy as np / import pandas as pd / import matplotlib.pyplot as plt / import seaborn as sns: 数値計算のNumPy、データ分析のPandas、可視化のMatplotlibSeabornという標準的なPythonライブラリをプログラムに組み込んでいます。
  • from mobius import Planner, SequenceGAmobiusから、ベイズ最適化のプランナーと、遺伝的アルゴリズムベースの最適化器を呼び出せるようにしています。
  • from mobius import Map4Fingerprint: ペプチド配列を数値ベクトル(フィンガープリント)に変換するMAP4という手法を呼び出しています。
  • from mobius import GPModel, ExpectedImprovement, TanimotoSimilarityKernel: ベイズ最適化の核心となるガウス過程モデル獲得関数カーネル関数を呼び出しています。
  • from mobius import LinearPeptideEmulator: PSSMマトリックスを使用してペプチドの結合親和性を予測するLinearPeptideEmulatorを呼び出しています。
  • from mobius.utils import MolFromHELM: HELM形式のペプチドをRDKit分子に変換する関数を呼び出しています。
  • from mobius import homolog_scanning, alanine_scanning: 初期ライブラリを生成するための配列ベースのスキャニング戦略を呼び出しています。
  • from mobius import convert_FASTA_to_HELM: FASTA形式のペプチド配列を、mobiusが使用するHELM形式に変換する関数を呼び出しています。

STEP 2: LinearPeptideEmulatorの初期化


MHCクラスI(HLA-A*02:01)のPSSMファイルを読み込み、LinearPeptideEmulatorを初期化します。

IEDBデータベースについて

PSSMファイルは、IEDB(Immune Epitope Database)から取得された実験データに基づいて作成されています。

データの取得方法:

  1. 文献からの収集: 公開された科学論文から手作業で実験データを収集
  2. 実験データ: 実際のMHC結合アッセイで測定された結合親和性(IC50値など)
  3. 機械学習モデル: SMM(Stabilized Matrix Method)という機械学習モデルで学習
  4. PSSMファイル生成: 学習したモデルからPSSMファイルが生成される
  • pssm_files = [...]: 複数のペプチド長(8、9、10、11残基)に対応するPSSMファイルのパスをリストで指定しています。
  • lpe = LinearPeptideEmulator(pssm_files)LinearPeptideEmulatorを初期化しています。これにより、ペプチドをMHCクラスIに結合させた際のpIC50スコア(結合スコア)を計算できます。pIC50スコアは低いほど結合親和性が高いことを示します。

STEP 3: リードペプチドの定義


最適化の出発点となるリードペプチドを定義します。

  • lead_peptide = convert_FASTA_to_HELM('HMTEVVRRC')[0]: FASTA形式のペプチド配列('HMTEVVRRC')を、mobiusが使用するHELM形式に変換しています。HELM(Hierarchical Editing Language for Macromolecules)は、ペプチドやその他の複雑な生体分子を表現するための標準形式です。

HELM形式の表記について

このノートブックでは、ペプチド配列をHELM形式(Hierarchical Editing Language for Macromolecules)で表現しています。

HELM形式の構造:

例: PEPTIDE1{H.M.M.D.F.I.F.E.V}$$$$V2.0

この表記は以下の部分から構成されています:

  1. PEPTIDE1: ペプチドのタイプ
    • 線形ペプチドを表す識別子
  2. {H.M.M.D.F.I.F.E.V}: アミノ酸配列
    • 各アミノ酸は1文字コードで表される
    • ドット(.)で区切られている
    • 左から右へ、N末端からC末端の順
  3. $$$$: セパレーター
    • 複数のポリマーや接続情報を区切る
    • 線形ペプチドの場合は接続情報がないため、$$$$のみ
  4. V2.0: HELMのバージョン
    • HELM記法のバージョン番号

STEP 4: シードライブラリの生成


初期評価用のシードライブラリを生成します。

  • seed_library = [lead_peptide]: シードライブラリのリストを初期化し、リードペプチドを最初の要素として追加しています。
  • for seq in alanine_scanning(lead_peptide):アラニンスキャニングを実行します。これは、リードペプチドの各位置をアラニン(A)に置き換えた変異体を生成する戦略です。各位置の重要性を評価するために使用されます。
  • for seq in homolog_scanning(lead_peptide):ホモログスキャニングを実行します。これは、リードペプチドの各位置を類似アミノ酸に置き換えた変異体を生成する戦略です。構造的に類似したアミノ酸への置換により、機能を維持しながら多様性を導入します。
  • if len(seed_library) >= 96: break: シードライブラリが96個に達したら、ループを終了します。

STEP 5: シードライブラリの評価

生成したシードライブラリの各ペプチドをPSSMマトリックスで評価します。

  • pic50_seed_library = lpe.score(seed_library)LinearPeptideEmulatorを使用して、シードライブラリの各ペプチドのpIC50スコアを計算しています。pIC50スコアは低いほど結合親和性が高いことを示します。

このステップでは、96個のペプチドそれぞれに対してPSSMマトリックスによる評価を実行し、MHCクラスIとの結合スコアを取得します。これらのスコアは、ベイズ最適化の学習データとして使用されます。

STEP 6: ベイズ最適化の設定

ベイズ最適化に必要なコンポーネントを設定します。

  • map4 = Map4Fingerprint(input_type='helm', dimensions=4096, radius=1)MAP4フィンガープリントを設定しています。これは、HELM形式のペプチド配列を4096次元の数値ベクトルに変換する手法です。radius=1は、原子から1ホップ以内の部分構造を考慮することを意味します。

役割: ペプチド配列を数値ベクトルに変換する「翻訳機」

なぜ必要?

  • コンピュータは文字列(ペプチド配列)を直接理解できません
  • 数値ベクトルに変換することで、数学的な計算が可能になります

具体例:

ペプチド「HMTEVVRRC」→ [0.23, -0.15, 0.87, ..., 0.42] (4096次元のベクトル)
ペプチド「HMTEVVRRV」→ [0.24, -0.14, 0.86, ..., 0.41] (似た配列なので似たベクトル)

gpmodel = GPModel(kernel=TanimotoSimilarityKernel(), transform=map4, noise_prior=NormalPrior(loc=0, scale=1))ガウス過程モデルを設定しています。これは、ペプチドのフィンガープリントから結合親和性を予測する代理モデルです。TanimotoSimilarityKernelは、2つのペプチドの類似度を計算するカーネル関数です。noise_priorは、観測ノイズの事前分布を設定しています。

役割: 「予測屋さん」- 未評価のペプチドのスコアを予測する

どのように予測するか?

  1. 学習: 既に評価したペプチドのデータを見る

    評価済み: HMTEVVRRC → スコア 2.5
    評価済み: HMTEVVRRV → スコア 2.3
    評価済み: HMTEVVRRA → スコア 2.8
  2. パターン発見: 「似た配列は似たスコアになる」というパターンを学習

    「位置9がC, V, Aのとき、スコアは2.3-2.8の範囲」
    「位置8がRのとき、スコアが良くなる傾向」
  3. 予測: 未評価のペプチドのスコアを予測

    未評価: HMTEVVRRL → 予測スコア: 2.4 ± 0.3
    (「2.4くらいになりそう。でも、0.3の誤差があるかも」)
  • acq = ExpectedImprovement(gpmodel, maximize=False): 獲得関数(Expected Improvement)を設定しています。これは、次に評価すべきペプチドを選ぶための関数です。maximize=Falseは、pIC50スコアを最小化する(結合親和性を最大化する)問題であることを示しています。pIC50スコアは低いほど良いため、最小化問題として設定します。

役割: 「次に何を試すか決める審判員」

判断基準:

  1. 予測値が良いペプチド → 試す価値がある

    予測スコア: 1.5(現在の最良: 2.0より良い!)
    → 試してみたい
  2. 不確実性が高いペプチド → もしかしたら良い結果が出るかも

    予測スコア: 2.5 ± 1.0(不確実性が大きい)
    → もしかしたら1.5になるかもしれない!
  3. バランス: この2つを組み合わせて、期待改善値を計算

    期待改善値 = 「このペプチドを試すことで、どれくらい改善が期待できるか」

STEP 7: デザインプロトコルの定義

ペプチドの構造制約とフィルター条件をYAML形式で定義します。

  • yaml_content = """...""": YAML形式の文字列でデザインプロトコルを定義しています。
    • monomers: 各位置で使用可能なアミノ酸のセットを定義しています。defaultは全20種類の標準アミノ酸、APOLARは非極性アミノ酸、POLARは極性アミノ酸など、意味のあるグループに分類されています。
    • polymers: ペプチドのスキャフォールドを定義しています。PEPTIDE1{X.M.X.X.X.X.X.X.X}$$$$V2.0は、9残基の線形ペプチドを表しています。各位置(1, 4, 9)で使用可能なアミノ酸のセットを指定しています。
    • filters: 合成や溶解度に問題がある可能性のあるペプチドを除外するフィルターを定義しています。PeptideSelfAggregationFilterは自己凝集を防ぐフィルター、PeptideSolubilityFilterは溶解度を確保するフィルターです。
  • with open('design_protocol.yaml', 'w') as f: f.write(yaml_content): 定義したデザインプロトコルをYAMLファイルに保存しています。

STEP 8: 最適化器とプランナーの初期化

ベイズ最適化を実行するための最適化器とプランナーを初期化します。

  • optimizer = SequenceGA(algorithm='GA', period=15, design_protocol_filename='design_protocol.yaml')遺伝的アルゴリズム(GA)ベースの最適化器を設定しています。algorithm='GA'は遺伝的アルゴリズムを使用することを指定し、period=15はGAの世代数を15に設定しています。design_protocol_filenameで、先ほど定義したデザインプロトコルファイルを指定しています。
  • ps = Planner(acq, optimizer)プランナーを初期化しています。プランナーは、獲得関数(acq)と最適化器(optimizer)を組み合わせて、次に評価すべきペプチドを推薦する役割を担います。

STEP 9: Design-Make-Testサイクルの実行

ベイズ最適化のメインループを実行します。

  • peptides = seed_library.copy() / pic50_scores = pic50_seed_library.copy(): 評価済みのペプチドとそのpIC50スコアを保持するリストを初期化しています。
  • data = [(0, p, s) for p, s in zip(peptides, pic50_scores)]: 後で可視化するためのデータを保存しています。0は初期シードライブラリを表します。
  • for i in range(3):: 3回のDMTサイクルを実行します。
    • suggested_peptides, _ = ps.recommend(peptides, pic50_scores.reshape(-1, 1), batch_size=96): プランナーが、既存のデータ(peptidespic50_scores)に基づいて、次に評価すべき96個のペプチドを推薦します。ベイズ最適化のアルゴリズムが、獲得関数と最適化器を使って最適なペプチドを選び出します。
    • pic50_suggested_peptides = lpe.score(suggested_peptides): 推薦された各ペプチドをPSSMマトリックスで評価し、pIC50スコアを計算します。
    • peptides = np.concatenate([peptides, suggested_peptides]) / pic50_scores = np.concatenate(...): 新しいデータを既存のリストに追加します。
    • best_idx = np.argmin(pic50_scores): これまでに見つかった最良のペプチドのインデックスを取得します(スコアが最小のもの)。
    • best_seq = peptides[best_idx] / best_pic50 = pic50_scores[best_idx]: 最良のペプチド配列とその結合スコアを表示します。

DMTサイクルの流れ(詳しく)

1. Design(設計)フェーズ

何をしているか?

  • ガウス過程モデルが、これまでに評価した全てのペプチドのデータを分析
  • 「どのような特徴を持つペプチドが良いスコアを出すか」を学習
  • 獲得関数が、この学習結果を基に「次に試すべき96個のペプチド」を選ぶ

具体例:

学習したパターン:
- 位置1にH(ヒスチジン)があるとスコアが良い
- 位置4にE(グルタミン酸)があるとスコアが良い
- 位置9にV(バリン)があるとスコアが良い
→ これらの特徴を組み合わせたペプチドを推薦

2. Make(生成)フェーズ

何をしているか?

  • 推薦されたペプチド配列を準備
  • デザインプロトコルに基づいて、化学的に妥当なペプチドのみを生成
  • フィルターで、実用的でないペプチドを除外

注意: このノートブックでは、ペプチド配列は既に生成されているため、このステップは自動的に行われます。

3. Test(評価)フェーズ

何をしているか?

  • 推薦された96個のペプチドを、LinearPeptideEmulatorで評価
  • 各ペプチドの結合スコア(pIC50)を取得

実際の使用では:

  • ここで実際のラボ実験を実行します
  • 分子ドッキング、結合アッセイなど

4. 更新フェーズ

何をしているか?

  • 新しい96個のデータを、既存のデータに追加
  • ガウス過程モデルを更新(新しいデータで再学習)
  • これまでに見つかった最良のペプチドを記録

学習の進化:

サイクル1: 96個のデータで学習 → 次の96個を選ぶ
サイクル2: 192個のデータで学習(より正確に!) → 次の96個を選ぶ
サイクル3: 288個のデータで学習(さらに正確に!) → 次の96個を選ぶ

STEP 10: 結果の可視化

最適化の進行状況を可視化します。

  • df = pd.DataFrame(data=data, columns=('iter', 'polymer', 'exp_value')): 保存したデータをPandasのDataFrameに変換します。
  • df['iter'] = df['iter'].replace({0: 'Init.', 1: '1', 2: '2', 3: '3'}): イテレーション番号を文字列に変換します('Init.'は初期シードライブラリを表します)。
  • sns.lineplot(...): 各イテレーションでのpIC50スコアの平均と95%信頼区間を可視化します。これにより、最適化が進行するにつれてpIC50スコアが改善(減少)するかを確認できます。
  • 最終結果の表示: 最適化の完了後、最良のペプチド配列(HELM形式)とその結合スコア(pIC50スコア)を表示します。また、評価したペプチドの総数も表示されます。

結果の可視化


実行が完了すると、各イテレーションでのpIC50スコアの分布が可視化されます。グラフから、最適化が進行するにつれてpIC50スコアが改善(減少)していく様子が確認できます。

また、各イテレーションの終了時に、これまでに見つかった最良のペプチドとそのスコアが表示されます。最終結果として、以下のような出力が得られます。

============================================================
最適化結果のサマリー
============================================================
最良のペプチド配列(HELM形式): PEPTIDE1{F.M.M.E.D.I.F.R.V}$$$$V2.0
pIC50スコア: -0.709
(スコアが低いほど結合親和性が高い)
評価したペプチドの総数: 384
初期シードライブラリ: 96
DMTサイクルで評価したペプチド: 288
============================================================

これは、HELM形式で表現された最良のペプチド配列と、そのpIC50スコア(-0.335)を示しています。pIC50スコアは低いほど結合親和性が高く、初期のリードペプチドから大幅に改善されていることがわかります。

最後に


mobiusとベイズ最適化を活用したペプチド最適化、いかがでしたでしょうか。

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

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

ぜひ皆さんもmobiusとベイズ最適化を組み合わせ、効率的なインシリコ創薬に取り組んでみてください!

参考文献


License: Apache-2.0


The post mobiusによるベイジアン最適化を用いたペプチドin silicoスクリーニング【In silico創薬】 first appeared on LabCode.

]]>
https://labo-code.com/bioinformatics/insilico-screening-with-mobius/feed/07053
FEgrowを用いたアクティブラーニングによる化合物スクリーニングの高速化【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で得られた化合物を基にさらに効率よくスクリーニングしていく方法を紹介します。

【この記事のまとめ】

創薬研究者やバイオインフォマティクスエンジニアに向けて、インシリコ創薬ツール「FEgrow」と能動学習(アクティブラーニング)を組み合わせ、膨大な化学空間から有望な化合物を最小限の計算リソースで効率的に探索する手法を解説します。

  • FEgrowによる分子設計と評価の自動化:足場分子(スキャフォールド)に対して多様なリンカーや置換基を結合させ、ドッキングシミュレーションを通じて結合親和性を評価するプロセスを習得できます。
  • アクティブラーニングによるスクリーニングの高速化:全ての化合物候補を評価するのではなく、機械学習が「次に評価すべき化合物」を自律的に判断することで、計算時間を大幅に短縮しつつ高活性化合物へ到達する方法を紹介します。
  • Google Colab/ローカル環境での実践ワークフロー:ライブラリのインストールから、SARS-CoV-2 Mproを標的とした具体的なチュートリアルコードの実行手順まで、即座に業務・研究へ応用できる形で網羅しています。

この記事を読むことで、計算コストの壁を突破し、限られた時間内でより高品質なリード化合物を特定するための高度なスクリーニング戦略を実装できるようになります。

動作検証済み環境

動作検証済み環境

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
Google Colabで実践する機械学習ポテンシャルを用いた金属触媒の構造最適化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 Google Colabで実践する機械学習ポテンシャルを用いた金属触媒の構造最適化 first appeared on LabCode.

]]>

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

【この記事のまとめ】

マテリアルズ・インフォマティクス(MI)や計算化学に携わる研究者・学生に向けて、Google Colabを用いた金属触媒の分子モデリングから機械学習ポテンシャル(MLP)計算までの実践的なワークフローを解説します。

  • 複雑な触媒モデルの構築:ASEやpymatgenを活用し、NiO表面スラブへのPtナノクラスター担持やCO分子の吸着モデルをコードで正確に作成する手法を紹介。
  • 計算精度を高める構造整形:斜格子から直交セルへの変換、スーパーセル展開、衝突チェックなど、シミュレーションの失敗を防ぐためのデータ処理プロセスを詳述。
  • MLPによる即時計算:汎用型機械学習ポテンシャル「UMA」を用いて、一点エネルギー計算にそのまま利用可能な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 Google Colabで実践する機械学習ポテンシャルを用いた金属触媒の構造最適化 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 について解説します。今回は、環境構築から使い方について、丁寧にご紹介します。

【この記事のまとめ】

創薬研究者やバイオインフォマティクスに携わる方へ。MITが開発したオープンソースのAIモデル「Boltz」を活用し、AlphaFold3と同等の高精度でタンパク質構造やタンパク質-リガンド複合体を予測・解析する方法を解説します。

  • AlphaFold3並の精度をオープンソースで実現:拡散モデル(Diffusion Model)をベースとした最新アルゴリズムにより、バイオ分子複合体の三次元構造を高精度に予測。商用利用可能なMITライセンスで提供されています。
  • 構造予測から親和性予測まで幅広く対応:アミノ酸配列のみの構造予測(Boltz-1)に加え、物理ベース計算(FEP)の1000倍以上の高速性で結合親和性を予測できるBoltz-2の可能性についても触れています。
  • WSL2/GPU環境での実践的セットアップ:WSL2上での環境構築手順から、YAMLファイルを用いた具体的なタンパク質-リガンド複合体予測の実行コマンド、PyMOLでの可視化結果までを網羅しています。

この記事を読むことで、高額な商用ツールや制限のあるWebサービスに頼らず、自身のローカル/サーバー環境で自由度の高い「高精度バイオ分子シミュレーション」を完結させる手法が手に入ります。

動作検証済み環境

動作検証済み環境

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