File size: 5,307 Bytes
2afa69c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import numpy as np
from dataclasses import dataclass
from .grid import WorldGrid
from .fluids import HydroKernel
from .erosion_process import ErosionProcess
from .lateral_erosion import LateralErosionKernel
from .mass_movement import MassMovementKernel
from .climate import ClimateKernel
from .wave import WaveKernel
from .glacier import GlacierKernel
from .wind import WindKernel

class EarthSystem:
    """
    Project Genesis: Unified Earth System Engine
    
    ํ†ตํ•ฉ ์ง€๊ตฌ ์‹œ์Šคํ…œ ์—”์ง„
    - ๊ธฐํ›„(Climate) -> ์ˆ˜๋ฌธ(Hydro) -> ์ง€ํ˜•(Erosion/Tectonics) ์ƒํ˜ธ์ž‘์šฉ์„
      ๋‹จ์ผ ๋ฃจํ”„(step) ๋‚ด์—์„œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
    """
    def __init__(self, grid: WorldGrid):
        self.grid = grid
        self.time = 0.0
        
        # Core Kernels
        self.hydro = HydroKernel(self.grid)
        self.erosion = ErosionProcess(self.grid)
        self.lateral = LateralErosionKernel(self.grid, k=0.01)
        self.mass_movement = MassMovementKernel(self.grid, friction_angle=35.0)
        self.climate = ClimateKernel(self.grid)
        
        # Phase 2 Kernels (Optional, enabled via settings)
        self.wave = WaveKernel(self.grid)
        self.glacier = GlacierKernel(self.grid)
        self.wind = WindKernel(self.grid)
        
        # State History (Optional for analysis)
        self.history = []

    def step(self, dt: float = 1.0, settings: dict = None):
        """
        ์‹œ์Šคํ…œ 1๋‹จ๊ณ„ ์ง„ํ–‰ (Time Step)
        
        Process Chain:
        1. Tectonics (Endogenous): Uplift, subsidence based on scenario settings
        2. Climate (Exogenous): Generate precipitation
        3. Hydro (Physics): Route flow, calculate discharge/depth
        4. Morphodynamics (Response): Erode, transport, deposit
        """
        if settings is None:
            settings = {}
            
        # 1. Tectonics (์ง€๊ตฌ์กฐ ์šด๋™)
        # Simple vertical uplift logic if provided
        uplift_rate = settings.get('uplift_rate', 0.0)
        tile_uplift = settings.get('uplift_mask', None)
        
        if uplift_rate > 0:
            if tile_uplift is not None:
                self.grid.apply_uplift(tile_uplift * uplift_rate, dt)
            else:
                self.grid.apply_uplift(uplift_rate, dt)
                
        # 2. Climate (๊ธฐํ›„)
        # Generate precipitation map
        # Default: Uniform rain + randomness
        base_precip = settings.get('precipitation', 0.01)
        precip_map = np.ones((self.grid.height, self.grid.width)) * base_precip
        
        # Apply rain source if specified (e.g., river mouth)
        rain_source = settings.get('rain_source', None) # (y, x, radius, amount)
        if rain_source:
             y, x, r, amount = rain_source
             # Simplified box source for speed
             y_min, y_max = max(0, int(y-r)), min(self.grid.height, int(y+r+1))
             x_min, x_max = max(0, int(x-r)), min(self.grid.width, int(x+r+1))
             precip_map[y_min:y_max, x_min:x_max] += amount
        
        # 3. Hydro (์ˆ˜๋ฌธ)
        # Route flow based on current topography + precip
        discharge = self.hydro.route_flow_d8(precipitation=precip_map)
        
        # Update grid state
        self.grid.discharge = discharge
        self.grid.water_depth = self.hydro.calculate_water_depth(discharge)
        
        # 4. Erosion / Deposition (์ง€ํ˜• ๋ณ€ํ™”)
        # Using the ErosionKernel (ErosionProcess wrapper)
        # Need to update K, m, n parameters dynamically?
        # For now, use instance defaults or allow overrides
        
        # Execute Transport & Deposition
        sediment_influx_map = None
        sediment_source = settings.get('sediment_source', None) # (y, x, radius, amount)
        if sediment_source:
             y, x, r, amount = sediment_source
             sediment_influx_map = np.zeros((self.grid.height, self.grid.width))
             y_min, y_max = max(0, int(y-r)), min(self.grid.height, int(y+r+1))
             x_min, x_max = max(0, int(x-r)), min(self.grid.width, int(x+r+1))
             sediment_influx_map[y_min:y_max, x_min:x_max] += amount
             
        self.erosion.simulate_transport(discharge, dt=dt, sediment_influx_map=sediment_influx_map)
        
        # 5. Lateral Erosion (์ธก๋ฐฉ ์นจ์‹) - ๊ณก๋ฅ˜ ํ˜•์„ฑ
        lateral_enabled = settings.get('lateral_erosion', True)
        if lateral_enabled:
            self.lateral.step(discharge, dt=dt)
        
        # 6. Hillslope Diffusion (์‚ฌ๋ฉด ์•ˆ์ •ํ™”)
        diff_rate = settings.get('diffusion_rate', 0.01)
        if diff_rate > 0:
            self.erosion.hillslope_diffusion(dt=dt * diff_rate)
        
        # 7. Mass Movement (๋งค์Šค๋ฌด๋ธŒ๋จผํŠธ) - ์‚ฐ์‚ฌํƒœ
        mass_movement_enabled = settings.get('mass_movement', True)
        if mass_movement_enabled:
            self.mass_movement.step(dt=dt)
            
        # Update Time
        self.time += dt
        
    def get_state(self):
        """ํ˜„์žฌ ์‹œ์Šคํ…œ ์ƒํƒœ ๋ฐ˜ํ™˜"""
        self.grid.update_elevation()
        return {
            'elevation': self.grid.elevation.copy(),
            'water_depth': self.grid.water_depth.copy(),
            'discharge': self.grid.discharge.copy(),
            'sediment': self.grid.sediment.copy(),
            'time': self.time
        }