中核概念: チェックポイントとワークフローモデル#

クイックスタート では qc.chk.new(...).scf(ref="r").run() と書いて mychk.scf.energy を 読みました。この 1 行が、qc-rs の大きな考え方をすべて使っています。この章では思い切り立ち止まってモデルを 詳しく説明します。これが腑に落ちれば、ツールキット全体が見通せます — どの機能も、追加する 1 つのステップか、 読む 1 つの結果にすぎません。

チェックポイント#

すべては 1 つのオブジェクト、チェックポイントを中心に回ります。1 つの分子のための小さな実験ノートだと 思ってください。3 つのものを保持します:

  1. 分子qc.chk.new(...) に与えた構造・基底関数・電荷・スピン。固定の入力です。

  2. 現在の電子状態 — 電子を生成した直近のステップの結果:分子軌道current_mo)と電子密度current_density)。推定・SCF・CASSCF はいずれもこれを更新します。物性はこの状態を読みます。

  3. 結果レコード — 実行したステップの成果: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 は 明確に定義された一連の動作を行います:

  1. 依存を解決。 各ステップが何を必要とするか割り出す。SCF は軌道の初期推定1 電子積分を、物性は 収束密度を、といった具合。

  2. 妥当な既定値を自動挿入。 明示的に要求しなかった依存には、安全な既定を挿入。特に、SCF に初期状態が なければ sad 推定(原子密度の重ね合わせ)を、そして既定の積分ステップを挿入。だから mychk.scf(ref="r").run() はそれだけで動きます — guess(...)ints(...) を手で書くことはほとんど ありません。

  3. 順序付けと実行。 グラフをトポロジカル順に並べ、各ステップを順に実行し、結果をチェックポイントに 記録

  4. 済みはスキップ。 まだ有効な結果は再利用し、再計算しない;欠けている/古いステップだけ実行。

  5. 刈り込み。 完了した 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 — 基礎 で、あるいは ユーザーガイド に飛び込んでください。