stastical_physics.state_sum のソースコード

"""
多粒子系の分配関数(Partition Function)の積の性質を検証するモジュール。

概要:
    複数の独立な粒子が存在する系において、全状態和としての分配関数 $Z_{tot}$ が、
    各粒子の分配関数 $Z_p$ の積に等しいことを数値的に検証します。

詳細説明:
    1. 各粒子に対して、ランダムなエネルギー準位 $\epsilon_{i}$ を生成します。
    2. 手法1(全組み合わせ):
       itertools.product を用いて、すべての粒子の状態の組み合わせを網羅し、
       全エネルギー $E = \sum \epsilon$ に対するボルツマン因子 $\exp(-E/k_B T)$ を足し合わせます。
    3. 手法2(分配関数の積):
       各粒子ごとに分配関数 $Z_p = \sum \exp(-\epsilon/k_B T)$ を計算し、それらを掛け合わせます。
    4. 両者の結果が一致することを確認し、独立系における計算の簡略化を理解します。

理論式:
    $$Z_{total} = \sum_{s_1, s_2, \dots} e^{-\beta(\epsilon_{s_1} + \epsilon_{s_2} + \dots)} = \prod_{p} \left( \sum_{s} e^{-\beta \epsilon_{s,p}} \right)$$

関連リンク: :doc:`state_sum_usage`
"""

import sys
from numpy import exp
import random
import itertools

[ドキュメント] def generate_energy_levels(ns): """ 0から1の範囲でランダムなエネルギー準位($k_B T$ で正規化済み)を生成します。 """ return [random.random() for _ in range(ns)]
[ドキュメント] def main(): """ 分配関数の2通りの計算と、結果の比較を行います。 """ # ------------------------ # パラメータ設定 # ------------------------ n_particles = 2 n_states = 3 argv = sys.argv if len(argv) > 1: n_particles = int(argv[1]) if len(argv) > 2: n_states = int(argv[2]) print(f"\n--- Partition Function Verification ---") print(f"Number of particles (np): {n_particles}") print(f"Number of states per particle (ns): {n_states}") # 各粒子のエネルギー準位を生成 eps_list = [generate_energy_levels(n_states) for _ in range(n_particles)] print("\nGenerated Energy Levels (Normalized by kBT):") for ip, eps in enumerate(eps_list): print(f" Particle {ip}: {['{:.4f}'.format(e) for e in eps]}") # --------------------------------------------------------- # 手法1: すべての状態の組み合わせを網羅 (Total Combination) # --------------------------------------------------------- print("\n[Method 1] Calculating Z_tot using all combinations of states...") # 状態インデックスの組み合わせを生成 state_indices = [range(n_states)] * n_particles all_combinations = list(itertools.product(*state_indices)) z_total_comb = 0.0 for ic, combo in enumerate(all_combinations): # 系の全エネルギーを計算 e_total = sum(eps_list[ip][idx] for ip, idx in enumerate(combo)) # ボルツマン因子の加算 z_contribution = exp(-e_total) z_total_comb += z_contribution # 組み合わせが少ない場合のみ詳細を表示 if len(all_combinations) <= 27: print(f" Combo {ic:2d} {combo}: Etot={e_total:8.5f}, Z_contribution={z_contribution:8.5f}") print(f"==> Z_total (Method 1) = {z_total_comb:.10f}") # --------------------------------------------------------- # 手法2: 各粒子の分配関数の積 (Product of Zp) # --------------------------------------------------------- print("\n[Method 2] Calculating Z_tot as a product of individual Zp...") z_total_prod = 1.0 for ip in range(n_particles): # 個々の粒子の分配関数 Zp を計算 zp = sum(exp(-e) for e in eps_list[ip]) print(f" Particle {ip} Zp = {zp:.10f}") z_total_prod *= zp print(f"==> Z_total (Method 2) = {z_total_prod:.10f}") # ------------------------ # 結果の比較 # ------------------------ diff = abs(z_total_comb - z_total_prod) print(f"\nDifference: {diff:.2e}") if diff < 1e-12: print("Verification Successful: Z_total = Π Zp") else: print("Verification Failed: Check the implementation.")
if __name__ == "__main__": main()