| """ |
| Wave Kernel (ํ๋ ์ปค๋) |
| |
| ํด์ ์งํ ํ์ฑ ํ๋ก์ธ์ค |
| - ํ๋ ์นจ์ (Wave Erosion): ํด์์ ๋ฒฝ ํํด |
| - ์ฐ์ ํด์ (Coastal Deposition): ์ฌ์ฃผ, ์ฌ์ทจ ํ์ฑ |
| - ์ฐ์๋ฅ (Longshore Drift): ์ธก๋ฐฉ ํด์ ๋ฌผ ์ด๋ |
| |
| ํต์ฌ ๊ณต์: |
| ์นจ์๋ฅ E = K * H^2 * (1/R) |
| - H: ํ๊ณ (Wave Height) |
| - R: ์์ ์ ํญ๋ ฅ (Rock Resistance) |
| """ |
|
|
| import numpy as np |
| from .grid import WorldGrid |
|
|
|
|
| class WaveKernel: |
| """ |
| ํ๋ ์ปค๋ |
| |
| ํด์์ ์์์ ํ๋ ์์ฉ์ ์๋ฎฌ๋ ์ด์
. |
| ์นจ์๊ณผ ํด์ ์ ๋์์ ์ฒ๋ฆฌ. |
| """ |
| |
| def __init__(self, grid: WorldGrid, |
| wave_height: float = 2.0, |
| wave_period: float = 8.0, |
| wave_direction: float = 0.0, |
| K_erosion: float = 0.001): |
| self.grid = grid |
| self.wave_height = wave_height |
| self.wave_period = wave_period |
| self.wave_direction = np.radians(wave_direction) |
| self.K = K_erosion |
| |
| def identify_coastline(self) -> np.ndarray: |
| """ |
| ํด์์ ์๋ณ |
| |
| ์ก์ง-๋ฐ๋ค ๊ฒฝ๊ณ์ ์ ์ฐพ์ |
| |
| Returns: |
| coastline_mask: ํด์์ ์
๋ง์คํฌ |
| """ |
| underwater = self.grid.is_underwater() |
| |
| |
| h, w = self.grid.height, self.grid.width |
| coastline = np.zeros((h, w), dtype=bool) |
| |
| for r in range(h): |
| for c in range(w): |
| if underwater[r, c]: |
| continue |
| |
| |
| for dr in [-1, 0, 1]: |
| for dc in [-1, 0, 1]: |
| if dr == 0 and dc == 0: |
| continue |
| nr, nc = r + dr, c + dc |
| if 0 <= nr < h and 0 <= nc < w: |
| if underwater[nr, nc]: |
| coastline[r, c] = True |
| break |
| if coastline[r, c]: |
| break |
| |
| return coastline |
| |
| def calculate_wave_energy(self) -> np.ndarray: |
| """ |
| ํ๋ ์๋์ง ๋ถํฌ ๊ณ์ฐ |
| |
| Returns: |
| energy: ๊ฐ ์
์ ํ๋ ์๋์ง |
| """ |
| h, w = self.grid.height, self.grid.width |
| |
| |
| base_energy = self.wave_height ** 2 |
| |
| |
| |
| sea_depth = np.maximum(0, self.grid.sea_level - self.grid.elevation) |
| |
| |
| wavelength = 1.56 * (self.wave_period ** 2) |
| depth_factor = np.ones((h, w)) |
| |
| shallow = sea_depth < wavelength / 2 |
| depth_factor[shallow] = 1.0 + 0.5 * (1 - sea_depth[shallow] / (wavelength / 2)) |
| |
| energy = base_energy * depth_factor |
| |
| |
| energy[~self.grid.is_underwater()] = 0 |
| |
| return energy |
| |
| def erode_coast(self, coastline: np.ndarray, |
| wave_energy: np.ndarray, |
| rock_resistance: np.ndarray = None, |
| dt: float = 1.0) -> np.ndarray: |
| """ |
| ํด์ ์นจ์ |
| |
| Args: |
| coastline: ํด์์ ๋ง์คํฌ |
| wave_energy: ํ๋ ์๋์ง ๋ฐฐ์ด |
| rock_resistance: ์์ ์ ํญ๋ ฅ (0~1, ๋์์๋ก ์ ํญ) |
| dt: ์๊ฐ ๊ฐ๊ฒฉ |
| |
| Returns: |
| erosion: ์นจ์๋ ๋ฐฐ์ด |
| """ |
| h, w = self.grid.height, self.grid.width |
| |
| if rock_resistance is None: |
| rock_resistance = np.ones((h, w)) * 0.5 |
| |
| erosion = np.zeros((h, w), dtype=np.float64) |
| |
| |
| coast_coords = np.argwhere(coastline) |
| |
| for r, c in coast_coords: |
| |
| adjacent_energy = 0 |
| count = 0 |
| |
| for dr in [-1, 0, 1]: |
| for dc in [-1, 0, 1]: |
| if dr == 0 and dc == 0: |
| continue |
| nr, nc = r + dr, c + dc |
| if 0 <= nr < h and 0 <= nc < w: |
| if self.grid.is_underwater()[nr, nc]: |
| adjacent_energy += wave_energy[nr, nc] |
| count += 1 |
| |
| if count > 0: |
| avg_energy = adjacent_energy / count |
| |
| resistance = rock_resistance[r, c] |
| erosion[r, c] = self.K * avg_energy * (1 - resistance) * dt |
| |
| return erosion |
| |
| def longshore_drift(self, coastline: np.ndarray, |
| sediment_available: np.ndarray, |
| dt: float = 1.0) -> np.ndarray: |
| """ |
| ์ฐ์๋ฅ์ ์ํ ํด์ ๋ฌผ ์ด๋ |
| |
| Args: |
| coastline: ํด์์ ๋ง์คํฌ |
| sediment_available: ์ด๋ ๊ฐ๋ฅํ ํด์ ๋ฌผ |
| dt: ์๊ฐ ๊ฐ๊ฒฉ |
| |
| Returns: |
| change: ํด์ ๋ฌผ ๋ณํ๋ |
| """ |
| h, w = self.grid.height, self.grid.width |
| change = np.zeros((h, w), dtype=np.float64) |
| |
| |
| |
| drift_dx = np.sin(self.wave_direction) |
| drift_dy = -np.cos(self.wave_direction) |
| |
| coast_coords = np.argwhere(coastline) |
| |
| for r, c in coast_coords: |
| available = sediment_available[r, c] |
| if available <= 0: |
| continue |
| |
| |
| move_amount = min(available * 0.1 * dt, available) |
| |
| |
| tr = int(r + drift_dy) |
| tc = int(c + drift_dx) |
| |
| if 0 <= tr < h and 0 <= tc < w: |
| if coastline[tr, tc] or self.grid.is_underwater()[tr, tc]: |
| change[r, c] -= move_amount |
| change[tr, tc] += move_amount |
| |
| return change |
| |
| def step(self, dt: float = 1.0, |
| rock_resistance: np.ndarray = None) -> dict: |
| """ |
| 1๋จ๊ณ ํ๋ ์์ฉ ์คํ |
| |
| Args: |
| dt: ์๊ฐ ๊ฐ๊ฒฉ |
| rock_resistance: ์์ ์ ํญ๋ ฅ ๋ฐฐ์ด |
| |
| Returns: |
| result: ์นจ์/ํด์ ๊ฒฐ๊ณผ |
| """ |
| |
| coastline = self.identify_coastline() |
| |
| if not np.any(coastline): |
| return {'erosion': np.zeros_like(self.grid.elevation), |
| 'drift': np.zeros_like(self.grid.elevation)} |
| |
| |
| wave_energy = self.calculate_wave_energy() |
| |
| |
| erosion = self.erode_coast(coastline, wave_energy, rock_resistance, dt) |
| |
| |
| self.grid.bedrock -= erosion |
| |
| |
| self.grid.sediment += erosion * 0.8 |
| |
| |
| drift = self.longshore_drift(coastline, self.grid.sediment, dt) |
| self.grid.sediment += drift |
| |
| |
| self.grid.update_elevation() |
| |
| return { |
| 'erosion': erosion, |
| 'drift': drift |
| } |
|
|