Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/nuclear-physics/reactor_kinetics.tex
75 views
unlisted
1
\documentclass[a4paper, 11pt]{article}
2
\usepackage[utf8]{inputenc}
3
\usepackage[T1]{fontenc}
4
\usepackage{amsmath, amssymb, amsthm}
5
\usepackage{graphicx}
6
\usepackage{booktabs}
7
\usepackage{siunitx}
8
\usepackage{subcaption}
9
\usepackage[makestderr]{pythontex}
10
11
\newtheorem{definition}{Definition}
12
\newtheorem{theorem}{Theorem}
13
\newtheorem{example}{Example}
14
\newtheorem{remark}{Remark}
15
16
\title{Nuclear Reactor Kinetics: Point Kinetics Model and Delayed Neutron Analysis}
17
\author{Nuclear Engineering Computation Laboratory}
18
\date{\today}
19
20
\begin{document}
21
\maketitle
22
23
\begin{abstract}
24
This technical report presents comprehensive computational analysis of nuclear reactor kinetics using the point kinetics equations with delayed neutrons. We implement solutions for reactivity transients, analyze the role of delayed neutron precursors in reactor control, and compute reactor periods for various reactivity insertions. The analysis covers prompt criticality, xenon dynamics, and feedback mechanisms essential for safe reactor operation.
25
\end{abstract}
26
27
\section{Theoretical Framework}
28
29
\begin{definition}[Reactivity]
30
Reactivity $\rho$ measures the deviation from criticality:
31
\begin{equation}
32
\rho = \frac{k_{eff} - 1}{k_{eff}}
33
\end{equation}
34
where $k_{eff}$ is the effective multiplication factor.
35
\end{definition}
36
37
\begin{theorem}[Point Kinetics Equations]
38
For six delayed neutron groups, the reactor power evolves according to:
39
\begin{align}
40
\frac{dn}{dt} &= \frac{\rho - \beta}{\Lambda} n + \sum_{i=1}^{6} \lambda_i C_i + S \\
41
\frac{dC_i}{dt} &= \frac{\beta_i}{\Lambda} n - \lambda_i C_i
42
\end{align}
43
where $n$ is neutron density, $C_i$ are precursor concentrations, $\beta = \sum \beta_i$ is total delayed neutron fraction, $\Lambda$ is mean generation time, and $S$ is external source.
44
\end{theorem}
45
46
\subsection{Reactor Period}
47
48
\begin{definition}[Stable Period]
49
The asymptotic reactor period $T$ satisfies the inhour equation:
50
\begin{equation}
51
\rho = \frac{\Lambda}{T} + \sum_{i=1}^{6} \frac{\beta_i}{1 + \lambda_i T}
52
\end{equation}
53
\end{definition}
54
55
\begin{example}[Reactivity Units]
56
Reactivity is measured in:
57
\begin{itemize}
58
\item \textbf{Dollar} (\$): $\rho/\beta$ (1\$ = one delayed neutron fraction)
59
\item \textbf{Cent}: 0.01\$ = 0.01$\beta$
60
\item \textbf{pcm}: $10^{-5}$ (parts per 100,000)
61
\end{itemize}
62
For U-235: $\beta \approx 0.0065$, so 1\$ $\approx$ 650 pcm.
63
\end{example}
64
65
\section{Computational Analysis}
66
67
\begin{pycode}
68
import numpy as np
69
from scipy.integrate import odeint, solve_ivp
70
from scipy.optimize import fsolve
71
import matplotlib.pyplot as plt
72
plt.rc('text', usetex=True)
73
plt.rc('font', family='serif', size=10)
74
75
# Reactor parameters (U-235 thermal)
76
Lambda = 1e-4 # Mean generation time (s)
77
beta_total = 0.0065 # Total delayed neutron fraction
78
79
# Six-group delayed neutron data for U-235
80
beta_i = np.array([0.000215, 0.001424, 0.001274, 0.002568, 0.000748, 0.000273])
81
lambda_i = np.array([0.0124, 0.0305, 0.111, 0.301, 1.14, 3.01]) # decay constants (1/s)
82
half_lives_i = np.log(2) / lambda_i # seconds
83
84
# Effective one-group parameters
85
beta_eff = np.sum(beta_i)
86
lambda_eff = np.sum(beta_i * lambda_i) / beta_eff
87
88
# Point kinetics equations (6 groups)
89
def point_kinetics_6group(y, t, rho_func):
90
"""Six-group point kinetics equations."""
91
n = y[0]
92
C = y[1:7]
93
94
rho = rho_func(t)
95
96
dn_dt = (rho - beta_eff) / Lambda * n + np.sum(lambda_i * C)
97
dC_dt = beta_i / Lambda * n - lambda_i * C
98
99
return np.concatenate([[dn_dt], dC_dt])
100
101
# Simplified one-group kinetics
102
def point_kinetics_1group(y, t, rho_func):
103
"""One-group point kinetics equations."""
104
n, C = y
105
rho = rho_func(t)
106
dn_dt = (rho - beta_eff) / Lambda * n + lambda_eff * C
107
dC_dt = beta_eff / Lambda * n - lambda_eff * C
108
return [dn_dt, dC_dt]
109
110
# Inhour equation
111
def inhour_equation(T, rho):
112
"""Inhour equation for reactor period."""
113
if abs(T) < 1e-10:
114
return np.inf
115
return Lambda / T + np.sum(beta_i / (1 + lambda_i * T)) - rho
116
117
def find_period(rho):
118
"""Find stable period for given reactivity."""
119
if rho <= 0:
120
return np.inf
121
elif rho >= beta_eff:
122
return Lambda / (rho - beta_eff) # Prompt critical
123
else:
124
# Newton-Raphson to solve inhour equation
125
T_guess = 1.0 / (lambda_eff * rho / (beta_eff - rho))
126
T_sol = fsolve(inhour_equation, T_guess, args=(rho,))[0]
127
return T_sol
128
129
# Initial conditions (equilibrium at n=1)
130
n0 = 1.0
131
C0_i = beta_i / Lambda * n0 / lambda_i
132
y0_6group = np.concatenate([[n0], C0_i])
133
y0_1group = [n0, beta_eff / Lambda * n0 / lambda_eff]
134
135
# Time arrays
136
t_short = np.linspace(0, 10, 1000) # seconds
137
t_long = np.linspace(0, 100, 1000)
138
139
# Reactivity insertions
140
rho_values = [0.001, 0.003, 0.005] # Below prompt critical
141
rho_prompt = 0.007 # Above prompt critical
142
143
# Solve for different reactivities
144
solutions = []
145
for rho_val in rho_values:
146
rho_func = lambda t, r=rho_val: r if t > 0 else 0
147
sol = odeint(point_kinetics_6group, y0_6group, t_short, args=(rho_func,))
148
solutions.append(sol[:, 0])
149
150
# Prompt supercritical case
151
t_prompt = np.linspace(0, 0.01, 500) # milliseconds
152
rho_func_prompt = lambda t: rho_prompt if t > 0 else 0
153
sol_prompt = odeint(point_kinetics_6group, y0_6group, t_prompt, args=(rho_func_prompt,))
154
155
# Negative reactivity (shutdown)
156
rho_neg = -0.005
157
rho_func_neg = lambda t: rho_neg if t > 0 else 0
158
sol_neg = odeint(point_kinetics_6group, y0_6group, t_long, args=(rho_func_neg,))
159
160
# Ramp reactivity insertion
161
ramp_rate = 0.0001 # per second
162
rho_func_ramp = lambda t: min(ramp_rate * t, 0.005) if t > 0 else 0
163
sol_ramp = odeint(point_kinetics_6group, y0_6group, t_long, args=(rho_func_ramp,))
164
165
# Reactor period vs reactivity
166
rho_range = np.linspace(0.0001, 0.006, 100)
167
periods = np.array([find_period(r) for r in rho_range])
168
169
# Temperature feedback
170
alpha_T = -3e-5 # Temperature coefficient (per K)
171
def feedback_rho(t, n, rho_ext, T0=300, C_heat=1e6):
172
"""Reactivity with temperature feedback."""
173
# Simple heat-up model
174
T = T0 + n * t / C_heat
175
return rho_ext + alpha_T * (T - T0)
176
177
# Xenon dynamics (simplified)
178
sigma_Xe = 2.65e-18 # Xe-135 absorption cross section (cm^2)
179
Sigma_f = 0.1 # Macroscopic fission cross section (1/cm)
180
gamma_Xe = 0.003 # Direct yield
181
gamma_I = 0.061 # Iodine yield (-> Xe-135)
182
lambda_Xe = 2.09e-5 # Xe-135 decay constant (1/s)
183
lambda_I = 2.87e-5 # I-135 decay constant (1/s)
184
185
# Equilibrium xenon concentration
186
def xenon_equilibrium(phi):
187
"""Equilibrium Xe-135 concentration."""
188
return (gamma_I + gamma_Xe) * Sigma_f * phi / (lambda_Xe + sigma_Xe * phi)
189
190
# Xenon after shutdown
191
def xenon_shutdown(t, phi0):
192
"""Xe-135 concentration after shutdown."""
193
Xe0 = xenon_equilibrium(phi0)
194
I0 = gamma_I * Sigma_f * phi0 / lambda_I
195
196
Xe = (Xe0 * np.exp(-lambda_Xe * t) +
197
I0 * lambda_I / (lambda_Xe - lambda_I) *
198
(np.exp(-lambda_I * t) - np.exp(-lambda_Xe * t)))
199
return Xe
200
201
phi0 = 1e14 # Initial flux (n/cm^2/s)
202
t_xenon = np.linspace(0, 100 * 3600, 500) # 100 hours
203
Xe_shutdown = xenon_shutdown(t_xenon, phi0)
204
205
# Create visualization
206
fig = plt.figure(figsize=(12, 10))
207
gs = fig.add_gridspec(3, 3, hspace=0.35, wspace=0.35)
208
209
# Plot 1: Step reactivity response
210
ax1 = fig.add_subplot(gs[0, 0])
211
colors = ['blue', 'green', 'red']
212
for sol, rho, color in zip(solutions, rho_values, colors):
213
rho_dollars = rho / beta_eff
214
ax1.plot(t_short, sol, color=color, lw=1.5,
215
label=f'{rho*1000:.0f} pcm ({rho_dollars:.2f}\\$)')
216
ax1.set_xlabel('Time (s)')
217
ax1.set_ylabel('Relative Power')
218
ax1.set_title('Step Reactivity Insertion')
219
ax1.legend(fontsize=7)
220
ax1.set_yscale('log')
221
ax1.grid(True, alpha=0.3, which='both')
222
223
# Plot 2: Prompt supercritical
224
ax2 = fig.add_subplot(gs[0, 1])
225
ax2.plot(t_prompt * 1000, sol_prompt[:, 0], 'r-', lw=2)
226
ax2.set_xlabel('Time (ms)')
227
ax2.set_ylabel('Relative Power')
228
ax2.set_title(f'Prompt Critical ({rho_prompt*1000:.0f} pcm)')
229
ax2.set_yscale('log')
230
ax2.grid(True, alpha=0.3, which='both')
231
232
# Plot 3: Reactor period
233
ax3 = fig.add_subplot(gs[0, 2])
234
ax3.semilogy(rho_range / beta_eff, periods, 'b-', lw=2)
235
ax3.axhline(y=1, color='gray', ls='--', alpha=0.5)
236
ax3.axvline(x=1, color='r', ls='--', alpha=0.5, label='Prompt critical')
237
ax3.set_xlabel('Reactivity (\\$)')
238
ax3.set_ylabel('Stable Period (s)')
239
ax3.set_title('Reactor Period')
240
ax3.legend(fontsize=8)
241
ax3.grid(True, alpha=0.3, which='both')
242
ax3.set_xlim([0, 1.1])
243
ax3.set_ylim([0.1, 1000])
244
245
# Plot 4: Shutdown transient
246
ax4 = fig.add_subplot(gs[1, 0])
247
ax4.plot(t_long, sol_neg[:, 0], 'b-', lw=2)
248
ax4.set_xlabel('Time (s)')
249
ax4.set_ylabel('Relative Power')
250
ax4.set_title(f'Shutdown ({rho_neg*1000:.0f} pcm)')
251
ax4.grid(True, alpha=0.3)
252
253
# Plot 5: Delayed neutron groups
254
ax5 = fig.add_subplot(gs[1, 1])
255
x_pos = range(len(beta_i))
256
ax5.bar(x_pos, beta_i * 100, color='blue', alpha=0.7)
257
ax5.set_xlabel('Precursor Group')
258
ax5.set_ylabel('$\\beta_i$ (\\%)')
259
ax5.set_title('Delayed Neutron Fractions')
260
ax5.set_xticks(x_pos)
261
ax5.set_xticklabels([1, 2, 3, 4, 5, 6])
262
ax5.grid(True, alpha=0.3, axis='y')
263
264
# Plot 6: Precursor half-lives
265
ax6 = fig.add_subplot(gs[1, 2])
266
ax6.bar(x_pos, half_lives_i, color='green', alpha=0.7)
267
ax6.set_xlabel('Precursor Group')
268
ax6.set_ylabel('Half-life (s)')
269
ax6.set_title('Precursor Decay Half-lives')
270
ax6.set_xticks(x_pos)
271
ax6.set_xticklabels([1, 2, 3, 4, 5, 6])
272
ax6.grid(True, alpha=0.3, axis='y')
273
274
# Plot 7: Ramp insertion
275
ax7 = fig.add_subplot(gs[2, 0])
276
ax7.plot(t_long, sol_ramp[:, 0], 'purple', lw=2)
277
ax7.set_xlabel('Time (s)')
278
ax7.set_ylabel('Relative Power')
279
ax7.set_title(f'Ramp Insertion ({ramp_rate*1e6:.0f} pcm/s)')
280
ax7.grid(True, alpha=0.3)
281
282
# Plot 8: Xenon poisoning after shutdown
283
ax8 = fig.add_subplot(gs[2, 1])
284
Xe_norm = Xe_shutdown / xenon_equilibrium(phi0)
285
ax8.plot(t_xenon / 3600, Xe_norm, 'r-', lw=2)
286
ax8.axhline(y=1, color='gray', ls='--', alpha=0.5)
287
ax8.set_xlabel('Time after shutdown (hours)')
288
ax8.set_ylabel('Xe-135 / Equilibrium')
289
ax8.set_title('Xenon Transient')
290
ax8.grid(True, alpha=0.3)
291
292
# Plot 9: Inhour equation components
293
ax9 = fig.add_subplot(gs[2, 2])
294
T_range = np.logspace(-1, 3, 200)
295
296
prompt_term = Lambda / T_range
297
delayed_term = np.sum([beta_i[i] / (1 + lambda_i[i] * T_range[:, np.newaxis])
298
for i in range(6)], axis=0).flatten()
299
total = prompt_term + delayed_term
300
301
ax9.loglog(T_range, prompt_term * 1000, 'b--', lw=1.5, label='Prompt')
302
ax9.loglog(T_range, delayed_term * 1000, 'r--', lw=1.5, label='Delayed')
303
ax9.loglog(T_range, total * 1000, 'k-', lw=2, label='Total')
304
ax9.set_xlabel('Period (s)')
305
ax9.set_ylabel('Reactivity (pcm)')
306
ax9.set_title('Inhour Equation')
307
ax9.legend(fontsize=7)
308
ax9.grid(True, alpha=0.3, which='both')
309
310
plt.savefig('reactor_kinetics_plot.pdf', bbox_inches='tight', dpi=150)
311
print(r'\begin{center}')
312
print(r'\includegraphics[width=\textwidth]{reactor_kinetics_plot.pdf}')
313
print(r'\end{center}')
314
plt.close()
315
316
# Calculate key values
317
period_50cent = find_period(0.5 * beta_eff)
318
prompt_period = Lambda / (rho_prompt - beta_eff)
319
xe_max_time = t_xenon[np.argmax(Xe_shutdown)] / 3600
320
xe_max_ratio = np.max(Xe_norm)
321
\end{pycode}
322
323
\section{Results and Analysis}
324
325
\subsection{Point Kinetics Parameters}
326
327
\begin{pycode}
328
print(r'\begin{table}[htbp]')
329
print(r'\centering')
330
print(r'\caption{Reactor Kinetics Parameters (U-235 Thermal)}')
331
print(r'\begin{tabular}{lcc}')
332
print(r'\toprule')
333
print(r'Parameter & Value & Units \\')
334
print(r'\midrule')
335
print(f'Total $\\beta$ & {beta_eff*1000:.2f} & -- ($\\times 10^{{-3}}$) \\\\')
336
print(f'Mean generation time $\\Lambda$ & {Lambda*1000:.2f} & ms \\\\')
337
print(f'Effective decay constant & {lambda_eff:.3f} & s$^{{-1}}$ \\\\')
338
print(f'1 dollar & {beta_eff*1e5:.0f} & pcm \\\\')
339
print(r'\bottomrule')
340
print(r'\end{tabular}')
341
print(r'\end{table}')
342
\end{pycode}
343
344
\subsection{Delayed Neutron Groups}
345
346
\begin{pycode}
347
print(r'\begin{table}[htbp]')
348
print(r'\centering')
349
print(r'\caption{Six-Group Delayed Neutron Data for U-235}')
350
print(r'\begin{tabular}{ccccc}')
351
print(r'\toprule')
352
print(r'Group & $\beta_i$ & $\lambda_i$ (s$^{-1}$) & $t_{1/2}$ (s) & Precursors \\')
353
print(r'\midrule')
354
355
precursors = ['Br-87', 'I-137', 'Br-89', 'I-138', 'As-85', 'Br-92']
356
for i in range(6):
357
print(f'{i+1} & {beta_i[i]:.6f} & {lambda_i[i]:.4f} & {half_lives_i[i]:.2f} & {precursors[i]} \\\\')
358
359
print(r'\midrule')
360
print(f'Total & {beta_eff:.6f} & {lambda_eff:.4f} (eff) & -- & -- \\\\')
361
print(r'\bottomrule')
362
print(r'\end{tabular}')
363
print(r'\end{table}')
364
\end{pycode}
365
366
\subsection{Reactor Periods}
367
368
\begin{remark}
369
Delayed neutrons are essential for reactor control. Without them, the reactor period would be:
370
\begin{equation}
371
T_{prompt} = \frac{\Lambda}{\rho} \approx \frac{10^{-4} \text{ s}}{10^{-3}} = 0.1 \text{ s}
372
\end{equation}
373
With delayed neutrons, the effective generation time increases to $\sim$0.1 s, giving manageable periods.
374
\end{remark}
375
376
Key period values:
377
\begin{itemize}
378
\item Period at 50 cents: \py{f"{period_50cent:.1f}"} s
379
\item Period at prompt critical: \py{f"{prompt_period*1000:.3f}"} ms
380
\item Prompt period ($\rho > \beta$): determined only by $\Lambda$
381
\end{itemize}
382
383
\subsection{Xenon Poisoning}
384
385
After shutdown, Xe-135 builds up due to I-135 decay:
386
\begin{itemize}
387
\item Maximum xenon at $t = \py{f"{xe_max_time:.1f}"}$ hours after shutdown
388
\item Peak concentration: \py{f"{xe_max_ratio:.2f}"} times equilibrium
389
\item This ``xenon dead time'' prevents immediate restart
390
\end{itemize}
391
392
\section{Safety Analysis}
393
394
\begin{theorem}[Prompt Critical Limit]
395
Prompt criticality occurs when $\rho = \beta$. Above this threshold:
396
\begin{equation}
397
T = \frac{\Lambda}{\rho - \beta}
398
\end{equation}
399
For $\rho = 1.1\beta$, $T = 10\Lambda \approx 1$ ms---uncontrollable.
400
\end{theorem}
401
402
\begin{example}[Control Rod Worth]
403
A typical control rod worth is 1000--5000 pcm. Safe insertion requires:
404
\begin{itemize}
405
\item Maximum rate: $<$ 0.1\$/s for normal operation
406
\item Shutdown margin: $>$ 1\% $\Delta k/k$ with strongest rod stuck out
407
\end{itemize}
408
\end{example}
409
410
\begin{example}[Doppler Feedback]
411
The prompt negative temperature coefficient:
412
\begin{equation}
413
\alpha_T = \frac{d\rho}{dT} \approx -3 \times 10^{-5} \text{ K}^{-1}
414
\end{equation}
415
provides inherent stability against power excursions.
416
\end{example}
417
418
\section{Discussion}
419
420
The point kinetics model reveals critical features of reactor dynamics:
421
422
\begin{enumerate}
423
\item \textbf{Delayed neutrons}: Increase effective generation time by factor $\beta/(\beta - \rho)$.
424
\item \textbf{Prompt jump}: Immediate power rise followed by asymptotic period.
425
\item \textbf{Xenon dynamics}: Creates operational constraints after shutdown.
426
\item \textbf{Feedback mechanisms}: Doppler and moderator coefficients ensure stability.
427
\item \textbf{Safety margins}: Reactivity limits prevent prompt criticality.
428
\end{enumerate}
429
430
\section{Conclusions}
431
432
This computational analysis demonstrates:
433
\begin{itemize}
434
\item Total delayed neutron fraction: $\beta = \py{f"{beta_eff*1000:.2f}"} \times 10^{-3}$
435
\item Mean generation time: $\Lambda = \py{f"{Lambda*1000:.2f}"}$ ms
436
\item Stable period at 50\textcent: \py{f"{period_50cent:.1f}"} s
437
\item Xenon peak at \py{f"{xe_max_time:.1f}"} hours post-shutdown
438
\end{itemize}
439
440
Understanding reactor kinetics is essential for safe operation, transient analysis, and accident prevention in nuclear power plants.
441
442
\section{Further Reading}
443
\begin{itemize}
444
\item Duderstadt, J.J., Hamilton, L.J., \textit{Nuclear Reactor Analysis}, Wiley, 1976
445
\item Stacey, W.M., \textit{Nuclear Reactor Physics}, 3rd Ed., Wiley-VCH, 2018
446
\item Keepin, G.R., \textit{Physics of Nuclear Kinetics}, Addison-Wesley, 1965
447
\end{itemize}
448
449
\end{document}
450
451