高校物理の最後に出てくる「原子核」。陽子・中性子・核分裂・連鎖反応 ── 言葉は知っていても、何が「連鎖」なのか、なぜ「」という量があるのか、教科書を読むだけだと分かりにくい。実際にコンピュータの中で中性子を飛ばして、原子核にぶつけて、連鎖反応を起こすと、これらが一気に繋がります。
① 中性子1個 → 核分裂 → 新しい中性子が複数飛び出す、というルールを実装する。② 「k因子(中性子が次世代で何倍になるか)」がなぜ重要か。③ U-235 / U-238 / Pu-239 / U-233 / Th-232 を比べて、なぜ天然ウランでは爆発しないのか。④ 臨界質量・制御棒の本当の役割。
本記事は教育目的の物理シミュレーションです。実際の核兵器設計には、爆縮レンズ・タンパー・正確な幾何形状・密度設計など、ここでは触れない要素が決定的に重要で、本記事のシミュレーションでは到達しません。あくまで「教科書の連鎖反応がコードで立ち上がる」体験のために書いています。
Step 0: 教科書のおさらい — 中性子と核分裂
核分裂は、ウランやプルトニウムの原子核に中性子が当たると、原子核が真っ二つに割れて、新しい中性子を平均 ν 個放出する現象。この新しい中性子が他の原子核にぶつかれば、また分裂が起こる。ぶつからずに飛び去ったり、別の物質に吸収されればそこで終わる。
重要な数字: - 核分裂断面積 σ(barn 単位、1 barn = 10⁻²⁴ cm²)= ぶつかりやすさ - 平均放出中性子数 ν(1回の分裂で生まれる中性子数) - k因子 = (新しく生まれる中性子) / (元の中性子) ─ k>1 なら指数増加(爆発的)、k=1 なら定常(原子炉)、k<1 なら減衰
U-235: σ_f = 583 barn, ν = 2.42 / Pu-239: σ_f = 750 barn, ν = 2.87 / U-233: σ_f = 530 barn, ν = 2.49 / U-238: σ_f ≈ 0.00002 barn(ほぼ反応しない)/ Th-232: σ_f ≈ 0(直接は分裂しない、増殖して U-233 に変わる)
Step 1: 中性子のランダムウォーク
中性子は質量を持つ粒子、媒質中を直進し、原子核にぶつかると散乱される。まずは2D の箱の中で、1個の中性子をランダムに動かしてみます。
import numpy as npimport matplotlib.pyplot as plt
np.random.seed(2)L = 10.0steps = 200
pos = np.array([5.0, 5.0]) # 中央スタートangle = np.random.uniform(0, 2*np.pi)v = np.array([np.cos(angle), np.sin(angle)])trajectory = [pos.copy()]
for _ in range(steps): pos = pos + v * 0.1 # 壁で反射(簡略化) if pos[0] < 0 or pos[0] > L: v[0] *= -1 if pos[1] < 0 or pos[1] > L: v[1] *= -1 # ときどきランダム散乱 if np.random.random() < 0.05: angle = np.random.uniform(0, 2*np.pi) v = np.array([np.cos(angle), np.sin(angle)]) trajectory.append(pos.copy())
trajectory = np.array(trajectory)plt.figure(figsize=(6, 6))plt.plot(trajectory[:, 0], trajectory[:, 1], lw=0.8, color="goldenrod")plt.scatter(*trajectory[0], c="green", s=100, label="start", zorder=5)plt.scatter(*trajectory[-1], c="red", s=100, label="end", zorder=5)plt.xlim(0, L); plt.ylim(0, L)plt.title("Step 1: A single neutron's path")plt.legend(); plt.grid(alpha=0.3)plt.show()
Step 2: 原子核を置いて衝突 → 核分裂
次に、箱の中にウラン原子核(U-235)を散りばめます。中性子が原子核の近くを通ると確率的に 核分裂 が起こり、その原子核は消えて、平均 ν=2.42 個の新しい中性子が飛び出します。
import numpy as np
# 原子核(fissile nuclei)N_NUCLEI = 300L = 10.0nuclei = np.random.rand(N_NUCLEI, 2) * L
# 元素パラメータ(U-235)P_FISSION = 0.95 # 衝突距離内に来たときの分裂確率(規格化)NU = 2.42 # 1分裂で出る中性子の平均数R_HIT = 0.25 # 「衝突」と判定する距離
# 中性子の状態(pos, vel)def make_neutron(pos): angle = np.random.uniform(0, 2*np.pi) return [pos.copy(), np.array([np.cos(angle), np.sin(angle)])]
neutrons = [make_neutron(np.array([5.0, 5.0]))]
def step_world(neutrons, nuclei): new_neutrons = [] survived_nuclei_mask = np.ones(len(nuclei), dtype=bool) for pos, vel in neutrons: pos += vel * 0.1 # 箱を出たら消える(漏洩) if not (0 <= pos[0] <= L and 0 <= pos[1] <= L): continue # 原子核との衝突判定 if len(nuclei) > 0: d2 = np.sum((nuclei - pos)**2, axis=1) hit = np.argmin(d2) if d2[hit] < R_HIT**2 and survived_nuclei_mask[hit]: if np.random.random() < P_FISSION: # 核分裂発生 ─ 中性子を ν 個生成(ポアソン) n_out = np.random.poisson(NU) survived_nuclei_mask[hit] = False for _ in range(n_out): new_neutrons.append(make_neutron(pos)) continue # この中性子は消費された new_neutrons.append([pos, vel]) return new_neutrons, nuclei[survived_nuclei_mask]
# 200 ステップ走らせるcounts = []for t in range(200): neutrons, nuclei = step_world(neutrons, nuclei) counts.append(len(neutrons)) if len(neutrons) == 0: break現実の核分裂では1回ごとに 0〜6 個程度の中性子が確率的に放出されます。平均が ν の ポアソン分布 で近似するのが一般的。このランダム性が「臨界点」付近で本質的に効きます。
Step 3: 連鎖反応のスナップショット
シミュレーションを動かして途中経過を可視化。生き残った原子核(灰色)と中性子(黄色)を時系列で並べます。

Step 4: 元素別シミュレーション
同じ仕組みで、断面積 σ と ν を変えると、各元素で連鎖反応がどれくらい起こるかを比較できます。「なぜ天然ウラン(99.3% は U-238)では爆発しないか」が一目で分かる場面です。
# 規格化したシミュレーション用パラメータELEMENTS = { "U-235": {"P": 0.78, "nu": 2.42, "color": "tab:blue"}, "Pu-239": {"P": 1.00, "nu": 2.87, "color": "tab:red"}, "U-233": {"P": 0.71, "nu": 2.49, "color": "tab:green"}, "U-238": {"P": 0.00003, "nu": 2.5, "color": "tab:gray"}, "Th-232": {"P": 0.0, "nu": 0.0, "color": "tab:olive"},}
def run(element, T_steps=200): p = ELEMENTS[element] nuclei = np.random.rand(N_NUCLEI, 2) * L neutrons = [make_neutron(np.array([5.0, 5.0]))] counts = [] for _ in range(T_steps): neutrons, nuclei = step_world_with(neutrons, nuclei, p["P"], p["nu"]) counts.append(len(neutrons)) return counts
plt.figure(figsize=(10, 5))for el, p in ELEMENTS.items(): plt.semilogy(run(el), label=f"{el} (P={p['P']}, ν={p['nu']})", color=p["color"], linewidth=2)plt.xlabel("Time steps"); plt.ylabel("Neutron count (log)")plt.title("Step 4: Chain reaction by element")plt.legend(loc="upper right"); plt.grid(alpha=0.3, which="both")plt.show()
実際の連鎖反応を動画で見る
数値だけだと「指数増加」が伝わりにくいので、シミュレーションを動画にしました。同じ条件・同じ箱で、4元素を比較。中性子(黄〜赤の点)が増えていく様子と、原子核(灰)が消えていく様子を見比べてください。Pu-239 / U-235 はあっという間に中性子だらけになり、U-238 / Th-232 はそもそも反応が起こらず1個目の中性子が箱から漏れて終了します。




上のアニメを並べて見ると、なぜ天然ウラン(U-238 が 99.3%)で核兵器が作れないかが直感できます。1000個の原子核のうち 993個が「邪魔者」として中性子を漏らしてしまうので、連鎖反応が続きません。ウラン濃縮= U-235 の比率を 0.7% から 90%+ に高める作業 = 上の Pu-239 / U-235 のアニメに状況を近づける作業、です。
天然ウランは 99.3% が U-238、わずか 0.7% が U-235。U-238 は熱中性子にほぼ反応しないので、99.3% の原子核がただの「邪魔者」になり連鎖反応が続かない。ウラン濃縮が政治的問題になる本質は、この U-235 の割合を高める作業の難しさにあります。
Step 5: 臨界 ─ k因子の物理的意味
k = 次世代の中性子数 / 現世代の中性子数。k > 1 なら指数的に増える(爆発的)、k = 1 なら定常運転(原子炉)、k < 1 なら減衰。同じ U-235 でも、原子核の密度や箱のサイズ(漏洩率)を変えると k が変わります。
# 原子核密度を変えて 3 パターンdensities = {"sub-critical (k<1)": 100, "critical (k≈1)": 250, "super-critical (k>1)": 500}
plt.figure(figsize=(10, 5))for label, n in densities.items(): nuclei = np.random.rand(n, 2) * L neutrons = [make_neutron(np.array([5.0, 5.0]))] counts = [] for _ in range(200): neutrons, nuclei = step_world(neutrons, nuclei) counts.append(len(neutrons)) if len(neutrons) > 5000: break plt.semilogy(counts, label=label, linewidth=2)plt.xlabel("Time steps"); plt.ylabel("Neutron count (log)")plt.title("Step 5: Three regimes ─ subcritical, critical, supercritical")plt.legend(); plt.grid(alpha=0.3, which="both")plt.show()
原子炉は k=1 で運転する装置(一定の中性子数を維持)/ 原爆は k>1 を瞬間的に作って指数増加させる装置。物理は同じ。形状・密度・反射材で k を制御するか暴走させるか、その違いだけです。
Step 6: 制御棒で k を 1 に戻す
原子炉の制御棒は、中性子をたくさん吸収する材質(カドミウム、ボロンなど)でできています。シミュレーションでも「中性子が制御棒の領域に入ったら消滅」というルールを足すと、暴走していた連鎖反応を k=1 に持ち込めます。
# 制御棒:箱の x=4〜5 の領域に入ったら中性子は吸収def step_with_control_rod(neutrons, nuclei): new_neutrons = [] survived = np.ones(len(nuclei), dtype=bool) for pos, vel in neutrons: pos += vel * 0.1 if not (0 <= pos[0] <= L and 0 <= pos[1] <= L): continue if 4 < pos[0] < 5: # ← 制御棒で吸収 continue # ... 通常の核分裂判定 ... new_neutrons.append([pos, vel]) return new_neutrons, nuclei[survived]
自由研究の提案
① 減速材の効果: 中性子は速いままだと U-235 とも反応しにくい。水・黒鉛などの減速材で「熱中性子」にすることで反応性が大きく上がる。シミュレーションでも「衝突ごとに速度を 0.7 倍に減速」させると変化が見える。 ② トリウム炉: Th-232 は直接分裂しないが、中性子を吸収して U-233(強い核燃料)に変わる。「Th + n → U-233」のルールを足して、トリウム燃料サイクルを再現してみる。 ③ 反射材: 箱の壁を「反射壁」にすると、漏洩する中性子が戻ってきて k が上がる。タンパーと呼ばれる現実の反射材の役割を確認できる。 ④ 遅発中性子: 実際の核分裂では、ν=2.42 のうち 0.65% が「遅発中性子」(数秒〜数分遅れて出る)。これが原子炉の制御を可能にしている本質。シミュレーションで「ν のうち 1% を遅延 100 ステップで放出」ルールを入れると、なぜ原子炉が制御できるかが分かる。
次回予告
EP.14 はソートアルゴリズム。コンピュータサイエンスの基礎、バブルソートからクイックソート、そして 2022 年に Java で標準採用された Powersort まで。「同じ問題を 100 万倍速く解く」アルゴリズムの発明史を、自分のパソコンで動かしながら追います。
この記事の感想を教えてください
あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。