中核概念: チェックポイントとワークフローモデル#
クイックスタート では qc.chk.new(...).scf(ref="r").run() と書いて mychk.scf.energy を
読みました。この 1 行が、qc-rs の大きな考え方をすべて使っています。この章では思い切り立ち止まってモデルを
詳しく説明します。これが腑に落ちれば、ツールキット全体が見通せます — どの機能も、追加する 1 つのステップか、
読む 1 つの結果にすぎません。
チェックポイント#
すべては 1 つのオブジェクト、チェックポイントを中心に回ります。1 つの分子のための小さな実験ノートだと 思ってください。3 つのものを保持します:
分子 —
qc.chk.new(...)に与えた構造・基底関数・電荷・スピン。固定の入力です。現在の電子状態 — 電子を生成した直近のステップの結果:分子軌道(
current_mo)と電子密度 (current_density)。推定・SCF・CASSCF はいずれもこれを更新します。物性はこの状態を読みます。結果レコード — 実行したステップの成果:SCF エネルギーと収束したか、計算した物性、最適化の軌跡など。
作りたてのチェックポイントは分子を持ちますが、まだ電子状態がありません — 何も計算されていません。
2 つのフェーズ:組み立て → 実行#
qc-rs の計算は、明確に分かれた 2 つのフェーズで進みます。この分離こそ、理解すべき最重要点です。
1. 組み立て — pending ステップを追加#
qc.scf(mychk, ...)(またはメソッド形 mychk.scf(...))は何も計算しません。pending ステップ
(「ここで SCF がほしい」というメモ)を載せた新しいチェックポイントを返します。元のチェックポイントは
変更されません(チェックポイントは実質不変で、ステップは新しいものを返します):
base = qc.chk.new(atom="O 0 0 0.1173; H 0 0.7572 -0.4692; H 0 -0.7572 -0.4692",
ao="cc-pvdz", unit="angstrom")
pending = base.scf(ref="r") # pending SCF ステップを持つ新しいチェックポイント
pending is base # False — base は不変
pending.scf.energy # None — まだ何も実行していない
組み立ては安価で副作用がないので、複数ステップの計算を自由に組めます — 何ステップも連結し、分岐し、あるいは チェックポイントを関数に渡す — 何も走らせる前に。
2. 実行 — 結果を実体化#
.run() が実際に計算します。その後は結果アクセサが本物の値を返します:
done = pending.run()
done.scf.energy # -76.026772
done.scf.converged # True
重要
pending ステップ vs 結果アクセサ
同じ名前が .run() の前後で異なる意味を持ちます。mychk.scf(...) はステップを追加し(引数を取り、新しい
チェックポイントを返す)、mychk.scf.energy は完了したステップの結果を読みます(実行前は None)。
「作業を頼む」ことと「答えを読む」ことを分けているからこそ、計算を自由に組み立て、安全に再実行できます。
.run() が実際に行うこと#
pending ステップは小さな依存グラフ — DAG(有向非巡回グラフ)— を成します。.run() を呼ぶと、qc-rs は
明確に定義された一連の動作を行います:
依存を解決。 各ステップが何を必要とするか割り出す。SCF は軌道の初期推定と1 電子積分を、物性は 収束密度を、といった具合。
妥当な既定値を自動挿入。 明示的に要求しなかった依存には、安全な既定を挿入。特に、SCF に初期状態が なければ
sad推定(原子密度の重ね合わせ)を、そして既定の積分ステップを挿入。だからmychk.scf(ref="r").run()はそれだけで動きます —guess(...)やints(...)を手で書くことはほとんど ありません。順序付けと実行。 グラフをトポロジカル順に並べ、各ステップを順に実行し、結果をチェックポイントに 記録。
済みはスキップ。 まだ有効な結果は再利用し、再計算しない;欠けている/古いステップだけ実行。
刈り込み。 完了した pending ノードは消され、チェックポイントは次のステップを受け入れられる状態に。
覚えておく価値のある帰結が 2 つ:
.run()は再度呼んでも安全。 有効な結果は再利用されるので、再実行で完了済みの作業は繰り返されません。 中断後のリスタートもこの仕組み:チェックポイントを読み込み.run()すれば止まった所から続きます。気にかけるものだけ指定すればよい。 推定と積分は補われます。制御したい場合 — 別の推定、特定の積分戦略 — はそれらのステップを明示的に追加し、
.run()は既定の代わりにそれらを使います。
注釈
古さ(staleness)
結果は世代の概念を持ちます。ステップが依存するものを変えると、下流の結果は古いと印付けされ次の
.run() で再計算され、影響のないものは保持されます。正しさ(古いものは残らない)を、影響のない作業の
やり直しなしに得られます。
同じことの 2 通りの書き方#
すべてのワークフロー動詞に、関数形とメソッドチェーン形があります。等価なので、文脈で読みやすい方を:
# 関数形 # メソッドチェーン形
qc.scf(mychk, ref="r").run() mychk.scf(ref="r").run()
メソッドチェーン形は 1 行に、関数形はチェックポイントがヘルパー関数を流れるときに明快です。
結果を読む、物性を計算する#
.run() の後、結果はステップに対応した名前付きアクセサにあります:
done.scf.energy # 全エネルギー
done.scf.converged # SCF は収束したか
解析は別です:qc.prop.<group>.<leaf> 名前空間にあり、最初に要求したとき遅延計算され、以後キャッシュ。
チェックポイントの現在の電子状態を読みます:
qc.prop.chrg.mulliken(done) # {'charges': [...], 'atom_labels': [...]}
done.prop.chrg.mulliken() # 同じもの、メソッドチェーン形
物性グループは 14 個あります(電荷、結合次数、芳香族性、軌道、QTAIM、ELF、多重極、スピン、概念 DFT、ESP、
実空間場、スペクトル、ジオメトリ …)— スイート全体は 分子物性。実行時に
まとめて先行計算する scf(prop=...) もあります。
保存と読み込み#
チェックポイント — 分子・現在の電子状態・すべての結果 — はディスクに書き出し、あとで再計算なしに復元 できます:
done.save("water") # チェックポイントを保存(HDF5 .qch5 ファイル)
later = qc.chk.load("water") # 復元(例:新しいセッションで)
later.scf.energy # -76.026772 — 直に読み戻し、再計算なし
読み込んだチェックポイントは結果を保持しているので、さらにステップを追加して .run() もできます — 既存の
結果は再利用され、新しい作業だけが走ります。
なぜこの設計か#
組み立てと実行を、そして pending ステップと結果を分けることで、初学者が後で恩恵を感じる 3 つが得られます:
組み立て可能性 — 計算は 1 ステップずつ拡張する短いパイプライン;組み立ては安価で驚きがない。
リスタート可能性 —
.run()は有効な結果を再利用するので、長いジョブは最初からでなく再開;保存した チェックポイントは再開可能なスナップショット。来歴(provenance) — どの電子状態がどの結果を生んだかを記録するので、解析が何から計算されたか曖昧に なりません。
このモデルを手にすれば、マニュアルの残りは本質的にカタログです:追加できるステップ(guess, ints, scf, opt, lct, td, …)と、読める結果(エネルギー、勾配、物性スイート)。次はその背後の理論を Part II — 基礎 で、あるいは ユーザーガイド に飛び込んでください。