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$):

  1. ์ „๊ธฐ์žฅ์— ์˜ํ•œ ์ ˆ๋ฐ˜ ๊ฐ€์†: $$\mathbf{v}^{-} = \mathbf{v}^n + \frac{q \Delta t}{2m} \mathbf{E}$$

  2. ์ž๊ธฐ์žฅ์— ์˜ํ•œ ํšŒ์ „: $$\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}$$

  3. ์ „๊ธฐ์žฅ์— ์˜ํ•œ ์ ˆ๋ฐ˜ ๊ฐ€์†: $$\mathbf{v}^{n+1} = \mathbf{v}^{+} + \frac{q \Delta t}{2m} \mathbf{E}$$

  4. ์œ„์น˜ ์—…๋ฐ์ดํŠธ: $$\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)$๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜ ๊ตฌํ˜„:

  1. ๊ท ์ผํ•œ B: $\mathbf{B} = B_0 \hat{\mathbf{z}}$ (์„ ํšŒ)
  2. ๊ท ์ผํ•œ E + B: $\mathbf{E} = E_0 \hat{\mathbf{x}}$, $\mathbf{B} = B_0 \hat{\mathbf{z}}$ (Eร—B ํ‘œ๋ฅ˜)
  3. ๊ฒฝ์‚ฌ B: $\mathbf{B} = B_0 (1 + \alpha x) \hat{\mathbf{z}}$ (grad-B ํ‘œ๋ฅ˜)
  4. ๊ณก์„  B: $\mathbf{B} = \frac{B_0 R_0}{R_0 + x} \hat{\mathbf{z}}$ (๊ณก๋ฅ  ํ‘œ๋ฅ˜, ๋‹จ์ˆœํ™”)
  5. ์ž๊ธฐ ๊ฑฐ์šธ: $\mathbf{B} = B_0 (1 + (z/L)^2) \hat{\mathbf{z}}$ (๊ฑฐ์šธ ํž˜)
  6. ํ† ์นด๋ง‰(๋‹จ์ˆœํ™”): ํ† ๋กœ์ด๋‹ฌ + ํด๋กœ์ด๋‹ฌ ์žฅ

๋‹จ๊ณ„ 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: ๋ถ„์„ ๋ฐ ๊ฒ€์ฆ

๊ฐ ์žฅ ๊ตฌ์„ฑ์— ๋Œ€ํ•ด ๊ณ„์‚ฐ:

  1. ์„ ํšŒ ๋ฐ˜์ง€๋ฆ„: $\rho = m v_\perp / (q B)$
  2. ํ‘œ๋ฅ˜ ์†๋„: ์ˆ˜์น˜์™€ ํ•ด์„ ๋น„๊ต:
  3. Eร—B ํ‘œ๋ฅ˜: $\mathbf{v}_E = \mathbf{E} \times \mathbf{B} / B^2$
  4. Grad-B ํ‘œ๋ฅ˜: $\mathbf{v}_{\nabla B} = \pm \frac{m v_\perp^2}{2 q B^3} \mathbf{B} \times \nabla B$
  5. ๊ณก๋ฅ  ํ‘œ๋ฅ˜: $\mathbf{v}_\kappa = \frac{m v_\parallel^2}{q B^3} \mathbf{B} \times (\mathbf{B} \cdot \nabla)\mathbf{B}$
  6. ๋‹จ์—ด ๋ถˆ๋ณ€๋Ÿ‰:
  7. ์ž๊ธฐ ๋ชจ๋ฉ˜ํŠธ: $\mu = m v_\perp^2 / (2B)$
  8. ์ข…๋ฐฉํ–ฅ ์ž‘์šฉ: $J = \oint v_\parallel ds$ (๋ฐ”์šด์Šค ์šด๋™์˜ ๊ฒฝ์šฐ)
  9. ์—๋„ˆ์ง€ ๋ณด์กด: ์ •์  ์žฅ์—์„œ $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 ํ™•์žฅ

  1. ์†์‹ค ์›๋ฟ”: ๊ฑฐ์šธ ๊ตฌ์„ฑ์—์„œ ํ”ผ์น˜๊ฐ์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์†์‹ค ์›๋ฟ” ๊ฐ๋„๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.
  2. ํ† ์นด๋ง‰ ๊ถค๋„: ํ† ๋กœ์ด๋‹ฌ ์žฅ $B_\phi \propto 1/R$๊ณผ ํด๋กœ์ด๋‹ฌ ์žฅ $B_\theta$๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋ฐ”๋‚˜๋‚˜ ๊ถค๋„๋ฅผ ๋ด…๋‹ˆ๋‹ค.
  3. ํ‘ธ์•ต์นด๋ ˆ ๋‹จ๋ฉด: ์ฃผ๊ธฐ ๊ถค๋„์˜ ๊ฒฝ์šฐ, ์œ„์ƒ ๊ณต๊ฐ„(์˜ˆ: $x=0$ ๊ต์ฐจ์ ์—์„œ $v_\parallel$ ๋Œ€ $z$)์„ ํ”Œ๋กฏํ•ฉ๋‹ˆ๋‹ค.
  4. ์ƒ๋Œ€๋ก ์  ์ž…์ž: ์ƒ๋Œ€๋ก ์  ์—๋„ˆ์ง€๋กœ ํ™•์žฅํ•˜๊ณ  ๋น„์ƒ๋Œ€๋ก ์ ๊ณผ ๋น„๊ตํ•ฉ๋‹ˆ๋‹ค.
  5. ํ†ต๊ณ„ ์•™์ƒ๋ธ”: ์„œ๋กœ ๋‹ค๋ฅธ ์ดˆ๊ธฐ ์กฐ๊ฑด์œผ๋กœ ๋งŽ์€ ์ž…์ž๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ํ‘œ๋ฅ˜ ํ†ต๊ณ„๋ฅผ ๊ณ„์‚ฐํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ 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 ํ™•์žฅ

  1. ๋น„์Šค๋“ฌํ•œ ์ „ํŒŒ: $\theta$๋ฅผ 0์—์„œ $\pi/2$๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  $\omega(k, \theta)$๋ฅผ 3D ํ‘œ๋ฉด์œผ๋กœ ํ”Œ๋กฏํ•ฉ๋‹ˆ๋‹ค.
  2. ์˜จ๋‚œ ํ”Œ๋ผ์ฆˆ๋งˆ: ์—ด ๋ณด์ • ์ถ”๊ฐ€(๋ด„-๊ทธ๋กœ์Šค: $\omega^2 = \omega_{pe}^2 + 3k^2 v_{te}^2$).
  3. ์ด์˜จ ์Œํ–ฅํŒŒ: ์ด์˜จ ์‘๋‹ต ํฌํ•จ, ๋ž€๋‹ค์šฐ ๊ฐ์‡ ์™€ ํ•จ๊ป˜ IA ๋ถ„์‚ฐ ํ”Œ๋กฏ.
  4. CMA ๋‹ค์ด์–ด๊ทธ๋žจ: $(X, Y)$ ๊ณต๊ฐ„์—์„œ ์ „ํŒŒ/๊ฐ์‡  ์˜์—ญ ํ”Œ๋กฏ ($X = \omega_{pe}^2/\omega^2$, $Y = \omega_{ce}/\omega$).
  5. ๊ณต๋ช… ์›๋ฟ”: ํœ˜์Šฌ๋ŸฌํŒŒ์˜ ๊ฒฝ์šฐ, ์ฃผํŒŒ์ˆ˜ ๋Œ€ ๊ณต๋ช… ์›๋ฟ” ๊ฐ๋„ ํ”Œ๋กฏ.

ํ”„๋กœ์ ํŠธ 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}$.

๋ถ„ํ•  ๋ฐฉ๋ฒ•: ๋ธ”๋ผ์†Œํ”„ ๋ฐฉ์ •์‹์„ ๋‘ ๋‹จ๊ณ„๋กœ ๋ถ„ํ• :

  1. x์—์„œ ์ด๋ฅ˜(์ž์œ  ํ๋ฆ„): $$\frac{\partial f}{\partial t} + v \frac{\partial f}{\partial x} = 0$$

  2. 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 ํ™•์žฅ

  1. ๊ณ ์ฐจ ๋ณด๊ฐ„: ๋” ๋‚˜์€ ์ •ํ™•๋„๋ฅผ ์œ„ํ•ด 3์ฐจ ๋˜๋Š” 5์ฐจ ์Šคํ”Œ๋ผ์ธ ์‚ฌ์šฉ.
  2. ์Œ๋ฅ˜ ๋ถˆ์•ˆ์ •์„ฑ: ์ดˆ๊ธฐ ์กฐ๊ฑด ์ˆ˜์ •, ์„ฑ์žฅ๋ฅ  ์ธก์ •, ์ด๋ก ๊ณผ ๋น„๊ต.
  3. ๋ฒ”ํ”„-์˜จ-ํ…Œ์ผ: ํ‰ํƒ„ํ™” ๊ด€์ธก, ํŒŒ๋™ ์—๋„ˆ์ง€ ํฌํ™” ์ธก์ •.
  4. ์ „์ž ํฌํš: ํฌํš๋œ ์ž…์ž์— ์˜ํ•ด ํ˜•์„ฑ๋œ ์œ„์ƒ ๊ณต๊ฐ„ ์†Œ์šฉ๋Œ์ด ํ”Œ๋กฏ.
  5. 2D ๋ธ”๋ผ์†Œํ”„: 2D-2V๋กœ ํ™•์žฅ(๊ณ„์‚ฐ ์ง‘์•ฝ์ !).
  6. PIC ๋น„๊ต: ๊ฐ„๋‹จํ•œ 1D PIC ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ๋ธ”๋ผ์†Œํ”„์™€ ๋น„๊ต.

๊ฒฐ๋ก 

์ด ์„ธ ํ”„๋กœ์ ํŠธ๋Š” ์ „์ฒด ๊ฐ•์ขŒ์˜ ์ž๋ฃŒ๋ฅผ ์ข…ํ•ฉํ•ฉ๋‹ˆ๋‹ค:

  • ํ”„๋กœ์ ํŠธ 1(์ž…์ž ๊ถค๋„)์€ ๋ ˆ์Šจ 3โ€“4์˜ ๋‹จ์ผ ์ž…์ž ์ด๋ก ์„ ์‹คํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ํ”„๋กœ์ ํŠธ 2(๋ถ„์‚ฐ ํ•ด๊ฒฐ๊ธฐ)๋Š” ๋ ˆ์Šจ 9โ€“10์˜ ํŒŒ๋™ ์ด๋ก ์„ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
  • ํ”„๋กœ์ ํŠธ 3(๋ธ”๋ผ์†Œํ”„-ํ‘ธ์•„์†ก)์€ ๋ ˆ์Šจ 6โ€“8์˜ ์šด๋™ ์ด๋ก ์„ ๋‹ค๋ฃจ๊ณ  ๋ž€๋‹ค์šฐ ๊ฐ์‡ ์™€ ๊ฐ™์€ ๊ธฐ๋ณธ ํ”Œ๋ผ์ฆˆ๋งˆ ํ˜„์ƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ์™„๋ฃŒํ•˜๋ฉด ํ˜„๋Œ€ ํ”Œ๋ผ์ฆˆ๋งˆ ๋ฌผ๋ฆฌ ์—ฐ๊ตฌ์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ณ„์‚ฐ ๋„๊ตฌ์— ๋Œ€ํ•œ ์‹ค๋ฌด ๊ฒฝํ—˜์„ ๊ฐ–๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์€ ๋‹ค์Œ์œผ๋กœ ํ™•์žฅ๋ฉ๋‹ˆ๋‹ค:

  • ์ž…์ž-์…€(PIC) ์ฝ”๋“œ: ๋ฌด์ถฉ๋Œ ํ”Œ๋ผ์ฆˆ๋งˆ ์‹œ๋ฎฌ๋ ˆ์ด์…˜(์˜ˆ: ๋ ˆ์ด์ €-ํ”Œ๋ผ์ฆˆ๋งˆ ์ƒํ˜ธ์ž‘์šฉ, ์šฐ์ฃผ ๋ฌผ๋ฆฌ)
  • ์ž์ด๋กœ์šด๋™๋ก  ์ฝ”๋“œ: ํ† ์นด๋ง‰ ๋‚œ๋ฅ˜(์˜ˆ: GENE, GYRO, GS2)
  • MHD ์ฝ”๋“œ: ํ•ต์œตํ•ฉ ํ‰ํ˜• ๋ฐ ์•ˆ์ •์„ฑ(์˜ˆ: NIMROD, M3D-C1)

ํ”Œ๋ผ์ฆˆ๋งˆ ๋ฌผ๋ฆฌ ๊ณผ์ •์„ ์™„๋ฃŒํ•˜์‹  ๊ฒƒ์„ ์ถ•ํ•˜ํ•ฉ๋‹ˆ๋‹ค! ์ด์ œ ํ”Œ๋ผ์ฆˆ๋งˆ ๋ฌผ๋ฆฌ์˜ ์ด๋ก ๊ณผ ๊ณ„์‚ฐ ๋ชจ๋‘์— ๋Œ€ํ•œ ๊ฒฌ๊ณ ํ•œ ๊ธฐ์ดˆ๋ฅผ ๊ฐ–์ถ”์…จ์Šต๋‹ˆ๋‹ค.


์ด์ „: ํ”Œ๋ผ์ฆˆ๋งˆ ์ง„๋‹จ | ๋‹ค์Œ: ์—†์Œ(๋งˆ์ง€๋ง‰ ๋ ˆ์Šจ)

to navigate between lessons