二電子積分と J/K 戦略#

量子化学計算で最大の性能レバーは、二電子積分をどう扱うかです。それらは \(\mathcal{O}(N^4)\) 個あり、各 SCF サイクルがそれらをクーロン(J)と交換(K)行列に縮約します。qc-rs はその選択を単一のキーワード ints(eri=...) で公開し、その選択は前 3 章のあらゆる並列レベルと相互作用します。本章は、正しいものを選べるよう 選択肢を地図化します。

理論:なぜ積分の扱いが支配するのか#

\(N\) 個の基底関数に対し、一意な二電子積分 \((\mu\nu|\lambda\sigma)\) は形式上 \(N^4/8\) 個あります。\(N = 500\) で 約 80 億個 — しばしば保存するには多すぎ、再計算するには高価です。以降のあらゆる手法(SCF, MP2, …)はここで 律速されるので、戦略の問いは実際には:保存するか、再計算するか、ディスクに置くか、近似するか? です。各答えは メモリと CPU 時間を異なる形でトレードオフするので、単一の最良の選択はありません — 分子とハードウェア次第です。

統一された eri=#

すべては ints(...) の 1 キーワードで、2 つのファミリに分かれます。

4 中心ファミリ — 厳密な積分#

真の \((\mu\nu|\lambda\sigma)\) 積分を使い(近似なし)、ビット単位で同一のエネルギーを与え、積分がどこに あるかだけが異なります:

eri=

戦略

適する場面

4c-auto (既定)

メモリ梯子を歩く:incore → ramdisk → disk → direct

とりあえず動く

4c-incore

積分を RAM に保存

小〜中、RAM に余裕(最速)

4c-direct

毎サイクル積分を再計算、何も保存しない

大、RAM 制限

4c-disk

積分を一度ディスクに書き、毎サイクルストリーム

アウトオブコア、速いスクラッチディスク

4c-ramdisk

疎ディスク符号化を RAM に保持

大/疎、MPI ランクに分散

4c-auto は安全な既定 — 収まる最もメモリを食う選択肢を選び、優雅にフォールバックします。RI(下記)を決して 選びません;RI は明示的にのみ選ばれます。

RI(密度フィッティング)ファミリ — 近似、はるかに安価#

RI(恒等分解、ポスト SCF の章 より)は 4 指標積分を補助基底を介して分解し、 小さく制御された フィッティング誤差と引き換えにコストを劇的に削ります。2 つの副ファミリは、フィットした factor を 保存するか再計算するかで異なります:

eri=

戦略

注記

ri-ram

白色化 RI factor を一度構築し RAM に保持(MPI で μ 分散)

incore 速度・recompute メモリ — 規模での store-B 既定

ri-recomp

毎サイクル 3 中心積分を再計算、factor を保存しない

メモリ倹約の RI

ri-recomp-disk

再計算 + より小さな占有 factor をディスクに書く

アウトオブコア RI

GPU メンバー(ri-cuda, ri-recomp-cuda, ri-ram-cuda)は GPU の章 にあります。RI は補助基底を 必要とします;rijk= を与えないと、qc-rs は軌道基底から既定の JK-fit 補助を自動導出します。

厳密 対 RI:フィッティング誤差、検証#

4 中心戦略は厳密で最後の桁まで一致します;RI 戦略は小さなフィッティング誤差を持ちますがはるかに安価です。 水/cc-pVDZ(RHF)で:

import qc
water = "O 0 0 0.117; H 0 0.757 -0.469; H 0 -0.757 -0.469"

for eri in ("4c-incore", "4c-direct", "ri-ram", "ri-recomp"):
    e = qc.chk.new(atom=water, ao="cc-pvdz", unit="angstrom",
                   rijk="cc-pvdz-jkfit").ints(eri=eri).scf(ref="r").run().scf.energy
    print(f"{eri:11} {e:.6f}")
# 4c-incore   -76.026794   ← 厳密
# 4c-direct   -76.026794   ← 厳密(incore とビット単位で同一)
# ri-ram      -76.026773   ← RI: +2.1e-5 フィッティング誤差
# ri-recomp   -76.026773   ← RI: ri-ram と同一

2 つの 4 中心戦略はビット単位で同一(−76.026794);2 つの RI 戦略は互いに同一(−76.026773)で、厳密とは わずか 2.1 × 10⁻⁵ Ha だけ異なります — 化学的精度をはるかに下回る RI フィッティング誤差です。だから RI は 無視できる制御された誤差で、大きな速度/メモリの利得を買います。

戦略の選び方#

実務的な決定ガイド:

  • 既定 / 不明4c-auto。うまく選び、RAM が厳しければフォールバック。

  • 小〜中、RAM に余裕、厳密で最速が欲しい4c-incore

  • 大、RAM 制限、厳密が欲しい4c-direct(再計算)または 4c-disk(アウトオブコア)。

  • 大、大きな速度/メモリの利得が欲しく ~1e-5 Ha を許容できるRI ファミリ(factor が RAM に収まれば ri-ram、収まらなければ ri-recomp)。規模での通常の選択で、RI-MP2 の唯一の経路。

  • GPU 利用可能4c-cuda / ri-cuda

RI は MPI とも合成して 1 ノードのメモリの壁を破ります(ri-ram は factor を AO 番号で分散するので、ランク あたりメモリ ≈ 全体 / ランク数MPI の章)。

補助基底と関連ノブ#

qc.chk.new(..., rijk="cc-pvdz-jkfit")     # RI J/K の JK-fit 補助(既定は自動導出)
qc.chk.new(..., ric="cc-pvdz-ri/mp2fit")  # RI-MP2 の相関フィット補助(ポスト SCF の章)

eri="none" は二電子構築を完全に飛ばします(1 電子のみのワークフロー用)。アウトオブコアのノブ(疎レイアウト、 ドロップ許容差、I/O モード)は integral.disk.* 下の iop キーです — IOP リファレンス 参照。

総合例#

import qc
water = "O 0 0 0.117; H 0 0.757 -0.469; H 0 -0.757 -0.469"

exact = qc.chk.new(atom=water, ao="cc-pvdz", unit="angstrom").ints(eri="4c-incore").scf(ref="r").run()
ri    = qc.chk.new(atom=water, ao="cc-pvdz", unit="angstrom",
                   rijk="cc-pvdz-jkfit").ints(eri="ri-ram").scf(ref="r").run()

print(f"exact (4c) : {exact.scf.energy:.6f}")   # -76.026794
print(f"RI         : {ri.scf.energy:.6f}")       # -76.026773
print(f"fitting err: {abs(exact.scf.energy - ri.scf.energy):.2e} Ha")   # 2.1e-05

練習 20

  1. 大きな分子の cc-pVTZ 計算が 4c-incore でメモリ不足エラーで落ちます。走らせられる異なる eri= 戦略を 2 つ、 各々のトレードオフとともに挙げなさい。

  2. ri-ramri-recomp互いに同じエネルギーを与えるのに、4c-incore とはわずかに異なるのはなぜですか。

  3. RI-MP2 を走らせたいです。どの eri= ファミリが必須で、どの追加の基底キーワードを設定せねばなりませんか。

これで Part IV は完結です。qc-rs 計算を CPU スレッド・クラスタ上の MPI ランク・NVIDIA GPU にわたって スケールさせ、分子とハードウェアに合った積分戦略を選べます。ここから、リファレンス の各節が、あらゆる入力とオプションの正確な詳細を与えます。