アーキテクチャ: pdb2reaction¶
1. 概要¶
pdb2reaction は、活性部位cluster modelに対して酵素反応経路解析を実行する
Python CLIです。geometry/path stageには組み込みMLIPまたはcustom ASE calculatorを
使用し、任意でPySCF/GPU4PySCF DFT 一点計算を追加できます
(extract → MEP → tsopt → IRC → freq → dft)。
同梱された 2 つの fork(pysisyphus/、thermoanalysis/)は、リポジトリ最上位に repo 内部モジュールとして配置されています。これらは意図的に上流の PyPI 配布版では ありません。本パッケージと並べて PyPI から再インストールすると、ローカルの拡張が気づかないうちに動かなくなります。§6 を参照してください。
2. 階層構造(6 つの計算層)¶
2.1 階層テーブル¶
layer |
dir |
responsibility |
may depend on |
|---|---|---|---|
L1 Interface |
|
Click root group、共有 option-decorator ファクトリ( |
|
L2 Application |
|
サブコマンドごとのオーケストレーション; ステージランナー 1 ファイルにつき 1 つ( |
|
L3 Domain |
|
化学的に意味を持つヘルパーロジック(結合変化検出、結合サマリ、元素情報伝播) |
|
L4a Infra (MLIP) |
|
MLIP バックエンドディスパッチャ + バックエンドごとのアダプタ(UMA / Orb / MACE / AIMNet2) |
|
L4b Infra (I/O) |
|
出力レイアウト、サマリ、軌跡、PDB 修正、エネルギーダイアグラム、Hessian キャッシュ |
|
L5 Foundation |
|
defaults(共有defaultの主要source)、utils(structure / coordinate / plot helper)、logging、将来の |
(none、設計意図) |
(bundle, not a layer) |
|
repo 内部 fork(optimizer / thermochemistry) |
(sibling, layer-external) |
依存方向(設計目標): L1 → L2 → {L3, L4} → L5。全面的な top-to-bottom 方向は機械的には強制していません。強制対象の subset では product module graph を非循環(pdb2reaction/* モジュール間に強連結成分が無い)に保ち、core/domain から workflows/* への import を禁止します。CIは2つのゲートで別々の不変条件を検査します。.github/scripts/check_engineering_markers.py は # CHEMISTRY-RULE:{4,5,7} マーカーと # DOMAIN_PURE マーカー、MLIP SDK(fairchem/orb_models/mace/aimnet)が backends/ 下のみで import されることを検査し、.github/scripts/check_import_graph.py(静的AST import graph)は product cycleが無いこと・pysisyphus/** が pdb2reaction を import しないこと・core → workflows / domain → workflows back-edgeが無いことを検査します。残る許容される下向きedge / 一方向facadeは workflows/* → cli.common_options/cli.decorators/cli.help_pages、core/utils.py → domain.add_elem_info/io.structure_formats/io.charge、io/charge.py → domain.residue_data/io.structure_formats、io/structure_formats.py → domain.add_elem_info、io/trj2fig.py → backends です。正準residue table(domain/residue_data.py)、charge engine(io/charge.py)、console-gated charge-summary logger(core/utils.py)は既存importパス維持のため workflows/extract.py から再exportされます。同梱forkはlayer graph外にあり、絶対package path(from pysisyphus.X import Y)で各layerからimportできます。
2.2 パッケージツリーの ASCII マップ¶
pdb2reaction/ [GH: t-0hmura/pdb2reaction]
├── pyproject.toml packages.find = ["pdb2reaction*", ...] (glob, frozen)
├── README.md / CONTRIBUTING.md / CHANGELOG.md
├── docs/
│ ├── ja/architecture.md ← このファイル
│ └──... (Sphinx ドキュメントサイト)
├── pdb2reaction/ ← package body, 6-layer physical dir
│ ├── __init__.py PEP 562 lazy: _LAZY_SYMBOLS / _LAZY_MODULES + __getattr__
│ ├── __main__.py `from .cli import cli`
│ ├── _version.py / py.typed
│ │
│ ├── cli/ # === L1 Interface ===
│ │ ├── app.py Click group + _LAZY_SUBCOMMANDS registry (absolute paths)
│ │ ├── common_options.py @add_print_every_option / @add_irc_pos_def_option / @add_precision_option / @add_coord_type_option / @add_ml_charge_spin_options
│ │ ├── decorators.py resolve_yaml_sources / load_merged_yaml_cfg / _write_error_json
│ │ ├── help_pages.py --help-advanced pager
│ │ ├── bool_compat.py --flag / --no-flag normalization
│ │ └── default_group.py subcommand resolver, lazy module import
│ │
│ ├── workflows/ # === L2 Application ===
│ │ ├── all.py full pipeline orchestrator (extract → … → DFT)
│ │ ├── path_search.py / path_opt.py MEP search / COS wrapper
│ │ ├── tsopt.py / freq.py / irc.py / dft.py per-stage runners
│ │ ├── opt.py / sp.py / scan.py / scan2d.py /
│ │ │ scan3d.py / scan_common.py geometry opt / single point / scans
│ │ ├── extract.py active-site extraction CLI
│ │ ├── restraints.py restraint helpers
│ │ └── align_freeze.py Kabsch + frozen-subset rmsd
│ │
│ ├── domain/ # === L3 Domain ===
│ │ ├── bond_changes.py R↔P bond detection
│ │ ├── bond_summary.py post-IRC diagnostic
│ │ ├── add_elem_info.py PDB element column normalizer
│ │ └── residue_data.py 残基・イオン電荷table
│ │
│ ├── backends/ # === L4a Infra (MLIP) ===
│ │ ├── __init__.py backend dispatch + registry
│ │ ├── base.py MLIPCalculator protocol
│ │ ├── custom.py custom ASE-calculator adapter
│ │ ├── _determinism.py deterministic reduction shim
│ │ └── uma.py / orb.py / mace.py / aimnet2.py per-backend adapters
│ │
│ ├── io/ # === L4b Infra (I/O) ===
│ │ ├── summary.py summary.json / summary.log writer
│ │ ├── energy_diagram.py Plotly diagram
│ │ ├── trj2fig.py trajectory → PNG / SVG / PDF / HTML / CSV
│ │ ├── pdb_fix.py altloc resolution
│ │ ├── altloc.py altloc identity/選択helper
│ │ ├── charge.py 残基を考慮した電荷解決
│ │ ├── structure_formats.py PDB/mmCIF bridge + identifier復元
│ │ └── hessian_cache.py in-memory Hessian cache
│ │
│ └── core/ # === L5 Foundation ===
│ ├── defaults.py 共有defaultの主要source
│ ├── utils.py PDB / XYZ / plot helpers
│ ├── output.py / result_commit.py output/result ownership
│ └── pes_composition.py energy成分合成
│
├── tests/ smoke / unit
├── .github/ workflows/ + scripts/ (CI、release、engineering、documentation checks)
└── (repo-top sibling, layer-external bundled forks)
pysisyphus/ ~90 file, repo-internal fork (slimmed; CLI driver + QM backends + wavefunction + dead optimizers / IRC / NEB variants removed)
thermoanalysis/ 5 file, repo-internal fork
2.3 階層ごとの責務詳細¶
L1 cli/ は root group、lazy registry、argv 正規化、段階的help、共有option-decoratorを所有します。実際の @click.command() とcommand固有optionは workflow/utility module側にもあります。rootはそれらを解決して呼び出します。_LAZY_SUBCOMMANDS の各entryは 絶対module path を使います。
L2 workflows/ は計算command moduleに加え、scan_common.py、restraints.py、align_freeze.py などの共有stage helperを含みます。command moduleは通常 cli という @click.command() を1つ公開しますが、utility commandは io//domain/ にもあるため、「subcommandごとに必ず1file」「workflow fileはすべてcommand」という規則ではありません。
L3 domain/。torch / numpy / pysisyphus.constants(数値バックエンド)を import してよい化学的に意味を持つヘルパーロジックですが、MLIP ランタイム(fairchem, orb_models, mace, aimnet)を import しては いけません。この MLIP 非依存は .github/scripts/check_engineering_markers.py がリポジトリ全体で強制します。なお # DOMAIN_PURE docstring マーカーはこれとは別のゲートで、backend 非依存を保つべき特定の workflow モジュール(workflows/dft.py / workflows/tsopt.py / workflows/sp.py)にのみ付与され、domain/ のファイルには付きません。domain ヘルパーはどの L2 ステージランナーからでも再利用可能です。
L4a backends/。MLIP バックエンドディスパッチャ(__init__.py + base.py)と、サポートする各 MLIP につき1つのadapter(uma.py, orb.py, mace.py, aimnet2.py)があります。
L4b io/。出力側I/O: stage summary、energy diagram、trajectory render、PDB altloc修正、PDB/mmCIF bridge/template identifier復元、in-memory Hessian cache。output formatはここが所有しstage runnerが利用します。foundation外importは上記back-edge一覧を参照してください。
L5 core/ は最下層です。defaults.py は共有される数値/CLI defaultの 主要source です。まずここをgrepし、path engine choiceなど正当なcommand-local defaultも確認します。utils.py は設定・構造・座標・plotの共有helperを含みます。
2.4 遅延 import の仕組み(概念図)¶
External consumer Package root Layer dir
--------------------------------------- ---------------------- ---------
from pdb2reaction.core.utils import x ──► (direct dotted import) ──► pdb2reaction/core/utils.py
import pdb2reaction.io.trj2fig ──► (direct dotted import) ──► pdb2reaction/io/trj2fig.py
from pdb2reaction import <Symbol> ──► pdb2reaction/__init__.py
__getattr__("<Symbol>")
└─► _LAZY_SYMBOLS["<Symbol>"]
= "pdb2reaction.<layer>.<module>"
└─► importlib.import_module(...)
from pdb2reaction import <module> ──► pdb2reaction/__init__.py
(= module attr) __getattr__("<module>")
└─► _LAZY_MODULES["<module>"]
= "pdb2reaction.<layer>.<module>"
└─► importlib.import_module(...) returns module
pdb2reaction myaction ──► pdb2reaction/cli/app.py
_LAZY_SUBCOMMANDS["myaction"]
= ("pdb2reaction.workflows.myaction", "cli", "...")
└─► importlib.import_module(absolute path)
└─► getattr(module, "cli") → Click command
遅延 import 互換性の 2 階層と CLI ディスパッチ:
Root シンボル属性(
from pdb2reaction import <Symbol>)—pdb2reaction/__init__.py:_LAZY_SYMBOLS+ PEP 562__getattr__が処理します。シンボルは初回アクセス時に layer-dir パスから読み込まれ、pdb2reactionimport 時の import コストはゼロのまま保たれます。Root モジュール属性(
from pdb2reaction import <module>)—_LAZY_MODULESが処理します。__getattr__はimportlib.import_moduleを介してモジュールオブジェクト自体を返します。pdb2reactionは現在、参照されるモジュール属性パスは 0 件です(レジストリは空です。root 属性アクセスは将来の拡張のために予約されています)。
CLI サブコマンドリゾルバ(cli/app.py:_LAZY_SUBCOMMANDS)は 絶対 モジュールパス(例: "pdb2reaction.workflows.all")を使うため、default_group.py を cli/ に移動してもサブコマンド探索が気づかないうちに動かなくなることはありません(レジストリはもはや __package__ に依存しません)。
3. Fresh-eyes 5 ステップナビゲーション(合計 ≈ 40 分)¶
リポジトリを初めて開くコントリビュータは、この道筋を上から下へ辿ってください。各ステップで 1 つの関心事を片付けます。
step |
minutes |
open |
what you learn |
|---|---|---|---|
1 |
3 |
1 段落のエレベーターピッチ + 単一コマンド使用法 |
|
2 |
5 |
このファイル( |
6 階層のディレクトリツリー、依存方向、各関心事の所在 |
3 |
5 |
Click root group、 |
|
4 |
20 |
1つの完全なsubcommandを上から下まで追う |
|
5 |
7 |
|
5 つの add-a-X レシピ + 「触るな」という隠れた制約 |
ステップ 5 の後は、§4 のファイル索引を辿ることで他のどのファイルでも読めます。本パッケージは意図的に 各階層内でフラット です。pdb2reaction/<layer>/ の下にネストしたパッケージは存在しないため、2 ディレクトリより深く辿る必要は決してありません。
4. ファイル索引 — 「この関心事はどこにあるか?」¶
4.1 CLI / エントリ(L1 cli/)¶
concern |
file |
|---|---|
Click root group + サブコマンドディスパッチ |
|
サブコマンドリゾルバ(遅延 import) |
|
|
|
YAML ソース解決 + 標準化された例外処理 |
|
|
|
Bool flag 互換( |
|
共有 option-decorator ファクトリ( |
|
4.2 ワークフローステージランナー(L2 workflows/)¶
concern |
file |
|---|---|
全パイプラインオーケストレータ |
|
構造最適化(L-BFGS / RFO) |
|
Scanと2D/3D energy-landscape grid + 共有 |
|
MEP 探索(GSM) |
|
MEP optimizer コア(pysisyphus COS) |
|
TS 最適化(RS-P-RFO + Bofill + macro/micro) |
|
振動解析(backend-agnostic PHVA + active block) |
|
IRC 積分(macro / micro) |
|
一点 DFT(gpu4pyscf サブプロセス) |
|
活性部位抽出(クラスターキャップ) |
|
拘束ヘルパー |
|
Kabsch / frozen-subset アラインメント |
|
4.3 化学ヘルパー(L3 domain/)¶
concern |
file |
|---|---|
R↔P 結合変化検出 |
|
IRC 後の結合サマリ |
|
PDB 元素列正規化 |
|
残基・イオン電荷テーブル |
|
4.4 MLIP バックエンド(L4a backends/)¶
concern |
file |
|---|---|
バックエンドディスパッチ + レジストリ |
|
|
|
custom ASE calculator アダプタ |
|
決定論的 reduction shim |
|
バックエンドごとのアダプタ |
|
add-a-backend レシピは Backends を参照してください。
4.5 I/O(L4b io/)¶
concern |
file |
|---|---|
|
|
Plotly エネルギーダイアグラム |
|
軌跡 → PNG / SVG / PDF / HTML / CSV |
|
PDB altloc 解決 |
|
altloc identity と一貫した選択 |
|
残基を考慮した電荷解決 |
|
PDB/mmCIF bridge + identifier 復元 |
|
インメモリ Hessian キャッシュ(実行ごとの TTL) |
|
調和拘束のセットアップ |
|
4.6 Foundation(L5 core/)¶
concern |
file |
|---|---|
共有/数値default(主要source。command-local例外も確認) |
|
PDB / XYZ / plot ヘルパー |
|
|
|
output/result ownership helper |
|
energy 成分合成 |
|
4.7 repo 内部の同梱 fork¶
dir |
role |
主な divergent files(完全な一覧は各ディレクトリの README を参照) |
|---|---|---|
|
optimizer / TS / IRC エンジン |
|
|
thermochemistry(ΔG, ZPE, 分配関数) |
|
touch 制限の境界については各ディレクトリの README.md を参照してください。
5. 隠れた制約(パッチ前に必読)¶
5.1 化学ルール(grep レシピ)¶
正確性に直結する 3 つのルールは workflows/dft.py と workflows/tsopt.py に実装されています。これらは smoke テストでは検出 されません。ここでの静かな乖離は反応経路の精度を壊します。インラインの # CHEMISTRY-RULE:N マーカーと # DOMAIN_PURE モジュール docstring マーカーがルールを識別し、.github/scripts/check_engineering_markers.py が CI でマーカーの完全性を強制します。
編集前にすべての化学ルールを見つけるには:
# List all rule sites in the repo (host file + line)
grep -rnE '# CHEMISTRY-RULE:[0-9]+' pdb2reaction/
# List every # DOMAIN_PURE marker (= chemistry-rule host modules)
grep -rn '# DOMAIN_PURE' pdb2reaction/
3 つのルール(マーカー ID は連続していません)は次の通りです:
marker |
rule |
host file |
|---|---|---|
4 |
gpu4pyscf |
|
5 |
def2 family auto-ECP injection |
|
7 |
|
|
これらのいずれかを編集するには、[CHEMISTRY-RULE:N] コミットプレフィックス、
maintainer approval、該当する focused regression test、scheduled numerical benchmark が必要です。
CONTRIBUTING.md §4.1 と §5 を参照してください。
5.2 VRAM 管理の不変条件(del チェーンをリファクタしない)¶
IRC / TSopt / Freq ステージは、CUDA メモリを解放するためにステージ間で GPU 常駐オブジェクト(calc, geom, hess)を明示的に del します。ステージ境界では gc.collect() に加え、CUDA allocation がある場合は torch.cuda.empty_cache() も実行します。これらの解放処理をリファクタで取り除かないでください。大きな活性部位モデルを伴う長時間の all ジョブは、これらがないと OOM します。
5.3 同梱 fork: 上流を並べてインストールしない¶
同梱された pysisyphus/ と thermoanalysis/ パッケージは fork です。pip install pysisyphus または pip install thermoanalysis を本パッケージとは別に PyPI 版を再インストールすると、次が気づかないうちに動かなくなります:
pysisyphus/irc/IRC.py— 初期変位のメモリ管理 + オプトインのrequire_pos_def_hessiankwargpysisyphus/optimizers/hessian_updates.py— GPU 常駐の in-place rank-two Bofill 更新、オプトインのPYSIS_BOFILL_CPU_OFFLOAD=1フォールバックpysisyphus/tsoptimizers/TSHessianOptimizer.py— RSIRFO kwargs(fork 間でホストパッケージの import パスが分岐)pysisyphus/calculators/{Calculator,Dimer}.py— GPU 対応バックエンドフック(30 以上の QM バックエンドは削除済み。抽象 base + Dimer TS calculator のみ残存)pysisyphus/_array.py—optimizers/hessian_updates.py(および徐々に他のホットパスファイル)で使われるget_xp/_outer/_dot/_eighshimthermoanalysis/QCData.py— 上流との branding / I/O 差分
5.4 パッケージ変更には隔離インストール検証が必要¶
include glob(pdb2reaction*)は新しい層サブパッケージを自動探索するため、通常の内部ファイル追加で package discovery を変える必要はありません。package discovery や runtime dependency を変更する場合は、sdist と wheel を作成し、wheel の内容を検査し、クリーン環境でインストールした後に CLI smoke test を実行してください。これは付随的な refactor ではなく release contract の変更です。
5.5 _LAZY_SUBCOMMANDS レジストリは絶対パスを使う必要がある¶
pdb2reaction/cli/app.py:_LAZY_SUBCOMMANDS はすべてのサブコマンドを 絶対 モジュールパスで解決します。いずれかのエントリを相対 dotted import(".all" など)に戻すと、default_group.py が移動した際にサブコマンド探索が気づかないうちに動かなくなります。リゾルバの __package__ がパッケージルートから乖離するためです。
6. 同梱 fork(repo 内部)¶
pdb2reaction はリポジトリ最上位に 2 つ の repo 内部モジュールを同梱しています:
dir |
upstream PyPI? |
purpose |
scope of edits allowed |
|---|---|---|---|
|
NO — fork、 |
optimizer, TS, IRC, COS, calculators |
logic edit には再現された不具合または承認済み機能、focused regression test、該当する numerical/GPU benchmark が必要 |
|
NO — fork(branding 差分) |
ΔG, ZPE, 分配関数, |
logic edit には I/O または数値上の必要性と thermochemistry golden test が必要 |
各ディレクトリは分岐ファイルと touch 制限の境界を列挙した独自の README.md を持ちます。階層モデルから見ると、これらの fork は L1..L5 グラフの 外側 に位置します。どの階層も絶対パッケージパス(from pysisyphus.X import Y)でこれらを import でき、L1 → L2 → {L3, L4} → L5 の方向を壊しません。
7. 推奨される深掘りの読み順¶
Fresh-eyes ツアー(§3)の後は、この深さ優先の読み順に従ってください:
pdb2reaction/core/defaults.py— デフォルト値テーブルを頭に入れる; 下流のすべてはここから読みます。pdb2reaction/cli/app.py— Click root +_LAZY_SUBCOMMANDSレジストリ。pdb2reaction/workflows/all.py— 1 つの完全なパイプラインを上から下まで。pdb2reaction/workflows/extract.py— 活性部位クラスターキャップ。pdb2reaction/backends/__init__.py+base.py— MLIP ディスパッチャとバックエンドごとのアダプタ契約。pdb2reaction/workflows/tsopt.py— RS-P-RFO + Bofill scatter(CHEMISTRY-RULE:7)。pdb2reaction/workflows/freq.py— クラスターモデル上での振動解析。pdb2reaction/workflows/irc.py— VRAM 管理 + IRC 積分。pdb2reaction/workflows/dft.py— gpu4pyscf による一点 DFT(CHEMISTRY-RULE:4 + :5)。pdb2reaction/core/utils.py— 共有 PDB / XYZ / plot ヘルパー。