From d2ffaad7a381d90c64af711ddd350ea6b811601b Mon Sep 17 00:00:00 2001 From: wzy-warehouse <18135009705@163.com> Date: Sat, 30 May 2026 15:03:39 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=AF=E5=8A=A8=E5=89=8D?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/core/launcher.py | 7 +-- app/core/rainfall_manager.py | 15 +++--- app/services/rainfall_grid_service.py | 70 +++++++++++++++------------ start.py | 4 +- 4 files changed, 54 insertions(+), 42 deletions(-) diff --git a/app/core/launcher.py b/app/core/launcher.py index e979cca..8503674 100644 --- a/app/core/launcher.py +++ b/app/core/launcher.py @@ -9,7 +9,6 @@ from app.core.venv_manager import check_virtualenv from app.core.dependency_manager import check_dependencies from app.utils.logger import get_logger from app.utils.thread_pool_manager import block_main_thread, thread_pool_manager -from app.core.rainfall_manager import rainfall_manager class AppLauncher: @@ -52,11 +51,13 @@ class AppLauncher: def start(): """启动应用服务""" + from app.core.rainfall_manager import rainfall_manager + logger = get_logger() - + # 启动降雨站点监测 logger.info("启动降雨站点监测服务...") rainfall_manager.monitoring_rainfall_station_id('2025-09-16 20:00:00') - + # 阻塞主线程,防止程序立即退出 block_main_thread() diff --git a/app/core/rainfall_manager.py b/app/core/rainfall_manager.py index 0faa6d5..36a033f 100644 --- a/app/core/rainfall_manager.py +++ b/app/core/rainfall_manager.py @@ -8,8 +8,6 @@ from typing import Optional from app.utils import thread_pool_manager from app.utils.logger import get_logger -from app.repositories.rainfall_repository import rainfall_repository -from app.services.rainfall_grid_service import rainfall_grid_service class RainfallManager: @@ -42,12 +40,14 @@ class RainfallManager: def _monitoring_loop(self, initial_query_time: datetime): """ 监测循环,定期检查最大ID是否改变 - + Args: initial_query_time: 初始查询时间 """ + from app.repositories.rainfall_repository import rainfall_repository + query_time = initial_query_time - + while True: try: # 查询当前时间窗口内的最大ID @@ -78,14 +78,17 @@ class RainfallManager: def _generate_rainfall_grid_task(self, query_time: datetime, max_id: int): """ 生成降雨栅格的任务函数 - + Args: query_time: 查询时间 max_id: 最大ID """ + from app.repositories.rainfall_repository import rainfall_repository + from app.services.rainfall_grid_service import rainfall_grid_service + try: self.logger.info(f"开始生成降雨栅格,查询时间: {query_time}, ID: {max_id}") - + # 1. 查询雨量站点数据 station_data = rainfall_repository.get_rainfall_stations_data(query_time) diff --git a/app/services/rainfall_grid_service.py b/app/services/rainfall_grid_service.py index 529adfe..f84e06c 100644 --- a/app/services/rainfall_grid_service.py +++ b/app/services/rainfall_grid_service.py @@ -8,17 +8,7 @@ from datetime import datetime from typing import Optional, List, Dict, Any, Tuple from io import BytesIO -import numpy as np -from scipy.spatial import Delaunay, ConvexHull -from scipy.interpolate import griddata -from scipy.ndimage import gaussian_filter -from PIL import Image -import matplotlib.pyplot as plt -from matplotlib.colors import ListedColormap, BoundaryNorm - -from config import settings from app.utils.logger import get_logger -from app.utils.redis_helper import redis_helper class RainfallGridService: @@ -54,16 +44,18 @@ class RainfallGridService: # 栅格分辨率(度) self.grid_resolution = 0.01 # 约1km - def _create_buffer_points(self, points_array: np.ndarray) -> np.ndarray: + def _create_buffer_points(self, points_array) -> 'np.ndarray': """ 创建缓冲点:在原始站点外围生成虚拟点以扩展插值区域 - + Args: points_array: 原始站点坐标数组 - + Returns: 缓冲点坐标数组 """ + import numpy as np + # 计算站点分布的中心 center = np.mean(points_array, axis=0) @@ -89,37 +81,39 @@ class RainfallGridService: def _calculate_adaptive_max_distance( self, - points_array: np.ndarray, + points_array, base_distance: float = 0.3, min_distance: float = 0.15, max_distance: float = 0.5 ) -> float: """ 根据站点密度自适应计算最大影响距离 - + Args: points_array: 站点坐标数组 base_distance: 基础距离 min_distance: 最小距离 max_distance: 最大距离 - + Returns: 自适应的最大影响距离 """ + import numpy as np + from scipy.spatial import distance_matrix + if len(points_array) < 3: return base_distance - + # 计算站点间的平均距离 - from scipy.spatial import distance_matrix dist_matrix = distance_matrix(points_array, points_array) - + # 排除对角线(自身距离为0) np.fill_diagonal(dist_matrix, np.inf) avg_distance = np.mean(np.min(dist_matrix, axis=1)) - + # 根据平均距离调整max_distance adaptive_distance = avg_distance * 3 # 约3倍平均站点间距 - + # 限制在合理范围内 return float(np.clip(adaptive_distance, min_distance, max_distance)) @@ -131,13 +125,17 @@ class RainfallGridService: 2. 自适应距离阈值 3. 边缘渐变处理 4. 高斯平滑减少突变 - + Args: station_data: 站点数据列表 - + Returns: 插值结果字典 """ + import numpy as np + from scipy.spatial import Delaunay, ConvexHull, distance_matrix + from scipy.ndimage import gaussian_filter + # 提取站点坐标和降雨量 points_array = np.array([[s['lon'], s['lat']] for s in station_data]) values_array = np.array([s['rainfall'] for s in station_data]) @@ -184,7 +182,6 @@ class RainfallGridService: hull_mask = hull_mask.reshape(grid_lon.shape) # 计算置信度:基于到最近站点的距离 - from scipy.spatial import distance_matrix grid_valid = grid_points[hull_mask.ravel()] if len(grid_valid) > 0: dist_to_stations = distance_matrix(grid_valid, points_array) @@ -289,29 +286,35 @@ class RainfallGridService: def save_rainfall_grid_png(self, grid_data: Dict[str, Any], max_id: int) -> Optional[str]: """ 将降雨栅格保存为PNG图片(背景透明) - + Args: grid_data: 栅格数据 max_id: 最大ID - + Returns: PNG文件相对路径,失败返回None """ + import numpy as np + import matplotlib.pyplot as plt + from matplotlib.colors import ListedColormap, BoundaryNorm + from PIL import Image + from config import settings + try: grid_values = grid_data['grid_values'] lon_range = grid_data['lon_range'] lat_range = grid_data['lat_range'] - + # 创建自定义颜色映射 levels = self.rainfall_levels['levels'] colors = self.rainfall_levels['colors'] - + cmap = ListedColormap([ tuple(c / 255.0 for c in color) for color in colors ]) - + norm = BoundaryNorm(levels, cmap.N) - + # 创建图形(设置dpi确保不拉伸) fig, ax = plt.subplots(1, 1, figsize=(10, 10), dpi=100) @@ -373,17 +376,20 @@ class RainfallGridService: self.logger.error(f"保存PNG图片失败: {e}", exc_info=True) return None - def store_to_redis(self, png_path: str, max_id: int, + def store_to_redis(self, png_path: str, max_id: int, query_time, station_data: List[Dict[str, Any]]): """ 将栅格信息存储到Redis - + Args: png_path: PNG文件相对路径 max_id: 最大ID query_time: 查询时间(datetime对象或字符串) station_data: 站点数据 """ + from config import settings + from app.utils.redis_helper import redis_helper + try: redis_key = settings.REDIS_RAIN_STATION_GRID_KEY redis_identifier_key = settings.REDIS_RAIN_STATION_IDENTIFIER_KEY diff --git a/start.py b/start.py index 81ba96e..3fc9fb2 100644 --- a/start.py +++ b/start.py @@ -3,13 +3,15 @@ 使用 Dynaconf 进行环境隔离配置 """ from pathlib import Path -from app.core.launcher import AppLauncher # 添加项目根目录到Python路径 project_root = Path(__file__).parent if __name__ == "__main__": + # 延迟导入,确保在依赖安装前不会导入第三方库 + from app.core.launcher import AppLauncher + # 创建并运行启动器 launcher = AppLauncher(project_root) launcher.run()