Geo-Lab / engine /precompute.py
HANSOL
Geo-Lab v4.1 - Clean deployment
2afa69c
"""
Geo-Lab AI: ํ”„๋ฆฌ์ปดํ“จํŒ… + ์บ์‹ฑ ์‹œ์Šคํ…œ
์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ๋ฏธ๋ฆฌ ๋Œ๋ ค๋†“๊ณ  ์Šฌ๋ผ์ด๋”๋กœ ํƒ์ƒ‰
"""
import numpy as np
import pickle
import hashlib
import os
from pathlib import Path
from typing import Dict, Any, Optional, Callable
import threading
from concurrent.futures import ThreadPoolExecutor
class PrecomputeCache:
"""ํ”„๋ฆฌ์ปดํ“จํŒ… ๊ฒฐ๊ณผ ์บ์‹œ"""
def __init__(self, cache_dir: str = None):
if cache_dir is None:
cache_dir = Path(__file__).parent.parent / "cache"
self.cache_dir = Path(cache_dir)
self.cache_dir.mkdir(exist_ok=True)
# ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ
self.memory_cache: Dict[str, Any] = {}
def _get_key(self, sim_type: str, params: dict) -> str:
"""ํŒŒ๋ผ๋ฏธํ„ฐ ๊ธฐ๋ฐ˜ ์บ์‹œ ํ‚ค ์ƒ์„ฑ"""
param_str = f"{sim_type}_{sorted(params.items())}"
return hashlib.md5(param_str.encode()).hexdigest()[:16]
def get(self, sim_type: str, params: dict) -> Optional[Any]:
"""์บ์‹œ์—์„œ ์กฐํšŒ"""
key = self._get_key(sim_type, params)
# ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ ํ™•์ธ
if key in self.memory_cache:
return self.memory_cache[key]
# ๋””์Šคํฌ ์บ์‹œ ํ™•์ธ
cache_file = self.cache_dir / f"{key}.pkl"
if cache_file.exists():
try:
with open(cache_file, 'rb') as f:
data = pickle.load(f)
self.memory_cache[key] = data
return data
except:
pass
return None
def set(self, sim_type: str, params: dict, data: Any):
"""์บ์‹œ์— ์ €์žฅ"""
key = self._get_key(sim_type, params)
# ๋ฉ”๋ชจ๋ฆฌ ์บ์‹œ
self.memory_cache[key] = data
# ๋””์Šคํฌ ์บ์‹œ
cache_file = self.cache_dir / f"{key}.pkl"
try:
with open(cache_file, 'wb') as f:
pickle.dump(data, f)
except:
pass
def get_or_compute(self, sim_type: str, params: dict,
compute_fn: Callable, force_recompute: bool = False) -> Any:
"""์บ์‹œ ๋˜๋Š” ๊ณ„์‚ฐ"""
if not force_recompute:
cached = self.get(sim_type, params)
if cached is not None:
return cached
# ๊ณ„์‚ฐ
result = compute_fn()
self.set(sim_type, params, result)
return result
class SimulationManager:
"""์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๋งค๋‹ˆ์ €
ํŒŒ๋ผ๋ฏธํ„ฐ๋ณ„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ํ”„๋ฆฌ์ปดํ“จํŒ…ํ•˜๊ณ 
UI์—์„œ๋Š” ์บ์‹œ๋œ ๊ฒฐ๊ณผ๋ฅผ ์กฐํšŒ
"""
def __init__(self):
self.cache = PrecomputeCache()
self.executor = ThreadPoolExecutor(max_workers=2)
self.computing: Dict[str, bool] = {}
def get_v_valley(self, rock_hardness: float = 0.5,
K: float = 1e-5,
max_time: int = 10000) -> Dict:
"""V์ž๊ณก ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ"""
from engine.physics_engine import VValleySimulation
# ํŒŒ๋ผ๋ฏธํ„ฐ ์–‘์žํ™” (์บ์‹œ ํšจ์œจ)
rock_hardness = round(rock_hardness, 1)
K = round(K, 6)
params = {
'rock_hardness': rock_hardness,
'K': K,
'max_time': max_time
}
def compute():
sim = VValleySimulation(width=100, height=100)
sim.erosion.K = K
sim.initialize_terrain(rock_hardness=rock_hardness)
history = sim.run(max_time, save_interval=max_time // 100)
# ๊ฐ ์Šค๋ƒ…์ƒท์˜ ๋‹จ๋ฉด๊ณผ ๊นŠ์ด ์ €์žฅ
cross_sections = []
depths = []
for elev in history:
temp_sim = VValleySimulation()
temp_sim.terrain.elevation = elev
x, z = temp_sim.get_cross_section()
depth = temp_sim.measure_valley_depth()
cross_sections.append((x, z))
depths.append(depth)
return {
'history': history,
'cross_sections': cross_sections,
'depths': depths,
'n_frames': len(history)
}
return self.cache.get_or_compute('v_valley', params, compute)
def get_meander(self, initial_sinuosity: float = 1.3,
max_time: int = 10000) -> Dict:
"""๊ณก๋ฅ˜ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ"""
from engine.meander_physics import MeanderSimulation
initial_sinuosity = round(initial_sinuosity, 1)
params = {
'initial_sinuosity': initial_sinuosity,
'max_time': max_time
}
def compute():
sim = MeanderSimulation(initial_sinuosity=initial_sinuosity)
history = sim.run(max_time, save_interval=max_time // 100)
# ๊ตด๊ณก๋„ ํžˆ์Šคํ† ๋ฆฌ
sinuosities = []
for x, y in history:
temp_channel = type(sim.channel)(x=x, y=y)
sinuosities.append(temp_channel.calculate_sinuosity())
return {
'history': history,
'oxbow_lakes': sim.oxbow_lakes,
'sinuosities': sinuosities,
'n_frames': len(history)
}
return self.cache.get_or_compute('meander', params, compute)
def get_delta(self, river_energy: float = 60,
wave_energy: float = 25,
tidal_energy: float = 15,
max_time: int = 10000) -> Dict:
"""์‚ผ๊ฐ์ฃผ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฒฐ๊ณผ"""
from engine.delta_physics import DeltaSimulation
# ์ •๊ทœํ™”
total = river_energy + wave_energy + tidal_energy + 0.01
river_energy = round(river_energy / total, 2)
wave_energy = round(wave_energy / total, 2)
tidal_energy = round(tidal_energy / total, 2)
params = {
'river_energy': river_energy,
'wave_energy': wave_energy,
'tidal_energy': tidal_energy,
'max_time': max_time
}
def compute():
sim = DeltaSimulation()
sim.set_energy_balance(river_energy, wave_energy, tidal_energy)
history = sim.run(max_time, save_interval=max_time // 100)
return {
'history': history,
'delta_type': sim.get_delta_type().value,
'delta_area': sim.get_delta_area(),
'n_frames': len(history)
}
return self.cache.get_or_compute('delta', params, compute)
def precompute_common_scenarios(self):
"""์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค ๋ฏธ๋ฆฌ ๊ณ„์‚ฐ"""
scenarios = [
# V์ž๊ณก
{'type': 'v_valley', 'rock_hardness': 0.3, 'K': 1e-5},
{'type': 'v_valley', 'rock_hardness': 0.5, 'K': 1e-5},
{'type': 'v_valley', 'rock_hardness': 0.7, 'K': 1e-5},
# ๊ณก๋ฅ˜
{'type': 'meander', 'initial_sinuosity': 1.2},
{'type': 'meander', 'initial_sinuosity': 1.5},
# ์‚ผ๊ฐ์ฃผ
{'type': 'delta', 'river': 0.7, 'wave': 0.2, 'tidal': 0.1},
{'type': 'delta', 'river': 0.3, 'wave': 0.5, 'tidal': 0.2},
{'type': 'delta', 'river': 0.2, 'wave': 0.2, 'tidal': 0.6},
]
for scenario in scenarios:
if scenario['type'] == 'v_valley':
self.executor.submit(
self.get_v_valley,
rock_hardness=scenario['rock_hardness'],
K=scenario['K']
)
elif scenario['type'] == 'meander':
self.executor.submit(
self.get_meander,
initial_sinuosity=scenario['initial_sinuosity']
)
elif scenario['type'] == 'delta':
self.executor.submit(
self.get_delta,
river_energy=scenario['river'],
wave_energy=scenario['wave'],
tidal_energy=scenario['tidal']
)
# ๊ธ€๋กœ๋ฒŒ ์ธ์Šคํ„ด์Šค
_manager = None
def get_simulation_manager() -> SimulationManager:
global _manager
if _manager is None:
_manager = SimulationManager()
return _manager