trimci.ground_state Tutorial新手教程

Three parameters, from molecular integrals to a converged ground-state energy. 三个参数,从分子积分到收敛的量子化学基态能量

Contents目录

  1. 30-second quick start30 秒速通
  2. The three parameters三个参数详解
  3. Recipe table (pick by accuracy)配方表(按精度选)
  4. The Result objectResult 对象
  5. Three input modes三种输入方式
  6. Save / load results保存 / 读取结果
  7. Decision tree决策树
  8. Advanced — full Config control高级 — Config 全量控制
  9. Common questions & pitfalls常见问题与陷阱

1. 30-second quick start 1. 30 秒速通

Have a FCIDUMP file? Three lines: 有 FCIDUMP 文件?三行代码:

Python

import trimci

result = trimci.ground_state("FCIDUMP")
print(result.energy)        # variational energy (Ha)
print(result.energy_pt2)    # + PT2 correction

No FCIDUMP, just h1 and eri arrays? Also three lines: 没有 FCIDUMP,只有 h1eri 数组?也三行:

Python

result = trimci.ground_state((h1, eri, n_elec))
print(result.summary())
What's happening underneath?底层在做什么? Internally runs a 3-phase workflow automatically: Phase 0 TrimCI Core Search + orbital optimization → Phase 1 expansion + orbopt refinement → Phase 2 final expansion + PT2. All parameters have sensible defaults. 自动跑 3 阶段 workflow:Phase 0 TrimCI Core Search + 轨道优化 → Phase 1 expansion + orbopt refinement → Phase 2 final expansion + PT2。所有参数都有合理默认值。

2. The three parameters 2. 三个参数详解

problem
Problem input.问题输入 Supports four forms:。支持四种形式:
  • FCIDUMP file path (string) — most common; spin read from the file's MS2 headerFCIDUMP 文件路径(字符串)— 最常用;自旋由文件 MS2 字段决定
  • (h1, eri, n_elec) tuple — pass spin via ms2; e_nuc defaults to 0(h1, eri, n_elec) 元组 — 用 ms2 指定自旋;e_nuc 默认 0
  • (h1, eri, n_elec, e_nuc) tuple — fully specified, ms2 kwarg sets spin(h1, eri, n_elec, e_nuc) 元组 — 完整指定,ms2 kwarg 设自旋
  • PySCF mean-field object — spin taken from mf.mol.spin; pass active=(n_e, n_o) for an active spacePySCF mean-field 对象 — 自旋取自 mf.mol.spin;用 active=(n_e, n_o) 指定活性空间
Open-shell is fully supported across all input modes.所有输入模式都支持开壳层。
n_dets
Target determinant count.目标 determinant 数 Determines final accuracy — larger is more accurate. Internally split on a log scale into Phase 0/1/2 caps (e.g. n_dets=10⁸1k / 1M / 10⁸). 。决定最终精度 — 越大越准。内部按 log scale 自动切成 Phase 0/1/2 三段(例如 n_dets=10⁸ 切成 1k / 1M / 10⁸)。
  • Default 100_000默认 100_000
  • Wall scales logarithmically with n_dets越大越接近 FCI,wall 时间随 n_dets log 增长
effort
Workload multiplier工作量倍数 , controlling Phase 0 stochastic exploration intensity. ,控制 Phase 0 的 stochastic 探索强度。
  • effort=0.4 is the sweet spot — leave it alone (based on Fe4S4 measurements)effort=0.4 是 sweet spot — 不用调(基于 Fe4S4 实测)
  • effort=1.0 matches TrimCI_skill defaults (num_runs=64, BFGS=50 iter)effort=1.0 对齐 TrimCI_skill 默认(num_runs=64, BFGS=50 iter)
  • effort=0.05 for a quick smoke testeffort=0.05 快速 smoke test
Scaling: num_runs ≈ 64×effort (BFGS maxiter fixed at 100 — exits early when converged).具体 scaling: num_runs ≈ 64×effort(BFGS maxiter 固定 100,收敛即提早退出)。

Optional kwargs 可选参数

ms2
2·S_z = n_alpha - n_beta2·S_z = n_α - n_β. Default 0 (closed-shell singlet). For the (h1, eri, n_elec) path: pass ms2=1 for doublet, ms2=2 for triplet, etc. For FCIDUMP path: the file's MS2 field is authoritative (passing ms2 here warns and is ignored). 默认 0(闭壳层单重态)。(h1, eri, n_elec) 路径:ms2=1 doublet,ms2=2 triplet 等。FCIDUMP 路径:以文件 MS2 字段为准(此 kwarg 会被忽略并 warn)。
Key insight关键经验 Measurements show n_dets is the dominant axis; effort is secondary. effort=0.4 is already good enough; for higher accuracy, scale n_dets, not effort. If your n_dets request exceeds the Hilbert dim, it's auto-clamped (see res.diagnostics.n_fci). 实测发现 n_dets 是主导轴,effort 次之。effort=0.4 已经够好;要更高精度优先扩 n_dets,不是堆 effort。n_dets 超 Hilbert 维度时自动 clamp(查 res.diagnostics.n_fci)。

3. Recipe table 3. 配方表 measured on Fe4S4 (54e, 36o)Fe4S4 (54e, 36o) 实测

Values below come from a 9-point n_dets sweep on a 32-core x86 node (effort=0.4 fixed). Wall times will scale with your hardware. 下面这张表来自跨 9 个 n_dets 的实测扫描,跑在 32 核 x86 节点上(effort=0.4 固定)。不同硬件 wall 时间会不同。

Goal目标 Call调用 Expected E_PT2 (Ha)期望 E_PT2 (Ha) Typical wall典型 wall
Smoke test (just confirm it runs)烟雾测试(确认能跑) ground_state(p, n_dets=100, effort=0.05) -327.17 ~2 min
Quick estimate快速估算 ground_state(p, n_dets=3000) -327.18 ~4 min
Balanced accuracy/cost平衡精度/成本recommended推荐 ground_state(p, n_dets=100_000) -327.224 ~5 min
High accuracy高精度 ground_state(p, n_dets=1_000_000) -327.231 ~10 min
Larger scale更大规模 ground_state(p, n_dets=3_000_000) -327.235 ~16 min

4. The Result object — how to extract data 4. Result 对象 — 怎么取数据

The returned Result has three layers. The 5 most commonly used fields are at the top: 返回的 Result 分三层。最常用的字段在顶层(5 个):

Top-level shortcuts

res = trimci.ground_state("FCIDUMP")

res.energy          # float — variational total energy (Ha)
res.energy_pt2      # float | None — variational + PT2
res.n_dets          # int   — final det count
res.wall_time       # float — total wall (seconds)

To judge whether the result is "converged enough" for your purpose, look at: 想判断结果是不是"够收敛",看:

Sub-objects: .energies / .wavefunction / .diagnostics 子对象:.energies / .wavefunction / .diagnostics

Energies — energy decompositionEnergies — 能量分解

res.energies.var               # variational energy
res.energies.pt2_correction    # ΔE_PT2 (≤ 0)
res.energies.nuclear           # nuclear repulsion
res.energies.electronic        # = var - nuclear
res.energies.history           # energy trajectory across all rounds [list]
res.energies.pt2_history       # per-round ΔPT2 [list]

Wavefunction

wf = res.wavefunction

wf.coeffs          # (N,) ndarray — amplitudes
wf.dets            # (N, 2K) ndarray — α+β bitstrings stacked
wf.alpha_bits      # (N, K) uint64
wf.beta_bits       # (N, K) uint64
wf.n_orb
wf.is_normalized   # normalization check

# advanced extraction
wf.leading(5)    # top-5 dets: [(α_bits, β_bits, c), ...]
wf.occupation_numbers()  # per-orbital occupation (n_orb, 2) [α, β]

# dict-like access (backward compat)
wf["110011|110011"]   # lookup amplitude by bitstring
for bits, c in wf.items():
    ...

Diagnostics — performance / Hilbert dim / configDiagnostics — 性能 / Hilbert 维度 / 配置

d = res.diagnostics

d.wall_phase0       # Phase 0 (orbopt) time
d.wall_expansion    # Phase 1+2 expansion time
d.n_dets_phase0     # det count after Phase 0
d.n_dets_final      # final det count
d.expansion_rounds  # total Phase 1+2 rounds
d.n_fci             # full Hilbert dim = C(n_orb, n_α)·C(n_orb, n_β)
                    # requested n_dets is auto-clamped to this
d.orbopt_dir        # Phase 0 orbopt npz dir (or None)
d.checkpoint_dir    # Phase 1+2 checkpoint dir (or None)
d.config            # the Config dataclass used for this run

Final rotated orbitals (lazy, loaded from disk) 最终旋转后的轨道(lazy 从磁盘加载)

# Integrals in the FINAL basis (after both Phase 0 and Phase 1 orbopt):
res.final_h1            # (n_orb, n_orb)
res.final_eri           # (n_orb, n_orb, n_orb, n_orb)

# Cumulative rotation: C_final = C_input @ U
res.orbital_rotation    # (n_orb, n_orb) orthogonal matrix

# Sanity check: U^T · h1_input · U should equal final_h1
assert np.allclose(
    res.orbital_rotation.T @ h1_input @ res.orbital_rotation,
    res.final_h1,
)

Human-readable summary人类可读 summary

print(res.summary())

# Output (example):
# TrimCI Calculation Summary
#   Energy (var):     -327.1937 Ha
#   Energy (PT2):     -327.1957 Ha  (ΔPT2 = -0.002)
#   Determinants:     800  (Phase 0: 100)
#   Wall (Phase 0):   3.1 min
#   Wall (Expansion): 0.7 min  (12 rounds)
#   Wall (total):     3.8 min

5. Three input modes 5. 三种输入方式

Mode A: FCIDUMP file (most common)方式 A: FCIDUMP 文件(最常用)

res = trimci.ground_state("path/to/FCIDUMP", n_dets=100000)

Mode B: (h1, eri, n_elec) tuple方式 B: (h1, eri, n_elec) 元组

import numpy as np

# 4-site Hubbard ring, U=4, t=1
n = 4
h1 = np.zeros((n, n))
eri = np.zeros((n, n, n, n))
for i in range(n):
    j = (i + 1) % n
    h1[i, j] = h1[j, i] = -1.0
    eri[i, i, i, i] = 4.0

res = trimci.ground_state((h1, eri, 4), n_dets=30)
# E_var = -2.1027484 Ha — matches exact FCI

# Open-shell: pass ms2 = 2·S_z = n_alpha - n_beta
res = trimci.ground_state((h1, eri, 3), ms2=1)   # doublet
res = trimci.ground_state((h1, eri, 4), ms2=2)   # triplet

The 4-tuple form (h1, eri, n_elec, e_nuc) lets you specify nuclear repulsion explicitly. 四元组形式 (h1, eri, n_elec, e_nuc) 让你显式指定核排斥。

Mode C: PySCF mean-field (a converged mf object)方式 C: PySCF mean-field(已收敛的 mf 对象)

from pyscf import gto, scf

mol = gto.M(atom="N 0 0 0; N 0 0 1.1", basis="sto-3g")
mf = scf.RHF(mol).run()

# Unified entry — same as Mode A/B
res = trimci.ground_state(mf, n_dets=10000)

# For an active space: pass active=(n_e, n_o)
# res = trimci.ground_state(mf, n_dets=10000, active=(8, 8))

6. Save / load results 6. 保存 / 读取结果

For large-n_dets calculations, save your results. Default is NPZ (compressed binary): 大 n_dets 跑出来的结果,务必存盘。默认 NPZ 格式(压缩二进制):

res.save("my_calc.npz")         # NPZ — recommended
res.save("my_calc")             # auto-appends .npz
res.save("my_calc.json")        # JSON — only for small n_dets / debug

# load back
res2 = trimci.Result.load("my_calc.npz")
print(res2.energy)               # exact round-trip across processes
Why NPZ?为什么 NPZ? N=1M dets in JSON ≈ 100 MB; in NPZ+zlib ≈ 5-15 MB (8-20× smaller), and dtypes like uint64/complex128 are preserved exactly. Always use NPZ unless you need to read it by eye. N=1M dets 的 JSON 大约 100 MB,NPZ + zlib 压缩约 5-15 MB(缩 8-20×),还保留 uint64/complex128 等 dtype。除非要肉眼检视,都用 NPZ。

7. Decision tree: tune for your scenario 7. 决策树:我的场景该怎么调

Just want to confirm TrimCI runs (don't care about energy) 想确认 TrimCI 能跑(不在乎能量)
trimci.ground_state(p, n_dets=100, effort=0.05)
# ~2 min, absolute value off by ~100 mHa, but you'll know if import + workflow are healthy
Small molecule (n_orb ≤ 10) for benchmarking 小分子(n_orb ≤ 10)做基准
trimci.ground_state(p, n_dets=10_000)
# Usually nails FCI. Cross-check with pyscf FCI: diff < 0.1 mHa
Mid-size system (n_orb ~ 30), production answer 中等体系(n_orb ~ 30)想 production 答案
trimci.ground_state(p, n_dets=100_000)
# Fe4S4: -327.224 Ha in 5 min, ~7 mHa above theoretical limit
Pursuing high accuracy 追求高精度
trimci.ground_state(p, n_dets=1_000_000)
# Fe4S4 single run: ~-327.23 Ha in ~10 min
# For tighter bounds, run multiple seeds and take the best/mean.
Strongly correlated (stretched bonds, transition-metal clusters) 极强关联(拉伸键、过渡金属簇等)
trimci.ground_state(p, n_dets=3_000_000)
# Measured: N2 r=2.5 Å (823 mHa correlation) → FCI at n=2000
# Fe4S4-scale clusters: 1M-3M recommended
Tight wall budget on a laptop 本地 wall 紧(笔记本跑)
  • Drop n_dets to the 10k-100k range; leave effort alonen_dets 到 10k-100k 区间,effort 不动
  • Don't push effort below 0.05 — Phase 0 becomes too weak, orbitals inaccurate不要降 effort 到 0.05 — Phase 0 太弱 orbital 不准

8. Advanced — full Config control 8. 高级 — Config 全量控制 advanced

When 3 parameters aren't enough, construct a Config and pass it via the config= kwarg of ground_state: 当三参数不够用时,构造 Config 对象,通过 ground_stateconfig= 关键字传入:

from trimci import Config

cfg = Config(
    # Phase 0
    num_runs=128,
    orbopt_cycles=8,
    orbopt=True,
    max_dets_phase0=500,
    tracking_dets=True,
    loaded_dets_randomness=0.1,
    # Phase 1 (orbopt + expansion)
    max_dets_phase1=100_000,
    growth_factor_phase1=1.1,
    orbopt_phase1=True,
    use_connection_cache_phase1=True,
    # Phase 2 (final expansion)
    max_dets_phase2=1_000_000,
    growth_factor_phase2=2.0,
    pt2_correction=True,
    pt2_only_last=True,   # PT2 only at the final round; saves time
    # Reproducibility (None = fresh entropy per call; int = deterministic)
    seed=42,
    # Performance
    n_cpu_workers=8,           # Phase 0 parallel subprocesses
    n_gpu_workers=0,
    backend_phase1="cpu",     # or "gpu", "auto"
    # Advanced PT2 override
    phase2_overrides={"pt2": {"sketch_width": 500_000}},
)

# config= works with any input type:
res = trimci.ground_state("FCIDUMP", config=cfg)
res = trimci.ground_state((h1, eri, 14, 0.0), config=cfg)
res = trimci.ground_state(mf, config=cfg)
n_fci auto-clampn_fci 自动 clamp If the requested n_dets exceeds the Hilbert dim C(n_orb, n_α) × C(n_orb, n_β), the Phase 0/1/2 caps are silently right-sized at the dispatcher (no warning needed — full FCI is the correct ceiling). Available as res.diagnostics.n_fci. 用户请求的 n_dets 超过 Hilbert 维度 C(n_orb, n_α) × C(n_orb, n_β) 时,dispatcher 静默把 Phase 0/1/2 caps 切到正确大小(不警告 — full FCI 本来就是天花板)。值在 res.diagnostics.n_fci
Reproducibility via seed用 seed 复现 Config(seed=42) drives Phase 0 TrimCI Core Search + PT2 sketches + loaded-det random walks from a master seed. Same seed → bitwise-identical Result (modulo OMP non-determinism, ~1e-12 Ha). Default seed=None draws fresh entropy on each call. Config(seed=42) 用 master seed 驱动 Phase 0 TrimCI Core Search + PT2 sketch + 继承 det 的 random walk。相同 seed → bitwise 一致 Result(除 OMP 非确定性的 ~1e-12 Ha 抖动)。默认 seed=None 每次取新熵。

Default values (auto-applied by ground_state) 默认参数(ground_state 自动用)

Parameter参数 Default默认值 Meaning含义
orbopt_cycles 5 (fixed)5 固定 Phase 0 orbital optimization passes.Phase 0 轨道优化轮数
tracking_dets True Carry dets between cycles instead of fresh random restarts.cycle 间继承 dets,不每次随机重启
loaded_dets_randomness 0.1 ~5 random single-excitations on carried dets to avoid basin lock-in.继承的 det 上做 ~5 步随机激发,避免 basin 锁死
pt2_only_last True Skip per-round PT2 during Phase 2 expansion; evaluate only at final det count.Phase 2 expansion 不做 per-round PT2,只在最终评估
num_runs round(64 × effort) Phase 0 stochastic exploration count.Phase 0 stochastic 探索次数
orbopt_max_iter 100 (fixed)100 (固定) Phase 1 BFGS step cap. Exits early when converged — cap rarely binds.Phase 1 BFGS 单 cycle 上限。收敛即提早退出,cap 几乎不触底
seed None None ⇒ fresh entropy. Set int for reproducible runs / multi-seed variance studies.None ⇒ 每次新随机。设 int 用于复现 / multi-seed 方差研究

9. Common questions and pitfalls 9. 常见问题与陷阱

Q: Energy isn't monotonic; higher effort gives worse results 问题:能量没收敛单调,effort 越高反而越差

The variance of a single stochastic realization can exceed the expected gap between different effort levels. Pass config=Config(seed=42, ...) to ground_state to make a run reproducible, then sweep seeds to estimate variance. Or just scale up n_dets instead of pushing effort. 原因:单次 stochastic 实现的方差大于不同 effort 之间的期望差。给 ground_stateconfig=Config(seed=42, ...) 可复现一次运行;扫多个 seed 可估方差。或者直接扩 n_dets 而不是堆 effort。

Q: I bumped n_dets but the wall barely grew 问题:n_dets 设很大但 wall 没怎么涨

This is expected. Phase 0 (orbital optimization) dominates wall time and barely scales with n_dets; Phase 1+2 expansion is relatively cheap under the default settings. 这是正常现象。Phase 0(轨道优化)是主要 wall 来源,几乎不随 n_dets 变化;Phase 1+2 expansion 在默认配置下成本相对较低。

Q: res.energy_pt2 is None 问题:res.energy_pt2 is None

Either pt2_correction is disabled, or n_dets has covered the full Hilbert space (FCI-saturated — no external dets for PT2 to add). Read res.energy directly. 说明 pt2_correction 被关了,或者 n_dets 已经覆盖了完整 Hilbert 空间(FCI saturated,PT2 没有外部 det 可加)。看 res.energy

Q: Does n_orb > 64 cause problems? 问题:n_orb > 64 是不是有问题

No. Wavefunction.alpha_bits has shape (N, K) where K = ceil(n_orb / 64) uint64 segments. All API surfaces (leading(), to_dict(), save/load) handle multi-segment dets correctly. 没问题。Wavefunction.alpha_bits(N, K) 形状,K = ceil(n_orb / 64) 个 uint64 segments。所有 API(leading()to_dict()、save/load)都正确处理多 segment。

Q: Error PySCF is required to write FCIDUMP 问题:报错 PySCF is required to write FCIDUMP

The (h1, eri) tuple path calls pyscf.tools.fcidump.from_integrals under the hood. Either install PySCF or pre-write the FCIDUMP file yourself and pass the path. (h1, eri) 元组路径会调用 pyscf.tools.fcidump.from_integrals。装 PySCF 或者自己用 FCIDUMP 文件路径替代。

Q: How do I run open-shell (spin ≠ 0)? 问题:开壳层(spin ≠ 0)怎么跑

Three options, depending on input form: 视输入形式,三种方式:

Q: Five minutes in and no energy printed 问题:跑了 5 分钟还没出能量

Check stdout for Phase 0 progress before res.diagnostics — Phase 0 prints continuously. If stuck in Cycle 1, orbopt_max_iter may be too high or the system is hard to converge. Try effort=0.05 first to confirm the workflow runs. res.diagnostics 之前先看 stdout — Phase 0 会 print progress。若卡在 Phase 0 cycle 1,可能是 orbopt_max_iter 太大 / 体系难收敛。试 effort=0.05 先验证 workflow 通。