mcpField
R
rowan

rowan

github.com/jaechang-hitsその他38467 回インストール1 週間前に更新
リポジトリ

rowan について

rowanは、分子構造を扱う研究者や開発者向けのクラウド量子化学計算用Python SDKです。ジョブの実行と保存を担い、量子化学ソフトをローカルに導入せずにエネルギー、構造、電子物性を取得できます。

主な機能

  1. 01DFT・半経験的計算
  2. 02構造最適化と配座探索
  3. 03ねじれエネルギースキャン
  4. 04単一点分子物性計算
  5. 05一括ジョブ送信と結果取得

活用シーン

  1. 01候補分子の構造最適化
  2. 02エネルギーによる配座順位付け
  3. 03ねじれエネルギー曲線の比較
  4. 04電荷とHOMO/LUMO準位の計算

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jaechang-hits/sciagent-skills --skill rowan

インストール後、Claude Code で/rowanを入力して読み込まれたか確認します。

詳細

rowan

概要

Rowan は、DFT および半経験的計算を Python SDK(rowan)を通じて利用できる、クラウド量子化学プラットフォームです。Python スクリプトや Jupyter ノートブックから計算(構造最適化、配座生成、ねじれ角スキャン、単一点エネルギー計算)を送信し、Gaussian、ORCA、Psi4 のインストールを管理することなく、結果(エネルギー、構造、部分電荷、フロンティア軌道エネルギー)を取得できます。Rowan がジョブのキューイング、実行、保存を処理します。学術研究や探索的な利用向けに無料プランが用意されています。

使用する場面

  • 小分子の構造最適化:DFT を使用して、医薬品候補、フラグメント、ビルディングブロックの正確な平衡構造を取得します。
  • エネルギー順位付けによる配座生成:複数の配座を生成して最適化し、ドッキングや物性予測に適した最低エネルギー配座を特定します。
  • ねじれ角ポテンシャルスキャン:回転可能な結合に沿ったエネルギープロファイルをマッピングし、配座の選好を把握します。
  • 量子化学的な物性計算:双極子モーメント、部分電荷(Mulliken、ESP)、HOMO/LUMO エネルギー、静電ポテンシャル面を計算します。
  • ドッキング前のエネルギー最小化:構造ベースのドッキングツール(DiffDock、AutoDock Vina)に入力する前に、リガンド構造を調整します。
  • 異性体の安定性比較:互変異性体、立体異性体、構造異性体の相対エネルギーを計算します。
  • 大規模な配座スクリーニング(1000 分子超)には、RDKit の ETKDGv3 + MMFF を使用してください(力場レベルで、クラウド費用はかかりません)。
  • タンパク質規模の量子化学/分子力学(QM/MM)には、ORCA + CP2K などの専用パッケージが必要です。

前提条件

pip install rowan

# Set API key (add to .bashrc or .env)
export ROWAN_API_KEY="your_api_key_here"

クイックスタート

import rowan

# Authenticate (uses ROWAN_API_KEY environment variable automatically)
client = rowan.RowanClient()

# Run geometry optimization of aspirin at GFN2-xTB level
job = client.compute(
    smiles="CC(=O)Oc1ccccc1C(=O)O",
    method="gfn2-xtb",
    tasks=["optimize"],
)
print(f"Job ID: {job.id}, Status: {job.status}")

# Wait for completion and retrieve energy
result = client.wait(job.id)
print(f"Energy: {result.energy:.6f} Hartree")
print(f"Optimized geometry atoms: {len(result.geometry.atoms)}")

コア API

モジュール 1:クライアントの初期化と認証
import rowan
import os

# Option 1: automatic (reads ROWAN_API_KEY env variable)
client = rowan.RowanClient()

# Option 2: explicit key
client = rowan.RowanClient(api_key=os.environ["ROWAN_API_KEY"])

print(f"Authenticated as: {client.user.email}")
print(f"Organization: {client.user.organization}")
モジュール 2:構造最適化

分子構造を最も近い局所極小へ最適化します。

import rowan

client = rowan.RowanClient()

# GFN2-xTB semiempirical (fast, good for conformer screening)
job_xtb = client.compute(
    smiles="CCc1ccc(cc1)NC(=O)C",    # paracetamol
    method="gfn2-xtb",
    tasks=["optimize"],
)
result_xtb = client.wait(job_xtb.id)
print(f"xTB optimized energy: {result_xtb.energy:.6f} Hartree")
print(f"Geometry: {len(result_xtb.geometry.atoms)} atoms")
# DFT optimization: B3LYP/6-31G* (accurate, slower)
job_dft = client.compute(
    smiles="CCc1ccc(cc1)NC(=O)C",
    method="b3lyp",
    basis_set="6-31g*",
    tasks=["optimize"],
    solvent="water",               # implicit solvent (SMD model)
)
result_dft = client.wait(job_dft.id)
print(f"B3LYP/6-31G* energy (water): {result_dft.energy:.6f} Hartree")
print(f"Dipole moment: {result_dft.dipole_moment:.3f} Debye")
モジュール 3:配座生成

複数の 3D 配座を生成し、エネルギーで順位付けします。

import rowan
import pandas as pd

client = rowan.RowanClient()

# Generate and optimize 10 conformers at GFN2-xTB level
job = client.compute(
    smiles="CC(C)CC1=CC=C(C=C1)C(C)C(=O)O",  # ibuprofen
    method="gfn2-xtb",
    tasks=["conformers"],
    n_conformers=10,
)
result = client.wait(job.id)

# Rank conformers by relative energy
conformers = result.conformers
df = pd.DataFrame([
    {"conformer_id": i,
     "energy_hartree":    c.energy,
     "rel_energy_kcal":   (c.energy - min(c2.energy for c2 in conformers)) * 627.509}
    for i, c in enumerate(conformers)
]).sort_values("rel_energy_kcal")

print(df.to_string(index=False))
print(f"\nLowest energy conformer ID: {df.iloc[0]['conformer_id']}")
モジュール 4:ねじれ角スキャン

二面角の関数としてエネルギーをマッピングします。

import rowan
import numpy as np
import matplotlib.pyplot as plt

client = rowan.RowanClient()

# Scan the C-C=C-C dihedral of butene
job = client.compute(
    smiles="CC=CC",             # but-2-ene
    method="gfn2-xtb",
    tasks=["torsion_scan"],
    torsion_atoms=[0, 1, 2, 3],  # atom indices defining dihedral
    n_scan_points=36,             # 36 points = 10-degree steps
)
result = client.wait(job.id)

angles  = [point.angle  for point in result.torsion_scan]
energies = [point.energy for point in result.torsion_scan]
rel_e = [(e - min(energies)) * 627.509 for e in energies]  # convert to kcal/mol

fig, ax = plt.subplots(figsize=(7, 4))
ax.plot(angles, rel_e, "o-", color="steelblue")
ax.set_xlabel("Dihedral angle (degrees)")
ax.set_ylabel("Relative energy (kcal/mol)")
ax.set_title("Torsional potential: but-2-ene C-C=C-C dihedral")
plt.tight_layout()
plt.savefig("torsion_scan.png", dpi=150)
print("Torsion scan saved -> torsion_scan.png")
モジュール 5:単一点物性

固定された構造における電子物性(HOMO/LUMO、部分電荷、ESP)を計算します。

import rowan

client = rowan.RowanClient()

# Single-point DFT: get frontier orbital energies and partial charges
job = client.compute(
    smiles="c1ccccc1N",          # aniline
    method="b3lyp",
    basis_set="6-311+g**",
    tasks=["single_point", "partial_charges", "orbitals"],
)
result = client.wait(job.id)

print(f"HOMO energy: {result.homo_energy:.4f} eV")
print(f"LUMO energy: {result.lumo_energy:.4f} eV")
print(f"HOMO-LUMO gap: {result.lumo_energy - result.homo_energy:.4f} eV")
print(f"Dipole moment: {result.dipole_moment:.3f} Debye")

# Partial charges (Mulliken)
for i, (atom, charge) in enumerate(zip(result.geometry.atoms, result.partial_charges)):
    print(f"  Atom {i} ({atom.symbol}): {charge:+.4f} e")
モジュール 6:バッチジョブの送信

複数の分子を並行して送信します。

import rowan
import pandas as pd
from concurrent.futures import ThreadPoolExecutor, as_completed

client = rowan.RowanClient()

smiles_list = [
    ("aspirin",      "CC(=O)Oc1ccccc1C(=O)O"),
    ("caffeine",     "Cn1cnc2c1c(=O)n(c(=O)n2C)C"),
    ("paracetamol",  "CC(=O)Nc1ccc(O)cc1"),
    ("ibuprofen",    "CC(C)Cc1ccc(cc1)C(C)C(=O)O"),
]

def submit_and_wait(name, smiles):
    job = client.compute(smiles=smiles, method="gfn2-xtb", tasks=["optimize"])
    result = client.wait(job.id)
    return {"name": name, "smiles": smiles, "energy": result.energy}

results = []
with ThreadPoolExecutor(max_workers=4) as executor:
    futures = {executor.submit(submit_and_wait, n, s): n for n, s in smiles_list}
    for future in as_completed(futures):
        results.append(future.result())

df = pd.DataFrame(results)
df.to_csv("batch_energies.csv", index=False)
print(df)

主なパラメーター

パラメーターモジュールデフォルト範囲/オプション効果
methodcompute必須"gfn2-xtb", "b3lyp", "wb97x-d", "mp2"QC メソッド。xTB は最速、DFT は高精度、MP2 は電子相関の計算に使用します
basis_setcompute (DFT)メソッドに依存"6-31g*", "6-311+g**", "def2-svp", "def2-tzvp"基底関数系。大きいほど高精度ですが、計算は遅くなります
taskscompute必須["optimize"], ["single_point"], ["conformers"], ["torsion_scan"]実行する計算
n_conformersconformers task101–100生成して最適化する配座の数
n_scan_pointstorsion_scan3612–72二面角スキャンの点数(360/n がステップ幅になります)
solventcomputeNone"water", "dmso", "methanol", etc.暗黙的な SMD 溶媒和モデル
torsion_atomstorsion_scan必須4 つの原子インデックスのリストスキャンする二面角を定義します

ベストプラクティス

  1. スクリーニングにはGFN2-xTBを、最終的な特性評価にはDFTを使用します:xTBはDFTより100〜1000倍高速で、配座ランキングや構造探索には十分です。正確なエネルギー、HOMO/LUMOギャップ、公開可能な結果を得るには、B3LYPまたはwB97X-Dに切り替えてください。

  2. 物性を計算する前に、必ず構造を最適化します:緩和されていない構造(SMILESからの3D埋め込みなど)を使ったシングルポイント計算では、信頼性の低いエネルギーや電子物性が得られます。最初にtasks=["optimize"]を実行してください。

  3. 生物学的に重要な分子にはsolventを設定します:気相のエネルギーは、帯電分子や極性の高い分子では、溶液相のエネルギーと大きく異なることがあります。水溶液条件下で評価する創薬候補には、solvent="water"を使用してください。

  4. 長時間のDFT計算ではジョブのステータスを確認します:長時間実行するバッチワークフローで処理がブロックされないよう、タイムアウトを指定してclient.wait()を使用するか、client.get_job(job_id).statusでポーリングしてください。

  5. 最適化した構造は再利用できるようXYZ形式でエクスポートします:同じ構造に対して異なる物性計算が必要な場合に、高コストなDFTジョブを再実行せずに済むよう、最適化した構造を保存してください。

    with open("optimized.xyz", "w") as f:
        f.write(result.geometry.to_xyz())
    

一般的なワークフロー

ワークフロー1:配座探索と物性計算

目的:創薬候補の最低エネルギー配座を見つけ、その電子物性を計算します。

import rowan
import pandas as pd

client = rowan.RowanClient()
smiles = "CC(C)Cc1ccc(cc1)C(C)C(=O)O"   # ibuprofen

# Step 1: Generate and rank conformers at fast xTB level
conf_job = client.compute(
    smiles=smiles, method="gfn2-xtb", tasks=["conformers"], n_conformers=20
)
conf_result = client.wait(conf_job.id)
lowest_conf = min(conf_result.conformers, key=lambda c: c.energy)
print(f"Lowest conformer energy: {lowest_conf.energy:.6f} Hartree")

# Step 2: Refine with DFT and compute properties
dft_job = client.compute(
    xyz=lowest_conf.to_xyz(),      # use optimized xTB geometry as DFT start
    method="b3lyp",
    basis_set="6-31g*",
    tasks=["optimize", "partial_charges", "orbitals"],
    solvent="water",
)
dft_result = client.wait(dft_job.id)

print(f"B3LYP/6-31G* energy (water): {dft_result.energy:.6f} Hartree")
print(f"HOMO-LUMO gap: {dft_result.lumo_energy - dft_result.homo_energy:.4f} eV")
print(f"Dipole moment: {dft_result.dipole_moment:.3f} Debye")
ワークフロー2:互変異性体の相対安定性

目的:2つの互変異性体のエネルギーを比較し、水中でどちらがより安定かを判断します。

import rowan

client = rowan.RowanClient()

tautomers = {
    "keto":   "CC(=O)CC(=O)C",     # acetylacetone keto form
    "enol":   "CC(=O)C=C(O)C",     # acetylacetone enol form
}

energies = {}
for name, smiles in tautomers.items():
    job = client.compute(
        smiles=smiles,
        method="b3lyp",
        basis_set="6-311+g**",
        tasks=["optimize"],
        solvent="water",
    )
    result = client.wait(job.id)
    energies[name] = result.energy
    print(f"{name}: {result.energy:.6f} Hartree")

delta_e_hartree = energies["enol"] - energies["keto"]
delta_e_kcal    = delta_e_hartree * 627.509
print(f"\nDelta E (enol - keto): {delta_e_kcal:.2f} kcal/mol")
print(f"More stable form: {'enol' if delta_e_kcal < 0 else 'keto'}")

予想される出力

  • result.energy — Hartree単位の全電子エネルギー
  • result.geometry — 最適化された3D構造(原子と座標)
  • result.dipole_moment — Debye単位のスカラー双極子モーメント
  • result.homo_energy、result.lumo_energy — eV単位のフロンティア軌道エネルギー
  • result.partial_charges — 元素電荷単位で表した、各原子の電荷のリスト
  • result.conformers — 個別のエネルギーを持つ配座オブジェクトのリスト
  • result.torsion_scan — (角度、エネルギー)のスキャン点のリスト

よく使うレシピ

レシピ:高速シングルポイントエネルギー計算

使用する場面:1回の呼び出しで2つの配座または反応中間体の相対エネルギーを比較します。

import rowan

client = rowan.Client()

smiles_list = ["CC(=O)O", "C(=O)(O)C"]  # Acetic acid, two representations
jobs = []
for smi in smiles_list:
    job = client.compute(
        molecule=rowan.Molecule.from_smiles(smi),
        theory_level="gfn2-xtb",
        task="single_point",
    )
    jobs.append(job)

# Collect energies
for smi, job in zip(smiles_list, jobs):
    result = client.wait(job)
    print(f"{smi}: energy = {result.energy:.6f} Hartree")
レシピ:実行中のジョブのステータス確認

使用する場面:処理をブロックせずに、時間のかかる最適化や配座探索を監視します。

import rowan, time

client = rowan.Client()
job = client.compute(
    molecule=rowan.Molecule.from_smiles("c1ccccc1"),
    theory_level="gfn2-xtb",
    task="optimize",
)
print(f"Job ID: {job.id}")

# Poll every 10 seconds (non-blocking)
for _ in range(30):
    status = client.status(job)
    print(f"Status: {status}")
    if status in ("completed", "failed"):
        break
    time.sleep(10)

result = client.get(job)
print(f"Final energy: {result.energy:.6f} Hartree")

トラブルシューティング

問題原因解決策
AuthenticationErrorAPIキーが設定されていないか、期限切れですROWAN_API_KEY環境変数を設定し、rowanquantum.comでキーを再生成してください
ジョブがqueued状態のままになる無料プランのサーバー負荷が高い待機するか、有料プランにアップグレードしてください。無料プランではピーク時にキューに入ることがあります
SCF not convergedエラーDFTの自己無撞着場計算が収束しませんでしたより小さい基底関数系を試してください。まずmethod="gfn2-xtb"を使用して、より良い初期構造を取得してください
ValueError: invalid SMILESSMILES文字列の形式が正しくありません送信前に、RDKitのChem.MolFromSmiles(smiles)で検証してください
最適化後のエネルギーが高い構造が局所極小にとどまっていますtasks=["conformers"]で複数の配座を生成し、最もエネルギーの低いものを選択してください
result.homo_energyがない軌道計算が要求されていませんtasksリストに"orbitals"を追加してください

参考資料

コメント