File size: 4,855 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 133 134 135 136 137 138 139 140 141 | """
Climate Kernel (๊ธฐํ ์ปค๋)
๊ธฐํ ์กฐ๊ฑด์ ๋ฐ๋ฅธ ๊ฐ์/๊ธฐ์จ ๋ถํฌ ์์ฑ
- ์๋ ๊ธฐ๋ฐ ๊ฐ์ ํจํด
- ๊ณ ๋ ๊ธฐ๋ฐ ์งํ์ฑ ๊ฐ์
- ๊ธฐ์จ์ ๋ฐ๋ฅธ ํํ์จ ์กฐ์
"""
import numpy as np
from .grid import WorldGrid
class ClimateKernel:
"""
๊ธฐํ ์ปค๋
๊ฐ์์ ๊ธฐ์จ ๋ถํฌ๋ฅผ ์์ฑํ์ฌ ๋ค๋ฅธ ํ๋ก์ธ์ค์ ์ํฅ.
"""
def __init__(self, grid: WorldGrid,
base_precipitation: float = 1000.0, # mm/year
base_temperature: float = 15.0, # ยฐC
lapse_rate: float = 6.5): # ยฐC/km (๊ณ ๋ ๊ฐ๋ฅ )
self.grid = grid
self.base_precipitation = base_precipitation
self.base_temperature = base_temperature
self.lapse_rate = lapse_rate
def generate_precipitation(self,
orographic_factor: float = 0.5,
latitude_effect: bool = True) -> np.ndarray:
"""
๊ฐ์ ๋ถํฌ ์์ฑ
Args:
orographic_factor: ์งํ์ฑ ๊ฐ์ ๊ฐ๋ (0~1)
latitude_effect: ์๋ ํจ๊ณผ ์ ์ฉ ์ฌ๋ถ
Returns:
precipitation: ๊ฐ์๋ ๋ฐฐ์ด (mm/year โ m/timestep์ผ๋ก ๋ณํ ํ์)
"""
h, w = self.grid.height, self.grid.width
elev = self.grid.elevation
# ๊ธฐ๋ณธ ๊ฐ์ (๊ท ์ผ)
precip = np.ones((h, w)) * self.base_precipitation
# 1. ์๋ ํจ๊ณผ (์ ๋ > ๊ทน์ง๋ฐฉ)
if latitude_effect:
# ๊ทธ๋ฆฌ๋ Y์ถ์ ์๋๋ก ๊ทผ์ฌ (0=์ ๋, h=๊ทน)
# ์ด๋ = ๊ฐ์ฅ ๋ง์, ์์ด๋ ๊ฑด์กฐ, ์จ๋ ์ฆ๊ฐ, ๊ทน ๊ฐ์
lat_factor = np.zeros(h)
for r in range(h):
# ์ ๊ทํ๋ ์๋ (0~1)
normalized_lat = r / h
# ๊ฐ๋จํ ์๋-๊ฐ์ ๊ด๊ณ (์ผ๋ด ํจํด ๊ทผ์ฌ)
lat_factor[r] = 1.0 - 0.3 * abs(normalized_lat - 0.5) * 2
precip *= lat_factor[:, np.newaxis]
# 2. ์งํ์ฑ ๊ฐ์ (๋ฐ๋๋ฐ์ด vs ๊ทธ๋)
if orographic_factor > 0:
# ๋์ชฝ์์ ๋ฐ๋์ด ๋ถ๋ค๊ณ ๊ฐ์
# ๊ณ ๋ ์ฆ๊ฐ ๊ตฌ๊ฐ = ๊ฐ์ ์ฆ๊ฐ (์์น ๊ธฐ๋ฅ)
# ๊ณ ๋ ๊ฐ์ ๊ตฌ๊ฐ = ๊ฐ์ ๊ฐ์ (ํ๊ฐ ๊ธฐ๋ฅ)
# X ๋ฐฉํฅ ๊ฒฝ์ฌ
_, dx = self.grid.get_gradient()
# ์์ ๊ฒฝ์ฌ = ๋์ชฝ์ผ๋ก ์์น = ๊ฐ์ ์ฆ๊ฐ
orographic = 1.0 + orographic_factor * (-dx) * 0.1
orographic = np.clip(orographic, 0.2, 2.0)
precip *= orographic
# 3. ๊ณ ๋ ํจ๊ณผ (์ผ์ ๊ณ ๋๊น์ง๋ ์ฆ๊ฐ, ์ดํ ๊ฐ์)
# ์ต๋ ๊ฐ์ ๊ณ ๋ (์: 2000m)
optimal_elev = 2000.0
elev_effect = 1.0 - 0.2 * np.abs(elev - optimal_elev) / optimal_elev
elev_effect = np.clip(elev_effect, 0.3, 1.2)
precip *= elev_effect
return precip
def get_temperature(self) -> np.ndarray:
"""
๊ธฐ์จ ๋ถํฌ ์์ฑ
Returns:
temperature: ๊ธฐ์จ ๋ฐฐ์ด (ยฐC)
"""
h, w = self.grid.height, self.grid.width
elev = self.grid.elevation
# ๊ธฐ๋ณธ ๊ธฐ์จ
temp = np.ones((h, w)) * self.base_temperature
# 1. ์๋ ํจ๊ณผ (์ ๋ > ๊ทน)
for r in range(h):
normalized_lat = r / h
# ์ ๋(0.5) = ๊ธฐ๋ณธ, ๊ทน(0, 1) = -30ยฐC
lat_temp_diff = 30.0 * abs(normalized_lat - 0.5) * 2
temp[r, :] -= lat_temp_diff
# 2. ๊ณ ๋ ํจ๊ณผ (์ฒด๊ฐ ์จ๋ ๊ฐ๋ฅ )
# ํด์๋ฉด ๊ธฐ์ค์์ km๋น lapse_rate๋งํผ ๊ฐ์
temp -= (elev / 1000.0) * self.lapse_rate
return temp
def get_weathering_rate(self, temperature: np.ndarray = None) -> np.ndarray:
"""
๊ธฐ์จ์ ๋ฐ๋ฅธ ํํ์จ ๊ณ์ฐ
ํํ์ ํํ: ์จ๋ ๋ค์ต โ ๋น ๋ฆ
๋ฌผ๋ฆฌ์ ํํ: ๋๊ฒฐ-์ตํด (-10~10ยฐC) โ ๋น ๋ฆ
Args:
temperature: ๊ธฐ์จ ๋ฐฐ์ด (์์ผ๋ฉด ์์ฑ)
Returns:
weathering_rate: ์๋ ํํ์จ (0~1)
"""
if temperature is None:
temperature = self.get_temperature()
h, w = self.grid.height, self.grid.width
# ํํ์ ํํ (์จ๋ ๋์์๋ก)
chemical = np.clip((temperature + 10) / 40.0, 0, 1)
# ๋ฌผ๋ฆฌ์ ํํ (๋๊ฒฐ-์ตํด ๋ฒ์์์ ์ต๋)
freeze_thaw = np.exp(-((temperature - 0) ** 2) / (2 * 10 ** 2))
# ํตํฉ ํํ์จ
weathering = chemical * 0.5 + freeze_thaw * 0.5
return weathering
|