From de9d6f0835d4e40cd50b6b9178aab39422c1a25e Mon Sep 17 00:00:00 2001 From: duxin Date: Mon, 27 Jul 2026 18:08:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20Kriging=20=E6=95=B4=E4=BD=93=E6=8B=9F?= =?UTF-8?q?=E5=90=88+=E5=8F=98=E5=BC=82=E5=87=BD=E6=95=B0=E5=AE=B9?= =?UTF-8?q?=E9=94=99+=E8=87=AA=E9=80=82=E5=BA=94=E5=88=86=E5=B1=82?= =?UTF-8?q?=E6=8A=BD=E6=A0=B7+=E9=AB=98=E6=96=AF=E5=B9=B3=E6=BB=91+?= =?UTF-8?q?=E6=8E=A9=E8=86=9C=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/postprocessing/map.py | 49 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/src/postprocessing/map.py b/src/postprocessing/map.py index 79731a7..43e8d27 100644 --- a/src/postprocessing/map.py +++ b/src/postprocessing/map.py @@ -672,7 +672,52 @@ class ContentMapper: grid_y = grid_yy[:, 0] total_cells = len(grid_x) * len(grid_y) - # ── 1) 全局变异函数拟合(多模型容错回退)── + # ── 1) 全局变异函数拟合(自适应分层抽样防 OOM)── + # 变异函数拟合内存 ≈ N²×8 bytes。预留 1.5GB 安全上限 → N_max≈14000 + _vario_pts = points + _vario_vals = values + # 从系统内存动态估算可容纳的最大点数 + try: + import psutil + _avail_gb = psutil.virtual_memory().available / (1024**3) + except Exception: + _avail_gb = 4.0 # 保守兜底 + # 计算安全点数:留 50% 余量给 Python 开销 + _MAX_VARIOGRAM_PTS = int(np.sqrt(max(_avail_gb * 0.5, 0.5) * 1024**3 / 8)) + _MAX_VARIOGRAM_PTS = np.clip(_MAX_VARIOGRAM_PTS, 3000, 20000) + + if len(points) > _MAX_VARIOGRAM_PTS: + # 空间分层抽样:网格覆盖全水域,每格保留1点 + _grid = int(np.ceil(np.sqrt(_MAX_VARIOGRAM_PTS))) + _x_bins = np.linspace(points[:, 0].min(), points[:, 0].max(), _grid + 1) + _y_bins = np.linspace(points[:, 1].min(), points[:, 1].max(), _grid + 1) + _keep = np.zeros(len(points), dtype=bool) + for _ix in range(_grid): + for _iy in range(_grid): + _cell = ( + (points[:, 0] >= _x_bins[_ix]) & + (points[:, 0] < _x_bins[_ix + 1]) & + (points[:, 1] >= _y_bins[_iy]) & + (points[:, 1] < _y_bins[_iy + 1]) + ) + if _cell.any(): + _keep[np.where(_cell)[0][0]] = True + _kept_idx = np.where(_keep)[0] + if len(_kept_idx) < _MAX_VARIOGRAM_PTS: + _remaining = np.where(~_keep)[0] + _extra = np.random.default_rng(42).choice( + _remaining, + min(_MAX_VARIOGRAM_PTS - len(_kept_idx), len(_remaining)), + replace=False, + ) + _kept_idx = np.concatenate([_kept_idx, _extra]) + _vario_pts = points[_kept_idx] + _vario_vals = values[_kept_idx] + print(f" [Kriging] 采样点 {len(points)} > {_MAX_VARIOGRAM_PTS}" + f"(可用内存 {_avail_gb:.1f}GB)," + f"空间分层抽样 → {len(_kept_idx)} 点" + f"(网格 {_grid}×{_grid},全覆盖)") + _vario_models = [ ('spherical', {'nugget': 1e-6}), ('exponential', {'nugget': 1e-6}), @@ -684,7 +729,7 @@ class ContentMapper: for _vm_name, _vm_kw in _vario_models: try: ok_model = OrdinaryKriging( - points[:, 0], points[:, 1], values, + _vario_pts[:, 0], _vario_pts[:, 1], _vario_vals, variogram_model=_vm_name, verbose=False, enable_plotting=False, **_vm_kw,