16. ํ๋ก์ ํธ
16. ํ๋ก์ ํธ¶
ํ์ต ๋ชฉํ¶
- ๋ค์ํ ์ฅ ๊ธฐํํ์ ๊ฐ์ง ๋ณด๋ฆฌ์ค ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ์ฌ ์์ ํ 3D ์ ์ ๊ถค๋ ์ ๋ถ๊ธฐ ๊ตฌํ
- ์๊ฐํ ๋๊ตฌ๋ฅผ ๊ฐ์ถ ๋๊ฐ ๋ฐ ์จ๋ ํ๋ผ์ฆ๋ง์ ์ผ๋ฐ ๋ถ์ฐ ๊ด๊ณ ํด๊ฒฐ๊ธฐ ๊ฐ๋ฐ
- ๋ฐ๋ผ๊ทธ๋์ฃผ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ ์ด๋ ํ๋ผ์ฆ๋ง ํ์์ ์ฐ๊ตฌํ๋ 1D ๋ธ๋ผ์ํ-ํธ์์ก ํด๊ฒฐ๊ธฐ ์์ฑ
- ๋จ์ผ ์ ์ ๊ถค๋, ํ๋ ์ด๋ก , ์ด๋ ์ด๋ก ์ ์ง์ ์ข ํฉ
- ์์น ๊ฒฐ๊ณผ๋ฅผ ํด์์ ์์ธก๊ณผ ๋์กฐ ๊ฒ์ฆํ๊ณ ์ ํ ์ด๋ก ์ ๋์ด์ ๋น์ ํ ๋ฌผ๋ฆฌ ํ๊ตฌ
- ์ฐ๊ตฌ์ ์ฌ์ฉ๋๋ ๊ณ์ฐ ํ๋ผ์ฆ๋ง ๋ฌผ๋ฆฌ ๋ฐฉ๋ฒ์ ๋ํ ์ค๋ฌด ๊ฒฝํ ํ๋
ํ๋ก์ ํธ 1: ์ ์ ๊ถค๋ ์๋ฎฌ๋ ์ดํฐ¶
1.1 ๊ฐ์¶
๋ชฉํ: ๋ค์ํ ์ ์๊ธฐ์ฅ ๊ตฌ์ฑ์ ์ฒ๋ฆฌํ๊ณ ์ ์ ๊ถค์ , ํ๋ฅ, ๋ถ๋ณ๋์ ์๊ฐํํ ์ ์๋ ๋ค๋ชฉ์ 3D ์ ์ ๊ถค๋ ์ ๋ถ๊ธฐ๋ฅผ ๊ตฌ์ถํฉ๋๋ค.
๋์ด๋: โญโญโญ
์์ ์๊ฐ: 10โ15์๊ฐ
๊ฐ๋ฐ ๊ธฐ์ : - ์ด๋ ๋ฐฉ์ ์์ ์์น ์ ๋ถ - ๋ณด๋ฆฌ์ค ์๊ณ ๋ฆฌ์ฆ(E&M ์ฅ์์ ์ ์๋ฅผ ์ํ ๋์ฝ ๋ฐฉ๋ฒ) - 3D ์๊ฐํ - ํด์์ ํ๋ฅ ์๋์ ๋์กฐ ๊ฒ์ฆ - ์ ์ ๊ตฌ์ ๋ฐ ์์ค ๋ฉ์ปค๋์ฆ ์ดํด
1.2 ๋ฌผ๋ฆฌ ๋ฐฐ๊ฒฝ¶
์ ํ๋ฅผ ๋ค ์ ์์ ์๋๋ก ์ ์ด๋ ๋ฐฉ์ ์์:
$$\frac{d\mathbf{p}}{dt} = q(\mathbf{E} + \mathbf{v} \times \mathbf{B})$$
์ฌ๊ธฐ์ $\mathbf{p} = \gamma m \mathbf{v}$๋ ์ด๋๋์ด๊ณ $\gamma = 1/\sqrt{1 - v^2/c^2}$๋ ๋ก๋ ์ธ ์ธ์์ ๋๋ค.
๋น์๋๋ก ์ ์ ์($v \ll c$)์ ๊ฒฝ์ฐ:
$$m \frac{d\mathbf{v}}{dt} = q(\mathbf{E} + \mathbf{v} \times \mathbf{B})$$
๋ณด๋ฆฌ์ค ์๊ณ ๋ฆฌ์ฆ์ ์ ์ ์ฅ์์ ์๋์ง๋ฅผ ๋ณด์กดํ๋ 2์ฐจ ์ ํํ ์๊ฐ ๊ฐ์ญ์ ์คํด์ ๋๋ค. ์ด๊ฒ์ ์ ์-์ (PIC) ์ฝ๋์ ์ฃผ๋ ฅ ๋ฐฉ๋ฒ์ ๋๋ค.
๋ณด๋ฆฌ์ค ์๊ณ ๋ฆฌ์ฆ (ํ ์๊ฐ ๋จ๊ณ $\Delta t$):
-
์ ๊ธฐ์ฅ์ ์ํ ์ ๋ฐ ๊ฐ์: $$\mathbf{v}^{-} = \mathbf{v}^n + \frac{q \Delta t}{2m} \mathbf{E}$$
-
์๊ธฐ์ฅ์ ์ํ ํ์ : $$\mathbf{v}^{+} = \mathbf{v}^{-} + \mathbf{v}^{-} \times \mathbf{t} + (\mathbf{v}^{-} \times \mathbf{t}) \times \mathbf{s}$$ ์ฌ๊ธฐ์: $$\mathbf{t} = \frac{q \Delta t}{2m} \mathbf{B}, \quad \mathbf{s} = \frac{2\mathbf{t}}{1 + t^2}$$
-
์ ๊ธฐ์ฅ์ ์ํ ์ ๋ฐ ๊ฐ์: $$\mathbf{v}^{n+1} = \mathbf{v}^{+} + \frac{q \Delta t}{2m} \mathbf{E}$$
-
์์น ์ ๋ฐ์ดํธ: $$\mathbf{x}^{n+1} = \mathbf{x}^n + \mathbf{v}^{n+1} \Delta t$$
1.3 ๊ตฌํ ๊ฐ์ด๋¶
๋จ๊ณ 1: ๊ธฐ๋ณธ ์ธํ๋ผ
์์ฑ์ ๊ฐ์ง Particle ํด๋์ค ์์ฑ:
- q, m: ์ ํ์ ์ง๋
- r: ์์น ๋ฒกํฐ [x, y, z]
- v: ์๋ ๋ฒกํฐ [vx, vy, vz]
- history: ๊ถค์ ์ ์ ์ฅํ๋ ๋ฆฌ์คํธ
๋จ๊ณ 2: ์ฅ ๊ตฌ์ฑ
๋ค์ํ ๊ธฐํํ์ ๋ํด $\mathbf{E}(\mathbf{r}, t)$์ $\mathbf{B}(\mathbf{r}, t)$๋ฅผ ๋ฐํํ๋ ํจ์ ๊ตฌํ:
- ๊ท ์ผํ B: $\mathbf{B} = B_0 \hat{\mathbf{z}}$ (์ ํ)
- ๊ท ์ผํ E + B: $\mathbf{E} = E_0 \hat{\mathbf{x}}$, $\mathbf{B} = B_0 \hat{\mathbf{z}}$ (EรB ํ๋ฅ)
- ๊ฒฝ์ฌ B: $\mathbf{B} = B_0 (1 + \alpha x) \hat{\mathbf{z}}$ (grad-B ํ๋ฅ)
- ๊ณก์ B: $\mathbf{B} = \frac{B_0 R_0}{R_0 + x} \hat{\mathbf{z}}$ (๊ณก๋ฅ ํ๋ฅ, ๋จ์ํ)
- ์๊ธฐ ๊ฑฐ์ธ: $\mathbf{B} = B_0 (1 + (z/L)^2) \hat{\mathbf{z}}$ (๊ฑฐ์ธ ํ)
- ํ ์นด๋ง(๋จ์ํ): ํ ๋ก์ด๋ฌ + ํด๋ก์ด๋ฌ ์ฅ
๋จ๊ณ 3: ๋ณด๋ฆฌ์ค ์ ๋ถ๊ธฐ
๋ณด๋ฆฌ์ค ์๊ณ ๋ฆฌ์ฆ์ ํจ์๋ก ๊ตฌํ:
def boris_step(r, v, E, B, q, m, dt):
"""
One step of Boris algorithm.
Parameters:
r, v: position and velocity (3D arrays)
E, B: electric and magnetic fields at position r (3D arrays)
q, m: charge and mass
dt: time step
Returns:
r_new, v_new
"""
# Half electric acceleration
v_minus = v + (q * dt / (2 * m)) * E
# Magnetic rotation
t = (q * dt / (2 * m)) * B
s = 2 * t / (1 + np.dot(t, t))
v_prime = v_minus + np.cross(v_minus, t)
v_plus = v_minus + np.cross(v_prime, s)
# Half electric acceleration
v_new = v_plus + (q * dt / (2 * m)) * E
# Position update
r_new = r + v_new * dt
return r_new, v_new
๋จ๊ณ 4: ์ ๋ถ ๋ฃจํ
def integrate_orbit(particle, E_func, B_func, t_final, dt):
"""
Integrate particle orbit from t=0 to t=t_final.
Parameters:
particle: Particle object
E_func, B_func: functions returning E(r, t) and B(r, t)
t_final: final time
dt: time step
"""
t = 0
while t < t_final:
E = E_func(particle.r, t)
B = B_func(particle.r, t)
particle.r, particle.v = boris_step(particle.r, particle.v, E, B,
particle.q, particle.m, dt)
particle.history['t'].append(t)
particle.history['r'].append(particle.r.copy())
particle.history['v'].append(particle.v.copy())
t += dt
๋จ๊ณ 5: ์๊ฐํ
matplotlib๋ฅผ ์ฌ์ฉํ์ฌ 3D ๊ถค์ ํ๋กฏ:
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, projection='3d')
r_history = np.array(particle.history['r'])
ax.plot(r_history[:, 0], r_history[:, 1], r_history[:, 2], linewidth=1)
ax.set_xlabel('x (m)')
ax.set_ylabel('y (m)')
ax.set_zlabel('z (m)')
ax.set_title('Particle Trajectory')
plt.show()
๋จ๊ณ 6: ๋ถ์ ๋ฐ ๊ฒ์ฆ
๊ฐ ์ฅ ๊ตฌ์ฑ์ ๋ํด ๊ณ์ฐ:
- ์ ํ ๋ฐ์ง๋ฆ: $\rho = m v_\perp / (q B)$
- ํ๋ฅ ์๋: ์์น์ ํด์ ๋น๊ต:
- EรB ํ๋ฅ: $\mathbf{v}_E = \mathbf{E} \times \mathbf{B} / B^2$
- Grad-B ํ๋ฅ: $\mathbf{v}_{\nabla B} = \pm \frac{m v_\perp^2}{2 q B^3} \mathbf{B} \times \nabla B$
- ๊ณก๋ฅ ํ๋ฅ: $\mathbf{v}_\kappa = \frac{m v_\parallel^2}{q B^3} \mathbf{B} \times (\mathbf{B} \cdot \nabla)\mathbf{B}$
- ๋จ์ด ๋ถ๋ณ๋:
- ์๊ธฐ ๋ชจ๋ฉํธ: $\mu = m v_\perp^2 / (2B)$
- ์ข ๋ฐฉํฅ ์์ฉ: $J = \oint v_\parallel ds$ (๋ฐ์ด์ค ์ด๋์ ๊ฒฝ์ฐ)
- ์๋์ง ๋ณด์กด: ์ ์ ์ฅ์์ $E_{kin} = \frac{1}{2} m v^2$๊ฐ ๋ณด์กด๋๋์ง ํ์ธ
1.4 ์์ ํ ์ฝ๋¶
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# Physical constants
e = 1.6e-19
m_e = 9.11e-31
m_p = 1.67e-27
class Particle:
def __init__(self, q, m, r0, v0):
self.q = q
self.m = m
self.r = np.array(r0, dtype=float)
self.v = np.array(v0, dtype=float)
self.history = {'t': [], 'r': [], 'v': []}
def kinetic_energy(self):
return 0.5 * self.m * np.dot(self.v, self.v)
def magnetic_moment(self, B):
B_mag = np.linalg.norm(B)
v_perp = np.linalg.norm(self.v - np.dot(self.v, B) * B / B_mag**2 * B_mag)
return self.m * v_perp**2 / (2 * B_mag)
def boris_step(r, v, E, B, q, m, dt):
"""Boris algorithm: one time step."""
# Half electric push
v_minus = v + (q * dt / (2 * m)) * E
# Magnetic rotation
t_vec = (q * dt / (2 * m)) * B
t_mag_sq = np.dot(t_vec, t_vec)
s_vec = 2 * t_vec / (1 + t_mag_sq)
v_prime = v_minus + np.cross(v_minus, t_vec)
v_plus = v_minus + np.cross(v_prime, s_vec)
# Half electric push
v_new = v_plus + (q * dt / (2 * m)) * E
# Position update
r_new = r + v_new * dt
return r_new, v_new
def integrate_orbit(particle, E_func, B_func, t_final, dt):
"""Integrate particle orbit."""
t = 0
while t < t_final:
E = E_func(particle.r, t)
B = B_func(particle.r, t)
particle.r, particle.v = boris_step(particle.r, particle.v, E, B,
particle.q, particle.m, dt)
particle.history['t'].append(t)
particle.history['r'].append(particle.r.copy())
particle.history['v'].append(particle.v.copy())
t += dt
# Field configurations
def uniform_B(r, t, B0=0.1):
"""Uniform magnetic field in z direction."""
return np.array([0, 0, 0]), np.array([0, 0, B0])
def E_cross_B(r, t, E0=1000, B0=0.1):
"""Uniform E and B fields (EรB drift)."""
return np.array([E0, 0, 0]), np.array([0, 0, B0])
def gradient_B(r, t, B0=0.1, alpha=0.1):
"""Gradient in B field."""
x, y, z = r
B = B0 * (1 + alpha * x)
return np.array([0, 0, 0]), np.array([0, 0, B])
def magnetic_mirror(r, t, B0=0.1, L=1.0):
"""Magnetic mirror field."""
x, y, z = r
B_mag = B0 * (1 + (z / L)**2)
# Simplified: B field in z direction with magnitude varying
# For full mirror: need radial component too
Bz = B_mag
Br = -B0 * (z / L**2) * np.sqrt(x**2 + y**2) # from div B = 0
theta = np.arctan2(y, x)
Bx = Br * np.cos(theta)
By = Br * np.sin(theta)
return np.array([0, 0, 0]), np.array([Bx, By, Bz])
# Test Case 1: Gyration in uniform B
print("Test 1: Gyration in uniform B field")
print("=" * 50)
B0 = 0.1 # T
v_perp = 1e6 # m/s
electron = Particle(q=-e, m=m_e, r0=[0, 0, 0], v0=[v_perp, 0, 0])
omega_c = e * B0 / m_e
rho_c = m_e * v_perp / (e * B0)
T_c = 2 * np.pi / omega_c
print(f"Cyclotron frequency: {omega_c:.3e} rad/s")
print(f"Gyroradius: {rho_c * 1e3:.3f} mm")
print(f"Cyclotron period: {T_c * 1e9:.3f} ns")
dt = T_c / 100
t_final = 3 * T_c
integrate_orbit(electron, lambda r, t: uniform_B(r, t, B0), lambda r, t: (np.zeros(3), np.zeros(3)),
t_final, dt)
r_hist = np.array(electron.history['r'])
fig = plt.figure(figsize=(12, 5))
ax1 = fig.add_subplot(121)
ax1.plot(r_hist[:, 0] * 1e3, r_hist[:, 1] * 1e3, 'b-', linewidth=1)
ax1.plot(r_hist[0, 0] * 1e3, r_hist[0, 1] * 1e3, 'go', markersize=8, label='Start')
ax1.set_xlabel('x (mm)')
ax1.set_ylabel('y (mm)')
ax1.set_title('Electron Gyration in Uniform B')
ax1.set_aspect('equal')
ax1.legend()
ax1.grid(alpha=0.3)
ax2 = fig.add_subplot(122, projection='3d')
ax2.plot(r_hist[:, 0] * 1e3, r_hist[:, 1] * 1e3, r_hist[:, 2] * 1e3, 'b-', linewidth=1)
ax2.set_xlabel('x (mm)')
ax2.set_ylabel('y (mm)')
ax2.set_zlabel('z (mm)')
ax2.set_title('3D View')
plt.tight_layout()
plt.savefig('project1_gyration.png', dpi=150)
plt.show()
# Verify gyroradius
x_max = np.max(np.abs(r_hist[:, 0]))
print(f"\nNumerical gyroradius: {x_max * 1e3:.3f} mm")
print(f"Theoretical: {rho_c * 1e3:.3f} mm")
print(f"Relative error: {100 * (x_max - rho_c) / rho_c:.2f}%")
# Test Case 2: EรB drift
print("\n\nTest 2: EรB drift")
print("=" * 50)
E0 = 1000 # V/m
B0 = 0.1 # T
v_ExB = E0 / B0
print(f"EรB drift velocity: {v_ExB:.2f} m/s")
proton = Particle(q=e, m=m_p, r0=[0, 0, 0], v0=[0, 1e5, 0])
t_final = 1e-4
dt = 1e-7
integrate_orbit(proton, lambda r, t: E_cross_B(r, t, E0, B0),
lambda r, t: (np.zeros(3), np.zeros(3)), t_final, dt)
r_hist = np.array(proton.history['r'])
t_hist = np.array(proton.history['t'])
# Calculate drift velocity
drift_y = (r_hist[-1, 1] - r_hist[0, 1]) / t_final
print(f"\nNumerical drift velocity: {drift_y:.2f} m/s")
print(f"Theoretical EรB drift: {v_ExB:.2f} m/s")
print(f"Relative error: {100 * (drift_y - v_ExB) / v_ExB:.2f}%")
plt.figure(figsize=(12, 5))
plt.subplot(121)
plt.plot(r_hist[:, 0] * 1e3, r_hist[:, 1] * 1e3, 'b-', linewidth=1)
plt.xlabel('x (mm)')
plt.ylabel('y (mm)')
plt.title('EรB Drift (x-y plane)')
plt.grid(alpha=0.3)
plt.subplot(122)
plt.plot(t_hist * 1e6, r_hist[:, 1] * 1e3, 'b-', linewidth=2)
plt.xlabel('Time (ฮผs)')
plt.ylabel('y position (mm)')
plt.title('Drift Motion')
plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('project1_ExB_drift.png', dpi=150)
plt.show()
# Test Case 3: Magnetic Mirror
print("\n\nTest 3: Magnetic Mirror")
print("=" * 50)
B0 = 0.1
L = 0.5
v_parallel = 1e5
v_perp = 5e4
electron_mirror = Particle(q=-e, m=m_e, r0=[0, 0, -0.4], v0=[v_perp, 0, v_parallel])
t_final = 5e-6
dt = 1e-9
integrate_orbit(electron_mirror, lambda r, t: magnetic_mirror(r, t, B0, L),
lambda r, t: (np.zeros(3), np.zeros(3)), t_final, dt)
r_hist = np.array(electron_mirror.history['r'])
v_hist = np.array(electron_mirror.history['v'])
# Calculate magnetic moment
B_field = np.array([magnetic_mirror(r, 0, B0, L)[1] for r in r_hist])
B_mag = np.linalg.norm(B_field, axis=1)
mu_values = []
for i, (v, B) in enumerate(zip(v_hist, B_field)):
B_unit = B / B_mag[i]
v_par = np.dot(v, B_unit)
v_perp_mag = np.sqrt(np.dot(v, v) - v_par**2)
mu = m_e * v_perp_mag**2 / (2 * B_mag[i])
mu_values.append(mu)
mu_values = np.array(mu_values)
print(f"Magnetic moment ฮผ:")
print(f" Mean: {np.mean(mu_values):.3e} J/T")
print(f" Std: {np.std(mu_values):.3e} J/T")
print(f" Variation: {100 * np.std(mu_values) / np.mean(mu_values):.2f}%")
fig = plt.figure(figsize=(12, 5))
ax1 = fig.add_subplot(121)
ax1.plot(r_hist[:, 2], r_hist[:, 0] * 1e3, 'b-', linewidth=1)
ax1.set_xlabel('z (m)')
ax1.set_ylabel('x (mm)')
ax1.set_title('Mirror Bounce Motion (side view)')
ax1.grid(alpha=0.3)
ax2 = fig.add_subplot(122)
ax2.plot(np.array(electron_mirror.history['t']) * 1e6, mu_values / mu_values[0], 'b-', linewidth=1)
ax2.axhline(1.0, color='r', linestyle='--', label='Perfect conservation')
ax2.set_xlabel('Time (ฮผs)')
ax2.set_ylabel('ฮผ / ฮผโ')
ax2.set_title('Magnetic Moment Conservation')
ax2.legend()
ax2.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('project1_mirror.png', dpi=150)
plt.show()
print("\nProject 1 complete!")
1.5 ํ์ฅ¶
- ์์ค ์๋ฟ: ๊ฑฐ์ธ ๊ตฌ์ฑ์์ ํผ์น๊ฐ์ ๋ณ๊ฒฝํ๊ณ ์์ค ์๋ฟ ๊ฐ๋๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
- ํ ์นด๋ง ๊ถค๋: ํ ๋ก์ด๋ฌ ์ฅ $B_\phi \propto 1/R$๊ณผ ํด๋ก์ด๋ฌ ์ฅ $B_\theta$๋ฅผ ๊ตฌํํ์ฌ ๋ฐ๋๋ ๊ถค๋๋ฅผ ๋ด ๋๋ค.
- ํธ์ต์นด๋ ๋จ๋ฉด: ์ฃผ๊ธฐ ๊ถค๋์ ๊ฒฝ์ฐ, ์์ ๊ณต๊ฐ(์: $x=0$ ๊ต์ฐจ์ ์์ $v_\parallel$ ๋ $z$)์ ํ๋กฏํฉ๋๋ค.
- ์๋๋ก ์ ์ ์: ์๋๋ก ์ ์๋์ง๋ก ํ์ฅํ๊ณ ๋น์๋๋ก ์ ๊ณผ ๋น๊ตํฉ๋๋ค.
- ํต๊ณ ์์๋ธ: ์๋ก ๋ค๋ฅธ ์ด๊ธฐ ์กฐ๊ฑด์ผ๋ก ๋ง์ ์ ์๋ฅผ ์คํํ๊ณ ํ๋ฅ ํต๊ณ๋ฅผ ๊ณ์ฐํฉ๋๋ค.
ํ๋ก์ ํธ 2: ๋ถ์ฐ ๊ด๊ณ ํด๊ฒฐ๊ธฐ¶
2.1 ๊ฐ์¶
๋ชฉํ: ํ๋ผ์ฆ๋ง์์ ์ ์ ๊ธฐ ๋ฐ ์ ์๊ธฐํ ๋ถ์ฐ ๊ด๊ณ๋ฅผ ์ํ ์ผ๋ฐ ํด๊ฒฐ๊ธฐ๋ฅผ ๋ง๋ญ๋๋ค. ๋ถ์ฐ ๋ค์ด์ด๊ทธ๋จ, CMA ๋ค์ด์ด๊ทธ๋จ์ ์์ฑํ๊ณ ํ๋ ๋ชจ๋๋ฅผ ์๋ณํฉ๋๋ค.
๋์ด๋: โญโญโญโญ
์์ ์๊ฐ: 12โ20์๊ฐ
๊ฐ๋ฐ ๊ธฐ์ : - ๋ณต์กํ ๋ถ์ฐ ๊ด๊ณ๋ฅผ ์ํ ๊ทผ ์ฐพ๊ธฐ - ๋๊ฐ ๋ฐ ์จ๋ ํ๋ผ์ฆ๋ง ํ๋ ์ด๋ก ์ดํด - ๋ค์ฐจ์ ๋ฐ์ดํฐ ์๊ฐํ(ฯ-k ๋ค์ด์ด๊ทธ๋จ, CMA ๋ค์ด์ด๊ทธ๋จ) - ํ๋ ๋ชจ๋ ๋ฐ ๊ณต๋ช /์ฐจ๋จ ํด์
2.2 ๋ฌผ๋ฆฌ ๋ฐฐ๊ฒฝ¶
ํ๋ผ์ฆ๋ง์์ ์ ์๊ธฐํ์ ๋ถ์ฐ ๊ด๊ณ๋ ํ๋ผ์ฆ๋ง ์ ๋ฅ $\mathbf{J}$๋ฅผ ํฌํจํ ๋งฅ์ค์ฐ ๋ฐฉ์ ์์์ ์ ๋๋ฉ๋๋ค:
$$\nabla \times \nabla \times \mathbf{E} + \frac{\omega^2}{c^2} \overleftrightarrow{\epsilon} \cdot \mathbf{E} = 0$$
์ฌ๊ธฐ์ $\overleftrightarrow{\epsilon}$๋ ์ ์ ํ ์์ ๋๋ค.
๋๊ฐ, ์ํ ํ๋ผ์ฆ๋ง์ ๊ฒฝ์ฐ, ์ฃผ ์ขํ๊ณ์์ ์ ์ ํ ์๋:
$$\overleftrightarrow{\epsilon} = \begin{pmatrix} S & -iD & 0 \\ iD & S & 0 \\ 0 & 0 & P \end{pmatrix}$$
์ฌ๊ธฐ์ ์คํฑ์ค ๋งค๊ฐ๋ณ์๋:
$$S = 1 - \sum_s \frac{\omega_{ps}^2}{\omega^2 - \omega_{cs}^2}$$ $$D = \sum_s \frac{\omega_{cs}}{\omega} \frac{\omega_{ps}^2}{\omega^2 - \omega_{cs}^2}$$ $$P = 1 - \sum_s \frac{\omega_{ps}^2}{\omega^2}$$
์๊ธฐ์ฅ์ ๋ํ ๊ฐ๋ $\theta$๋ก ์ ํํ๋ ๊ฒฝ์ฐ, ๋ถ์ฐ ๊ด๊ณ๋:
$$A n^4 - B n^2 + C = 0$$
์ฌ๊ธฐ์ $n = ck/\omega$๋ ๊ตด์ ๋ฅ ์ด๊ณ :
$$A = S \sin^2\theta + P \cos^2\theta$$ $$B = (S^2 - D^2) \sin^2\theta + PS(1 + \cos^2\theta)$$ $$C = P(S^2 - D^2)$$
์จ๋ ํ๋ผ์ฆ๋ง ๋ณด์ ์ ์ด ํญ(๋ด-๊ทธ๋ก์ค, ๋๋ค์ฐ ๊ฐ์ ๋ฑ)์ ์ถ๊ฐํฉ๋๋ค.
2.3 ๊ตฌํ ๊ฐ์ด๋¶
๋จ๊ณ 1: ์คํฑ์ค ๋งค๊ฐ๋ณ์
def stix_parameters(omega, omega_ps, omega_cs):
"""
Calculate Stix parameters S, D, P.
Parameters:
omega: wave frequency (rad/s)
omega_ps: plasma frequencies (array for each species)
omega_cs: cyclotron frequencies (array, signed)
Returns:
S, D, P
"""
S = 1 - np.sum(omega_ps**2 / (omega**2 - omega_cs**2))
D = np.sum((omega_cs / omega) * omega_ps**2 / (omega**2 - omega_cs**2))
P = 1 - np.sum(omega_ps**2 / omega**2)
return S, D, P
๋จ๊ณ 2: ๋ถ์ฐ ๊ด๊ณ
def cold_plasma_dispersion(omega, k, theta, omega_ps, omega_cs):
"""
Cold plasma dispersion relation: A n^4 - B n^2 + C = 0.
Returns the LHS (should be zero for a wave mode).
"""
S, D, P = stix_parameters(omega, omega_ps, omega_cs)
c = 3e8
n = c * k / omega # refractive index
sin2 = np.sin(theta)**2
cos2 = np.cos(theta)**2
A = S * sin2 + P * cos2
B = (S**2 - D**2) * sin2 + P * S * (1 + cos2)
C = P * (S**2 - D**2)
return A * n**4 - B * n**2 + C
๋จ๊ณ 3: ๊ทผ ์ฐพ๊ธฐ
์ฃผ์ด์ง $k$์ $\theta$์ ๋ํด, ๋ถ์ฐ ๊ด๊ณ๊ฐ ๋ง์กฑ๋๋๋ก $\omega$๋ฅผ ์ฐพ์ต๋๋ค:
from scipy.optimize import fsolve, brentq
def find_omega(k, theta, omega_guess, omega_ps, omega_cs):
"""
Find wave frequency ฯ for given k and ฮธ.
"""
def dispersion_func(omega):
if omega <= 0:
return 1e10 # penalize negative frequencies
return cold_plasma_dispersion(omega, k, theta, omega_ps, omega_cs)
omega_solution = fsolve(dispersion_func, omega_guess)[0]
return omega_solution
๋จ๊ณ 4: ๋ถ์ฐ ๋ค์ด์ด๊ทธ๋จ ์์ฑ
def dispersion_diagram(k_range, theta, omega_ps, omega_cs, omega_guesses):
"""
Generate ฯ(k) dispersion diagram for multiple modes.
Parameters:
k_range: array of wavenumbers
theta: propagation angle
omega_guesses: list of initial guesses for different modes
Returns:
omegas: list of arrays, one per mode
"""
omegas = [[] for _ in omega_guesses]
for k in k_range:
for i, omega_guess in enumerate(omega_guesses):
try:
omega_sol = find_omega(k, theta, omega_guess, omega_ps, omega_cs)
if omega_sol > 0 and np.abs(cold_plasma_dispersion(omega_sol, k, theta,
omega_ps, omega_cs)) < 1e-3:
omegas[i].append(omega_sol)
else:
omegas[i].append(np.nan)
except:
omegas[i].append(np.nan)
return [np.array(omega_list) for omega_list in omegas]
๋จ๊ณ 5: CMA ๋ค์ด์ด๊ทธ๋จ
ํด๋ ๋ชจ-๋ฉ๋ ๋ฆฌ-์จ๋ฆฌ์ค(CMA) ๋ค์ด์ด๊ทธ๋จ์ $(\omega_{pe}^2/\omega_{ce}^2, \omega^2/\omega_{ce}^2)$ ๊ณต๊ฐ์์ ์๋ก ๋ค๋ฅธ ํ๋ ๋ชจ๋๊ฐ ์กด์ฌํ๋ ์์ญ์ ๋ณด์ฌ์ค๋๋ค.
์ฐจ๋จ๊ณผ ๊ณต๋ช : - R ์ฐจ๋จ: $\omega = \omega_R = \frac{1}{2}(\omega_{ce} + \sqrt{\omega_{ce}^2 + 4\omega_{pe}^2})$ - L ์ฐจ๋จ: $\omega = \omega_L = \frac{1}{2}(-\omega_{ce} + \sqrt{\omega_{ce}^2 + 4\omega_{pe}^2})$ - P ์ฐจ๋จ: $\omega = \omega_{pe}$ - ์๋ถ ํ์ด๋ธ๋ฆฌ๋: $\omega_{UH}^2 = \omega_{pe}^2 + \omega_{ce}^2$ - ํ๋ถ ํ์ด๋ธ๋ฆฌ๋: $\omega_{LH}^2 = \frac{\omega_{pi}^2}{1 + \omega_{pe}^2 / \omega_{ce}^2}$
2.4 ์์ ํ ์ฝ๋¶
import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import fsolve, brentq
# Constants
e = 1.6e-19
m_e = 9.11e-31
m_p = 1.67e-27
c = 3e8
def stix_parameters(omega, omega_ps, omega_cs):
"""Calculate Stix parameters S, D, P."""
S = 1 - np.sum(omega_ps**2 / (omega**2 - omega_cs**2 + 1e-10))
D = np.sum((omega_cs / omega) * omega_ps**2 / (omega**2 - omega_cs**2 + 1e-10))
P = 1 - np.sum(omega_ps**2 / (omega**2 + 1e-10))
return S, D, P
def cold_plasma_dispersion(omega, k, theta, omega_ps, omega_cs):
"""Cold plasma dispersion relation."""
S, D, P = stix_parameters(omega, omega_ps, omega_cs)
n = c * k / (omega + 1e-10)
sin2 = np.sin(theta)**2
cos2 = np.cos(theta)**2
A = S * sin2 + P * cos2
B = (S**2 - D**2) * sin2 + P * S * (1 + cos2)
C = P * (S**2 - D**2)
return A * n**4 - B * n**2 + C
# Plasma parameters
n = 1e18 # m^-3
B = 0.05 # T
omega_pe = np.sqrt(n * e**2 / (m_e * 8.85e-12))
omega_pi = np.sqrt(n * e**2 / (m_p * 8.85e-12))
omega_ce = e * B / m_e
omega_ci = e * B / m_p
omega_ps = np.array([omega_pe, omega_pi])
omega_cs = np.array([omega_ce, -omega_ci]) # electrons +, ions -
print("Plasma parameters:")
print(f" ฯ_pe / (2ฯ) = {omega_pe / (2 * np.pi):.3e} Hz")
print(f" ฯ_ce / (2ฯ) = {omega_ce / (2 * np.pi):.3e} Hz")
print(f" ฯ_pi / (2ฯ) = {omega_pi / (2 * np.pi):.3e} Hz")
print(f" ฯ_ci / (2ฯ) = {omega_ci / (2 * np.pi):.3e} Hz")
print()
# Cutoff frequencies
omega_R = 0.5 * (omega_ce + np.sqrt(omega_ce**2 + 4 * omega_pe**2))
omega_L = 0.5 * (-omega_ce + np.sqrt(omega_ce**2 + 4 * omega_pe**2))
omega_UH = np.sqrt(omega_pe**2 + omega_ce**2)
omega_LH = omega_pi / np.sqrt(1 + omega_pe**2 / omega_ce**2)
print("Characteristic frequencies:")
print(f" R cutoff: {omega_R / (2 * np.pi):.3e} Hz")
print(f" L cutoff: {omega_L / (2 * np.pi):.3e} Hz")
print(f" Upper hybrid: {omega_UH / (2 * np.pi):.3e} Hz")
print(f" Lower hybrid: {omega_LH / (2 * np.pi):.3e} Hz")
print()
# Dispersion diagram: parallel propagation (ฮธ = 0)
k_range = np.linspace(1, 1000, 300)
theta = 0 # parallel
# Find O-mode (P = 0 โ ฯ = ฯ_pe) and X-mode (more complex)
omega_O = []
omega_R_mode = []
omega_L_mode = []
for k in k_range:
# O-mode: ฯยฒ = ฯ_peยฒ + kยฒ cยฒ
omega_O.append(np.sqrt(omega_pe**2 + (k * c)**2))
# R-mode: solve S - nยฒ = 0
def R_dispersion(omega):
S, D, P = stix_parameters(omega, omega_ps, omega_cs)
n = c * k / omega
return S - n**2
# L-mode: solve S - nยฒ = 0 (but different branch)
try:
omega_R_sol = fsolve(R_dispersion, omega_R * 1.5)[0]
if omega_R_sol > omega_R and omega_R_sol < 10 * omega_ce:
omega_R_mode.append(omega_R_sol)
else:
omega_R_mode.append(np.nan)
except:
omega_R_mode.append(np.nan)
try:
omega_L_sol = fsolve(R_dispersion, omega_L * 0.9)[0]
if omega_L_sol > 0 and omega_L_sol < omega_L * 1.5:
omega_L_mode.append(omega_L_sol)
else:
omega_L_mode.append(np.nan)
except:
omega_L_mode.append(np.nan)
omega_O = np.array(omega_O)
omega_R_mode = np.array(omega_R_mode)
omega_L_mode = np.array(omega_L_mode)
# Plot dispersion diagram
plt.figure(figsize=(12, 7))
plt.plot(k_range, omega_O / omega_ce, 'b-', linewidth=2, label='O-mode')
plt.plot(k_range, omega_R_mode / omega_ce, 'r-', linewidth=2, label='R-mode (X-mode branch)')
plt.plot(k_range, omega_L_mode / omega_ce, 'g-', linewidth=2, label='L-mode (X-mode branch)')
# Light line
plt.plot(k_range, k_range * c / omega_ce, 'k--', linewidth=1, alpha=0.5, label='Light line ฯ = ck')
# Cutoffs and resonances
plt.axhline(omega_R / omega_ce, color='r', linestyle=':', alpha=0.7, label=f'R cutoff')
plt.axhline(omega_L / omega_ce, color='g', linestyle=':', alpha=0.7, label=f'L cutoff')
plt.axhline(omega_pe / omega_ce, color='b', linestyle=':', alpha=0.7, label=f'ฯ_pe')
plt.axhline(omega_UH / omega_ce, color='m', linestyle=':', alpha=0.7, label=f'Upper hybrid')
plt.axhline(1.0, color='orange', linestyle=':', alpha=0.7, label=f'ฯ_ce')
plt.xlabel('Wavenumber k (mโปยน)', fontsize=12)
plt.ylabel('ฯ / ฯ_ce', fontsize=12)
plt.title('Cold Plasma Dispersion: Parallel Propagation (ฮธ = 0)', fontsize=14)
plt.legend(fontsize=10, loc='upper left')
plt.grid(alpha=0.3)
plt.xlim(0, 1000)
plt.ylim(0, 20)
plt.tight_layout()
plt.savefig('project2_dispersion_parallel.png', dpi=150)
plt.show()
print("Project 2: Dispersion diagram complete!")
2.5 ํ์ฅ¶
- ๋น์ค๋ฌํ ์ ํ: $\theta$๋ฅผ 0์์ $\pi/2$๋ก ๋ณ๊ฒฝํ๊ณ $\omega(k, \theta)$๋ฅผ 3D ํ๋ฉด์ผ๋ก ํ๋กฏํฉ๋๋ค.
- ์จ๋ ํ๋ผ์ฆ๋ง: ์ด ๋ณด์ ์ถ๊ฐ(๋ด-๊ทธ๋ก์ค: $\omega^2 = \omega_{pe}^2 + 3k^2 v_{te}^2$).
- ์ด์จ ์ํฅํ: ์ด์จ ์๋ต ํฌํจ, ๋๋ค์ฐ ๊ฐ์ ์ ํจ๊ป IA ๋ถ์ฐ ํ๋กฏ.
- CMA ๋ค์ด์ด๊ทธ๋จ: $(X, Y)$ ๊ณต๊ฐ์์ ์ ํ/๊ฐ์ ์์ญ ํ๋กฏ ($X = \omega_{pe}^2/\omega^2$, $Y = \omega_{ce}/\omega$).
- ๊ณต๋ช ์๋ฟ: ํ์ฌ๋ฌํ์ ๊ฒฝ์ฐ, ์ฃผํ์ ๋ ๊ณต๋ช ์๋ฟ ๊ฐ๋ ํ๋กฏ.
ํ๋ก์ ํธ 3: 1D ๋ธ๋ผ์ํ-ํธ์์ก ํด๊ฒฐ๊ธฐ¶
3.1 ๊ฐ์¶
๋ชฉํ: ๋ฐ๋ผ๊ทธ๋์ฃผ(๋ถํ ) ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ฌ 1D-1V ๋ธ๋ผ์ํ-ํธ์์ก ํด๊ฒฐ๊ธฐ๋ฅผ ๊ตฌํํฉ๋๋ค. ๋ญ๋ฎค์ด ์ง๋, ๋๋ค์ฐ ๊ฐ์ , ์๋ฅ ๋ถ์์ ์ฑ, ๋ฒํ-์จ-ํ ์ผ ๋ถ์์ ์ฑ์ ์๋ฎฌ๋ ์ด์ ํฉ๋๋ค.
๋์ด๋: โญโญโญโญโญ
์์ ์๊ฐ: 20โ30์๊ฐ
๊ฐ๋ฐ ๊ธฐ์ : - PDE๋ฅผ ์ํ ๊ณ ๊ธ ์์น ๋ฐฉ๋ฒ - ์ด๋ ํ๋ผ์ฆ๋ง ์๋ฎฌ๋ ์ด์ - FFT ๊ธฐ๋ฐ ํธ์์ก ํด๊ฒฐ๊ธฐ - ์์ ๊ณต๊ฐ ์๊ฐํ - ์ ํ ์ด๋ก ๊ณผ ๋น๊ต(๋๋ค์ฐ ๊ฐ์ ์จ, ์ฑ์ฅ๋ฅ )
3.2 ๋ฌผ๋ฆฌ ๋ฐฐ๊ฒฝ¶
1D ๋ธ๋ผ์ํ ๋ฐฉ์ ์์ ์ ์ ๋ถํฌ ํจ์ $f(x, v, t)$์ ์งํ๋ฅผ ์ค๋ช ํฉ๋๋ค:
$$\frac{\partial f}{\partial t} + v \frac{\partial f}{\partial x} + \frac{q E}{m} \frac{\partial f}{\partial v} = 0$$
์ ๊ธฐ์ฅ์ ์ํ ํธ์์ก ๋ฐฉ์ ์๊ณผ ๊ฒฐํฉ:
$$\frac{\partial E}{\partial x} = \frac{q}{\epsilon_0} (n_i - n_e)$$
์ฌ๊ธฐ์ ์ ์ ๋ฐ๋๋: $$n_e(x, t) = \int f(x, v, t) \, dv$$
์ด์จ์ ๊ณ ์ ๋ ์ค์ฑํ ๋ฐฐ๊ฒฝ์ผ๋ก ๊ฐ์ : $n_i = n_0 = \text{const}$.
๋ถํ ๋ฐฉ๋ฒ: ๋ธ๋ผ์ํ ๋ฐฉ์ ์์ ๋ ๋จ๊ณ๋ก ๋ถํ :
-
x์์ ์ด๋ฅ(์์ ํ๋ฆ): $$\frac{\partial f}{\partial t} + v \frac{\partial f}{\partial x} = 0$$
-
v์์ ์ด๋ฅ(๊ฐ์): $$\frac{\partial f}{\partial t} + \frac{q E}{m} \frac{\partial f}{\partial v} = 0$$
๊ฐ ๋จ๊ณ๋ ํน์ฑ์ ์ญ์ถ์ ์ผ๋ก ์ ํํ ํด๊ฒฐ๋ฉ๋๋ค.
3.3 ๊ตฌํ ๊ฐ์ด๋¶
๋จ๊ณ 1: ์ด๊ธฐํ
์์ ๊ณต๊ฐ ๊ทธ๋ฆฌ๋ ์ค์ : - $x \in [0, L]$์์ $N_x$ ๊ทธ๋ฆฌ๋ ์ - $v \in [v_{min}, v_{max}]$์์ $N_v$ ๊ทธ๋ฆฌ๋ ์ - ์ด๊ธฐ ๋ถํฌ: ๋๋ค์ฐ ๊ฐ์ ๋ฅผ ์ํ $f_0(x, v) = f_0(v) (1 + \alpha \cos(kx))$
๋จ๊ณ 2: ํธ์์ก ํด๊ฒฐ๊ธฐ(FFT)
def solve_poisson_fft(rho, dx, L):
"""
Solve Poisson equation: dยฒฯ/dxยฒ = -ฯ/ฮตโ using FFT.
Returns electric field E = -dฯ/dx.
"""
epsilon_0 = 8.85e-12
Nx = len(rho)
# Fourier transform of rho
rho_k = np.fft.fft(rho)
# Wavenumbers
k = 2 * np.pi * np.fft.fftfreq(Nx, d=dx)
k[0] = 1 # avoid division by zero (DC component is arbitrary for periodic)
# Fourier transform of potential: ฯ_k = -ฯ_k / (ฮตโ kยฒ)
phi_k = -rho_k / (epsilon_0 * k**2)
phi_k[0] = 0 # set DC component to zero
# Electric field: E = -dฯ/dx โ E_k = i k ฯ_k
E_k = 1j * k * phi_k
# Inverse FFT
E = np.real(np.fft.ifft(E_k))
return E
๋จ๊ณ 3: x์์ ์ด๋ฅ
$\partial f / \partial t + v \partial f / \partial x = 0$์ ํด๊ฒฐ:
๊ฐ $v_j$์ ๋ํด, ํน์ฑ์ $x(t) = x_0 + v_j \Delta t$์ ๋๋ค. $f$๋ฅผ ์ ๋ฐ์ดํธํ๊ธฐ ์ํด ์ญ์ถ์ :
$$f^{n+1}(x_i, v_j) = f^n(x_i - v_j \Delta t, v_j)$$
๋น๊ทธ๋ฆฌ๋ ๊ฐ์ ๋ํด ๋ณด๊ฐ(์: 3์ฐจ ์คํ๋ผ์ธ) ์ฌ์ฉ.
๋จ๊ณ 4: v์์ ์ด๋ฅ
$\partial f / \partial t + (qE/m) \partial f / \partial v = 0$์ ํด๊ฒฐ:
๊ฐ $x_i$์ ๋ํด, ํน์ฑ์ $v(t) = v_0 + (q E_i / m) \Delta t$์ ๋๋ค. ์ ๋ฐ์ดํธ:
$$f^{n+1}(x_i, v_j) = f^n(x_i, v_j - \frac{qE_i}{m} \Delta t)$$
๋ค์ ๋ณด๊ฐ ์ฌ์ฉ.
๋จ๊ณ 5: ์๊ฐ ๋จ๊ณ ๋ฃจํ
for n in range(Nt):
# 1. Compute density
n_e = np.trapz(f, v_grid, axis=1)
# 2. Solve Poisson
rho = e * (n_0 - n_e)
E = solve_poisson_fft(rho, dx, L)
# 3. Advection in x (half step)
f = advect_x(f, v_grid, dt/2)
# 4. Advection in v (full step)
f = advect_v(f, E, dt)
# 5. Advection in x (half step)
f = advect_x(f, v_grid, dt/2)
# 6. Diagnostics
energy[n] = compute_energy(f, E)
3.4 ํ ์คํธ ์ผ์ด์ค¶
ํ ์คํธ 1: ํ๋ผ์ฆ๋ง ์ง๋
์์ ์ ํํ ๋ฐ๋ ๊ต๋์ผ๋ก ์ด๊ธฐํ: $$n_e(x, 0) = n_0 (1 + \epsilon \cos(kx)), \quad f(x, v, 0) = \frac{n_e(x, 0)}{\sqrt{2\pi v_{th}^2}} e^{-v^2/(2v_{th}^2)}$$
์ ๊ธฐ์ฅ์ $\omega_{pe}$์์ ์ง๋ํด์ผ ํฉ๋๋ค. ๊ฒ์ฆ: $$\omega_{pe} = \sqrt{\frac{n_0 e^2}{\epsilon_0 m_e}}$$
ํ ์คํธ 2: ๋๋ค์ฐ ๊ฐ์
๋์ผํ ์ด๊ธฐ ์กฐ๊ฑด ์ฌ์ฉ. ์ ๊ธฐ์ฅ ์งํญ์ ์ง์์ ์ผ๋ก ๊ฐ์ ํด์ผ ํฉ๋๋ค: $$E(t) \propto e^{-\gamma_L t}$$
์ฌ๊ธฐ์ ๋๋ค์ฐ ๊ฐ์ ์จ์ ($k\lambda_D \ll 1$์ ๊ฒฝ์ฐ): $$\gamma_L \approx \sqrt{\frac{\pi}{8}} \omega_{pe} (k\lambda_D)^{-3} e^{-1/(2k^2\lambda_D^2)}$$
ํ ์คํธ 3: ์๋ฅ ๋ถ์์ ์ฑ
๋ ๊ฐ์ ๋ฐ๋ ๋ฐฉํฅ ๋น์ผ๋ก ์ด๊ธฐํ: $$f(x, v, 0) = \frac{n_0}{2} \left[ \frac{1}{\sqrt{2\pi v_{th}^2}} e^{-(v - v_0)^2 / (2v_{th}^2)} + \frac{1}{\sqrt{2\pi v_{th}^2}} e^{-(v + v_0)^2 / (2v_{th}^2)} \right]$$
$x$์ ์์ ๊ต๋ ํฌํจ. ๋ถ์์ ์ฑ์ ์ง์์ ์ผ๋ก ์ฑ์ฅํฉ๋๋ค. ์ฑ์ฅ๋ฅ ์ ์ธก์ ํ๊ณ ์ด๋ก ๊ณผ ๋น๊ตํฉ๋๋ค.
ํ ์คํธ 4: ๋ฒํ-์จ-ํ ์ผ
๋ฒํฌ ๋งฅ์ค์ฐ๋ฆฌ์์ ๋ ๋์ ์๋์์ ์์ ๋ฒํ๋ฅผ ์ถ๊ฐํ์ฌ ์ด๊ธฐํ: $$f(x, v, 0) = \frac{n_b}{\sqrt{2\pi v_{th}^2}} e^{-v^2/(2v_{th}^2)} + \frac{n_{bump}}{\sqrt{2\pi v_{bump}^2}} e^{-(v - v_{bump})^2/(2v_{bump}^2)}$$
์ด๊ฒ์ ๋ถ์์ ํ๊ณ ๋ฒํ๋ฅผ ํํํํ๋ ํ๋์ ๊ตฌ๋ํฉ๋๋ค(์ค์ ํ ํ์ฐ).
3.5 ์์ ํ ์ฝ๋(๋จ์ํ)¶
๊ธธ์ด ๋๋ฌธ์ ๊ฐ์ํ๋ ๋ฒ์ ์ ์ ๊ณตํฉ๋๋ค:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d
# Constants
e = 1.6e-19
m_e = 9.11e-31
epsilon_0 = 8.85e-12
# Grid parameters
Nx = 128
Nv = 128
L = 2 * np.pi / 1e5 # spatial domain (one wavelength)
v_max = 5e6 # m/s
x_grid = np.linspace(0, L, Nx, endpoint=False)
v_grid = np.linspace(-v_max, v_max, Nv)
dx = x_grid[1] - x_grid[0]
dv = v_grid[1] - v_grid[0]
# Plasma parameters
n_0 = 1e16 # m^-3
T_e = 1 # eV
v_th = np.sqrt(e * T_e / m_e)
omega_pe = np.sqrt(n_0 * e**2 / (epsilon_0 * m_e))
# Time step (CFL condition)
dt = 0.1 * min(dx / v_max, dv / (e * 1e3 / m_e)) # conservative
Nt = 500
print(f"ฯ_pe = {omega_pe:.3e} rad/s")
print(f"T_pe = {2 * np.pi / omega_pe:.3e} s")
print(f"dt = {dt:.3e} s")
print(f"Total time = {Nt * dt:.3e} s ({Nt * dt * omega_pe / (2 * np.pi):.2f} plasma periods)")
# Initial distribution: Maxwellian with perturbation
k_pert = 2 * np.pi / L
alpha = 0.01
f = np.zeros((Nx, Nv))
for i, x in enumerate(x_grid):
n_local = n_0 * (1 + alpha * np.cos(k_pert * x))
f[i, :] = n_local / (np.sqrt(2 * np.pi) * v_th) * np.exp(-v_grid**2 / (2 * v_th**2))
# Advection functions (using linear interpolation for simplicity)
def advect_x(f, v_grid, dt):
"""Advect in x: f(x - v*dt, v)."""
f_new = np.zeros_like(f)
for j, v in enumerate(v_grid):
shift = v * dt
x_old = (x_grid - shift) % L # periodic boundary
f_new[:, j] = np.interp(x_old, x_grid, f[:, j], period=L)
return f_new
def advect_v(f, E, dt):
"""Advect in v: f(x, v - (qE/m)*dt)."""
f_new = np.zeros_like(f)
for i, x_i in enumerate(x_grid):
accel = -e * E[i] / m_e
v_old = v_grid - accel * dt
# Interpolate (with extrapolation for boundary)
f_new[i, :] = np.interp(v_old, v_grid, f[i, :], left=0, right=0)
return f_new
def solve_poisson_fft(rho, dx):
"""Solve Poisson equation using FFT."""
Nx = len(rho)
rho_k = np.fft.fft(rho)
k = 2 * np.pi * np.fft.fftfreq(Nx, d=dx)
k[0] = 1 # avoid division by zero
phi_k = -rho_k / (epsilon_0 * k**2)
phi_k[0] = 0
E_k = 1j * k * phi_k
E = np.real(np.fft.ifft(E_k))
return E
# Diagnostics
E_history = []
energy_history = []
# Time-stepping loop
for n in range(Nt):
# Compute density
n_e = np.trapz(f, v_grid, axis=1)
# Solve Poisson
rho = e * (n_0 - n_e)
E = solve_poisson_fft(rho, dx)
# Store diagnostics
E_history.append(np.max(np.abs(E)))
field_energy = 0.5 * epsilon_0 * np.sum(E**2) * dx
kinetic_energy = 0.5 * m_e * np.sum(f * (v_grid[np.newaxis, :]**2) * dx * dv)
energy_history.append(field_energy + kinetic_energy)
# Split-step advection
f = advect_x(f, v_grid, dt / 2)
f = advect_v(f, E, dt)
f = advect_x(f, v_grid, dt / 2)
# Print progress
if n % 50 == 0:
print(f"Step {n}/{Nt}, E_max = {E_history[-1]:.3e} V/m")
# Plot results
t_grid = np.arange(Nt) * dt
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# Electric field amplitude vs. time
axes[0, 0].semilogy(t_grid * omega_pe / (2 * np.pi), E_history, 'b-', linewidth=1)
axes[0, 0].set_xlabel('Time (plasma periods)', fontsize=11)
axes[0, 0].set_ylabel('Max |E| (V/m)', fontsize=11)
axes[0, 0].set_title('Electric Field Amplitude (Landau Damping)', fontsize=12)
axes[0, 0].grid(alpha=0.3)
# Fit exponential decay to measure damping rate
t_fit = t_grid[50:200]
E_fit = np.array(E_history[50:200])
log_E = np.log(E_fit)
p = np.polyfit(t_fit, log_E, 1)
gamma_numerical = -p[0]
# Theoretical Landau damping rate
k = k_pert
lambda_D = v_th / omega_pe
kLD = k * lambda_D
gamma_theory = np.sqrt(np.pi / 8) * omega_pe * (kLD)**(-3) * np.exp(-1 / (2 * kLD**2))
axes[0, 0].plot(t_fit * omega_pe / (2 * np.pi), np.exp(p[0] * t_fit + p[1]), 'r--',
linewidth=2, label=f'Fit: ฮณ = {gamma_numerical:.2e} sโปยน')
axes[0, 0].legend(fontsize=10)
print(f"\nLandau damping:")
print(f" Numerical ฮณ = {gamma_numerical:.3e} sโปยน ({gamma_numerical/omega_pe:.3e} ฯ_pe)")
print(f" Theoretical ฮณ = {gamma_theory:.3e} sโปยน ({gamma_theory/omega_pe:.3e} ฯ_pe)")
print(f" Relative error = {100 * (gamma_numerical - gamma_theory) / gamma_theory:.1f}%")
# Energy conservation
axes[0, 1].plot(t_grid * omega_pe / (2 * np.pi), np.array(energy_history) / energy_history[0], 'g-',
linewidth=2)
axes[0, 1].axhline(1.0, color='k', linestyle='--', alpha=0.5)
axes[0, 1].set_xlabel('Time (plasma periods)', fontsize=11)
axes[0, 1].set_ylabel('Total energy / E(0)', fontsize=11)
axes[0, 1].set_title('Energy Conservation', fontsize=12)
axes[0, 1].grid(alpha=0.3)
# Phase space at initial time
axes[1, 0].contourf(x_grid, v_grid / 1e6, f.T, levels=20, cmap='viridis')
axes[1, 0].set_xlabel('x (m)', fontsize=11)
axes[1, 0].set_ylabel('v (10โถ m/s)', fontsize=11)
axes[1, 0].set_title('Phase Space f(x, v) at Final Time', fontsize=12)
# Density profile
n_e_final = np.trapz(f, v_grid, axis=1)
axes[1, 1].plot(x_grid, n_e_final / n_0, 'b-', linewidth=2, label='Final')
axes[1, 1].axhline(1.0, color='k', linestyle='--', alpha=0.5, label='Equilibrium')
axes[1, 1].set_xlabel('x (m)', fontsize=11)
axes[1, 1].set_ylabel('n_e / n_0', fontsize=11)
axes[1, 1].set_title('Density Profile', fontsize=12)
axes[1, 1].legend(fontsize=10)
axes[1, 1].grid(alpha=0.3)
plt.tight_layout()
plt.savefig('project3_vlasov_landau.png', dpi=150)
plt.show()
print("\nProject 3: Vlasov-Poisson simulation complete!")
3.6 ํ์ฅ¶
- ๊ณ ์ฐจ ๋ณด๊ฐ: ๋ ๋์ ์ ํ๋๋ฅผ ์ํด 3์ฐจ ๋๋ 5์ฐจ ์คํ๋ผ์ธ ์ฌ์ฉ.
- ์๋ฅ ๋ถ์์ ์ฑ: ์ด๊ธฐ ์กฐ๊ฑด ์์ , ์ฑ์ฅ๋ฅ ์ธก์ , ์ด๋ก ๊ณผ ๋น๊ต.
- ๋ฒํ-์จ-ํ ์ผ: ํํํ ๊ด์ธก, ํ๋ ์๋์ง ํฌํ ์ธก์ .
- ์ ์ ํฌํ: ํฌํ๋ ์ ์์ ์ํด ํ์ฑ๋ ์์ ๊ณต๊ฐ ์์ฉ๋์ด ํ๋กฏ.
- 2D ๋ธ๋ผ์ํ: 2D-2V๋ก ํ์ฅ(๊ณ์ฐ ์ง์ฝ์ !).
- PIC ๋น๊ต: ๊ฐ๋จํ 1D PIC ์ฝ๋๋ฅผ ๊ตฌํํ๊ณ ๋ธ๋ผ์ํ์ ๋น๊ต.
๊ฒฐ๋ก ¶
์ด ์ธ ํ๋ก์ ํธ๋ ์ ์ฒด ๊ฐ์ข์ ์๋ฃ๋ฅผ ์ข ํฉํฉ๋๋ค:
- ํ๋ก์ ํธ 1(์ ์ ๊ถค๋)์ ๋ ์จ 3โ4์ ๋จ์ผ ์ ์ ์ด๋ก ์ ์คํํฉ๋๋ค.
- ํ๋ก์ ํธ 2(๋ถ์ฐ ํด๊ฒฐ๊ธฐ)๋ ๋ ์จ 9โ10์ ํ๋ ์ด๋ก ์ ๊ตฌํํฉ๋๋ค.
- ํ๋ก์ ํธ 3(๋ธ๋ผ์ํ-ํธ์์ก)์ ๋ ์จ 6โ8์ ์ด๋ ์ด๋ก ์ ๋ค๋ฃจ๊ณ ๋๋ค์ฐ ๊ฐ์ ์ ๊ฐ์ ๊ธฐ๋ณธ ํ๋ผ์ฆ๋ง ํ์์ ๋ณด์ฌ์ค๋๋ค.
์ด๋ฌํ ํ๋ก์ ํธ๋ฅผ ์๋ฃํ๋ฉด ํ๋ ํ๋ผ์ฆ๋ง ๋ฌผ๋ฆฌ ์ฐ๊ตฌ์์ ์ฌ์ฉ๋๋ ๊ณ์ฐ ๋๊ตฌ์ ๋ํ ์ค๋ฌด ๊ฒฝํ์ ๊ฐ๊ฒ ๋ฉ๋๋ค. ์ด๋ฌํ ๋ฐฉ๋ฒ์ ๋ค์์ผ๋ก ํ์ฅ๋ฉ๋๋ค:
- ์ ์-์ (PIC) ์ฝ๋: ๋ฌด์ถฉ๋ ํ๋ผ์ฆ๋ง ์๋ฎฌ๋ ์ด์ (์: ๋ ์ด์ -ํ๋ผ์ฆ๋ง ์ํธ์์ฉ, ์ฐ์ฃผ ๋ฌผ๋ฆฌ)
- ์์ด๋ก์ด๋๋ก ์ฝ๋: ํ ์นด๋ง ๋๋ฅ(์: GENE, GYRO, GS2)
- MHD ์ฝ๋: ํต์ตํฉ ํํ ๋ฐ ์์ ์ฑ(์: NIMROD, M3D-C1)
ํ๋ผ์ฆ๋ง ๋ฌผ๋ฆฌ ๊ณผ์ ์ ์๋ฃํ์ ๊ฒ์ ์ถํํฉ๋๋ค! ์ด์ ํ๋ผ์ฆ๋ง ๋ฌผ๋ฆฌ์ ์ด๋ก ๊ณผ ๊ณ์ฐ ๋ชจ๋์ ๋ํ ๊ฒฌ๊ณ ํ ๊ธฐ์ด๋ฅผ ๊ฐ์ถ์ จ์ต๋๋ค.
์ด์ : ํ๋ผ์ฆ๋ง ์ง๋จ | ๋ค์: ์์(๋ง์ง๋ง ๋ ์จ)