Alaea 2.4.0__tar.gz → 2.4.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {alaea-2.4.0 → alaea-2.4.2}/.DS_Store +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/S_DateTime.py +2 -2
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/baysalt/erosion_coastline.py +209 -100
- {alaea-2.4.0 → alaea-2.4.2/Alaea.egg-info}/PKG-INFO +1 -1
- {alaea-2.4.0/Alaea.egg-info → alaea-2.4.2}/PKG-INFO +1 -1
- {alaea-2.4.0 → alaea-2.4.2}/setup.py +1 -1
- {alaea-2.4.0 → alaea-2.4.2}/.gitattributes +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/.gitignore +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/Blogging.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/Pyshell/RS_File.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/Pyshell/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/SameAsMATLAB/CoorTrans.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/SameAsMATLAB/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/SameAsMATLAB/calculatefuns.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/Standard/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/Standard/xr_attrs.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/Standard/xr_ice.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/Standard/xr_wave.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/baysalt/Forage/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/baysalt/Forage/erosion_data/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/baysalt/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/commonCode.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/cprintfs.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/exutils/Interp/Interp_g2s.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/exutils/Interp/Interp_s2g.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/exutils/Interp/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/exutils/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/pFVCOM/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/pFVCOM/fvcom_class.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/pFVCOM/fvcom_image.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/pFVCOM/fvcom_load.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/pFVCOM/fvcom_tools.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/pFVCOM/writeFile.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/processBar.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/read_conf.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/server_info.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/tools/P_params.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/tools/Read.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/tools/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/tools/download_check.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/tools/geo_distance.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/tools/kml2shp.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea/warningTools/__init__.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea.egg-info/SOURCES.txt +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea.egg-info/dependency_links.txt +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea.egg-info/requires.txt +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/Alaea.egg-info/top_level.txt +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/MANIFEST.in +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/README.md +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/run_twine.py +0 -0
- {alaea-2.4.0 → alaea-2.4.2}/setup.cfg +0 -0
|
Binary file
|
|
@@ -123,9 +123,9 @@ class Ttime:
|
|
|
123
123
|
|
|
124
124
|
if TIME is not None and fmt is not None:
|
|
125
125
|
if isinstance(TIME, list):
|
|
126
|
-
self.Times = [datetime.
|
|
126
|
+
self.Times = [datetime.strptime(TIME[i], fmt) for i in range(len(TIME))]
|
|
127
127
|
else:
|
|
128
|
-
self.Times = [datetime.
|
|
128
|
+
self.Times = [datetime.strptime(TIME, fmt)]
|
|
129
129
|
elif TIME is not None:
|
|
130
130
|
if hasattr(TIME[0], 'dtype'):
|
|
131
131
|
if isinstance(TIME, list):
|
|
@@ -14,10 +14,11 @@
|
|
|
14
14
|
|
|
15
15
|
这里的“erosion(侵蚀)”更接近一种海岸线附近的掩膜修正 / 邻域填补:
|
|
16
16
|
"""
|
|
17
|
-
|
|
18
|
-
import
|
|
17
|
+
import contextlib
|
|
18
|
+
import os
|
|
19
19
|
import time
|
|
20
|
-
from
|
|
20
|
+
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
|
|
21
|
+
from typing import List
|
|
21
22
|
|
|
22
23
|
import matplotlib.pyplot as plt
|
|
23
24
|
import numpy as np
|
|
@@ -30,9 +31,13 @@ from Alaea.Blogging import Blog
|
|
|
30
31
|
from Alaea.tools.Read import read_json, write_json
|
|
31
32
|
|
|
32
33
|
__all__ = [
|
|
34
|
+
'LOGGER',
|
|
33
35
|
'erosion_cal_id',
|
|
34
36
|
'erosion_via_id',
|
|
35
|
-
'
|
|
37
|
+
'erosion_cal_id_multi_times',
|
|
38
|
+
'erosion_via_id_multi_times',
|
|
39
|
+
'erosion_via_id_multi_vars',
|
|
40
|
+
'erosion_via_id_multi_times_multi_vars',
|
|
36
41
|
]
|
|
37
42
|
|
|
38
43
|
BLOG = Blog('erosion_coastline')
|
|
@@ -47,7 +52,7 @@ def erosion_cal_id(
|
|
|
47
52
|
k,
|
|
48
53
|
judge_num,
|
|
49
54
|
method='np.nan',
|
|
50
|
-
):
|
|
55
|
+
) -> dict:
|
|
51
56
|
"""
|
|
52
57
|
计算“哪些点需要被回填”,以及“每个点应该参考哪些邻居点”。
|
|
53
58
|
|
|
@@ -90,79 +95,73 @@ def erosion_cal_id(
|
|
|
90
95
|
lon_mesh, lat_mesh = np.meshgrid(g_lon, g_lat)
|
|
91
96
|
# 后面 KDTree 就是在这个二维坐标集合上做最近邻搜索
|
|
92
97
|
point = np.column_stack((lon_mesh.ravel(), lat_mesh.ravel()))
|
|
93
|
-
# 下面两个 deque 用来保存所有“候选邻居点”的二维索引
|
|
94
|
-
fp_lon = deque([])
|
|
95
|
-
fp_lat = deque([])
|
|
96
|
-
|
|
97
|
-
# 建立 KDTree:适合大量最近邻查询
|
|
98
|
-
# 这里 point 里装的是所有格点坐标,所以相当于“让每个格点去找离自己最近的 k 个格点”
|
|
99
|
-
ckt = spt.cKDTree(point) # 用C写的查找类,执行速度更快
|
|
100
|
-
# 这里不再逐点循环,而是一次性把所有格点的近邻都查出来
|
|
101
|
-
LOGGER.debug('Kdtree建立完毕,开始查找每个格点的近邻点')
|
|
102
|
-
|
|
103
|
-
# 对所有格点一次性查询最近邻:
|
|
104
|
-
# distances.shape 约为 (n_points, k)
|
|
105
|
-
# sequences.shape 约为 (n_points, k)
|
|
106
|
-
# sequences 里保存的是最近邻在 point 数组中的一维编号
|
|
107
|
-
distances, sequences = ckt.query(point, k)
|
|
108
|
-
|
|
109
|
-
# point 中每个元素对应一个展开后的一维索引 [0, 1, 2, ...]
|
|
110
|
-
idx_all = np.arange(point.shape[0])
|
|
111
|
-
# 把展开索引还原回二维索引:
|
|
112
|
-
# 行号 = index // 每行列数
|
|
113
|
-
lat_i_all = idx_all // lon_number
|
|
114
|
-
# 列号 = index % 每行列数
|
|
115
|
-
lon_i_all = idx_all % lon_number
|
|
116
98
|
|
|
117
99
|
# 先找出哪些格点属于“待处理点”
|
|
118
100
|
# 不同数据源中,水点/无效点/边界点的表达方式不同,所以这里分三种判断方法
|
|
119
101
|
if method == 'np.nan':
|
|
120
|
-
mask = np.isnan(value
|
|
102
|
+
mask = np.isnan(value)
|
|
121
103
|
elif method == 'nc.mask':
|
|
122
|
-
mask = value.mask
|
|
104
|
+
mask = value.mask
|
|
123
105
|
elif method == 'txt.mask':
|
|
124
|
-
mask = (value
|
|
106
|
+
mask = (value == 0)
|
|
125
107
|
else:
|
|
126
|
-
mask = np.
|
|
108
|
+
mask = np.zeros((lat_number, lon_number), dtype=bool)
|
|
127
109
|
|
|
128
|
-
|
|
129
|
-
|
|
110
|
+
target_lat, target_lon = np.where(mask)
|
|
111
|
+
if target_lat.size == 0:
|
|
112
|
+
return {
|
|
113
|
+
'change_lat': [],
|
|
114
|
+
'change_lon': [],
|
|
115
|
+
'value_lat': [],
|
|
116
|
+
'value_lon': [],
|
|
117
|
+
}
|
|
130
118
|
|
|
131
|
-
|
|
132
|
-
|
|
119
|
+
valid_idx = target_lat * lon_number + target_lon
|
|
120
|
+
target_point = point[valid_idx]
|
|
133
121
|
|
|
134
|
-
#
|
|
135
|
-
|
|
122
|
+
# 建立 KDTree:适合大量最近邻查询
|
|
123
|
+
ckt = spt.cKDTree(point) # 用C写的查找类,执行速度更快
|
|
124
|
+
LOGGER.debug('Kdtree建立完毕,开始查找待处理格点的近邻点')
|
|
136
125
|
|
|
137
|
-
#
|
|
138
|
-
|
|
139
|
-
|
|
126
|
+
# 只对待处理点查找最近邻,而不是对所有格点都查
|
|
127
|
+
query_kwargs = {'k': k}
|
|
128
|
+
with contextlib.suppress(Exception):
|
|
129
|
+
query_kwargs['workers'] = -1
|
|
130
|
+
_, neigh = ckt.query(target_point, **query_kwargs)
|
|
140
131
|
|
|
141
|
-
#
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
LOGGER.debug('所有格点的近邻点查找完毕,开始获取行列索引')
|
|
132
|
+
# 当 k == 1 时,scipy 会返回一维数组,这里统一成二维
|
|
133
|
+
neigh = np.atleast_2d(neigh)
|
|
134
|
+
if neigh.shape[0] != target_lat.size:
|
|
135
|
+
neigh = neigh.reshape(target_lat.size, -1)
|
|
146
136
|
|
|
147
|
-
#
|
|
148
|
-
lat_id =
|
|
149
|
-
lon_id =
|
|
137
|
+
# 邻居点的一维编号 -> 二维行列编号
|
|
138
|
+
lat_id = neigh // lon_number
|
|
139
|
+
lon_id = neigh % lon_number
|
|
150
140
|
|
|
151
141
|
LOGGER.debug('行列索引获取完毕,开始判断每个目标点的邻居里有效点数量')
|
|
152
|
-
|
|
142
|
+
|
|
153
143
|
# 根据不同类型的数据,进一步判断:
|
|
154
144
|
# 某个目标点的 k 个邻居里,是否有足够多的有效点可以拿来回填
|
|
155
|
-
lonli_arr = np.array([0])
|
|
156
|
-
latli_arr = np.array([0])
|
|
157
145
|
if method == 'np.nan':
|
|
158
146
|
latli_arr, lonli_arr = judge_nan_npnan(lat_id, lon_id, value, k, judge_num)
|
|
159
|
-
elif method =='nc.mask':
|
|
147
|
+
elif method == 'nc.mask':
|
|
160
148
|
latli_arr, lonli_arr = judge_nan_ncmask(lat_id, lon_id, value, k, judge_num)
|
|
161
149
|
elif method == 'txt.mask':
|
|
162
150
|
latli_arr, lonli_arr = judge_nan_txtmask(lat_id, lon_id, value, k, judge_num)
|
|
151
|
+
else:
|
|
152
|
+
latli_arr = np.empty((0, k), dtype=int)
|
|
153
|
+
lonli_arr = np.empty((0, k), dtype=int)
|
|
163
154
|
|
|
164
155
|
LOGGER.debug('有效邻居点数量判断完毕,开始生成索引')
|
|
165
156
|
|
|
157
|
+
if latli_arr.size == 0:
|
|
158
|
+
return {
|
|
159
|
+
'change_lat': [],
|
|
160
|
+
'change_lon': [],
|
|
161
|
+
'value_lat': [],
|
|
162
|
+
'value_lon': [],
|
|
163
|
+
}
|
|
164
|
+
|
|
166
165
|
# reshape 之后,每一行对应“一个目标点 + 它的 k-1 或 k 个邻居”
|
|
167
166
|
# 约定每行第 1 列是目标点本身,后面各列是参考邻居
|
|
168
167
|
_change_lat = latli_arr[:, 0].tolist()
|
|
@@ -191,27 +190,23 @@ def judge_nan_ncmask(latli, lonli, value, k, judge_num):
|
|
|
191
190
|
- 如果这 k 个点里“未被 mask 的有效点”数量不少于 judge_num,
|
|
192
191
|
就保留这一组索引
|
|
193
192
|
"""
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
lonli_2 = np.reshape(lonli_1, [-1, k])
|
|
193
|
+
latli_2 = np.asarray(latli)
|
|
194
|
+
lonli_2 = np.asarray(lonli)
|
|
195
|
+
if latli_2.size == 0:
|
|
196
|
+
return latli_2.reshape(0, k), lonli_2.reshape(0, k)
|
|
197
|
+
|
|
200
198
|
# mask=True 说明该位置是无效/被遮罩的点
|
|
201
199
|
mask_arr = value.mask
|
|
202
200
|
# 取出每组 k 个邻居的 mask 情况
|
|
203
|
-
test_arr = mask_arr[latli_2
|
|
201
|
+
test_arr = mask_arr[latli_2, lonli_2]
|
|
204
202
|
|
|
205
203
|
# 统计每组中“无效点”的数量
|
|
206
|
-
sum_arr = np.sum(test_arr, axis=1)
|
|
204
|
+
sum_arr = np.sum(test_arr, axis=1)
|
|
207
205
|
|
|
208
206
|
# 无效点数 <= k - judge_num,等价于有效点数 >= judge_num
|
|
209
|
-
|
|
207
|
+
select_mask = sum_arr <= (k - judge_num)
|
|
210
208
|
|
|
211
|
-
|
|
212
|
-
lonli_r = lonli_2[select_id[:]]
|
|
213
|
-
|
|
214
|
-
return latli_r, lonli_r
|
|
209
|
+
return latli_2[select_mask], lonli_2[select_mask]
|
|
215
210
|
|
|
216
211
|
|
|
217
212
|
def judge_nan_npnan(latli, lonli, value, k, judge_num):
|
|
@@ -221,26 +216,22 @@ def judge_nan_npnan(latli, lonli, value, k, judge_num):
|
|
|
221
216
|
逻辑与 judge_nan_ncmask 一样,只不过这里通过 np.isnan(value)
|
|
222
217
|
判断某个点是否无效。
|
|
223
218
|
"""
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
lonli_2 = np.reshape(lonli_1, [-1, k])
|
|
219
|
+
latli_2 = np.asarray(latli)
|
|
220
|
+
lonli_2 = np.asarray(lonli)
|
|
221
|
+
if latli_2.size == 0:
|
|
222
|
+
return latli_2.reshape(0, k), lonli_2.reshape(0, k)
|
|
223
|
+
|
|
230
224
|
# NaN 为 True,表示该点不能直接作为有效值参与平均
|
|
231
225
|
mask_arr = np.isnan(value)
|
|
232
226
|
|
|
233
227
|
# 检查每组 k 个邻居中哪些位置是 NaN
|
|
234
|
-
test_arr = mask_arr[latli_2
|
|
235
|
-
sum_arr = np.sum(test_arr, axis=1)
|
|
228
|
+
test_arr = mask_arr[latli_2, lonli_2]
|
|
229
|
+
sum_arr = np.sum(test_arr, axis=1)
|
|
236
230
|
|
|
237
231
|
# 只有有效值数量 >= judge_num 的目标点,才保留下来
|
|
238
|
-
|
|
232
|
+
select_mask = sum_arr <= (k - judge_num)
|
|
239
233
|
|
|
240
|
-
|
|
241
|
-
lonli_r = lonli_2[select_id[:]]
|
|
242
|
-
|
|
243
|
-
return latli_r, lonli_r
|
|
234
|
+
return latli_2[select_mask], lonli_2[select_mask]
|
|
244
235
|
|
|
245
236
|
|
|
246
237
|
def judge_nan_txtmask(latli, lonli, value, k, judge_num):
|
|
@@ -253,25 +244,21 @@ def judge_nan_txtmask(latli, lonli, value, k, judge_num):
|
|
|
253
244
|
|
|
254
245
|
当一组邻居中陆点数量 >= judge_num 时,保留该组。
|
|
255
246
|
"""
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
lonli_2 = np.reshape(lonli_1, [-1, k])
|
|
247
|
+
latli_2 = np.asarray(latli)
|
|
248
|
+
lonli_2 = np.asarray(lonli)
|
|
249
|
+
if latli_2.size == 0:
|
|
250
|
+
return latli_2.reshape(0, k), lonli_2.reshape(0, k)
|
|
261
251
|
|
|
262
252
|
# 取出每组邻居的实际值;在 mask 中通常 0=水,1=陆
|
|
263
|
-
test_arr = value[latli_2
|
|
253
|
+
test_arr = value[latli_2, lonli_2]
|
|
264
254
|
|
|
265
255
|
# 每组求和,相当于统计这一组里有多少个陆点
|
|
266
|
-
sum_arr = np.sum(test_arr, axis=1)
|
|
256
|
+
sum_arr = np.sum(test_arr, axis=1)
|
|
267
257
|
|
|
268
258
|
# 只有陆点数达到阈值,才把该目标点纳入后续腐蚀/填补
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
latli_r = latli_2[select_id[:]]
|
|
272
|
-
lonli_r = lonli_2[select_id[:]]
|
|
259
|
+
select_mask = sum_arr >= judge_num
|
|
273
260
|
|
|
274
|
-
return
|
|
261
|
+
return latli_2[select_mask], lonli_2[select_mask]
|
|
275
262
|
|
|
276
263
|
|
|
277
264
|
def erosion_via_id(_weight, value):
|
|
@@ -286,6 +273,7 @@ def erosion_via_id(_weight, value):
|
|
|
286
273
|
支持两种输入:
|
|
287
274
|
- 2D: [lat, lon]
|
|
288
275
|
- 3D: [time, lat, lon]
|
|
276
|
+
对 3D 输入会一次性批量处理整个 time 维,而不是逐时次循环。
|
|
289
277
|
|
|
290
278
|
:param _weight: erosion_cal_id 返回的字典
|
|
291
279
|
:param value: 二维或三维格点值
|
|
@@ -298,30 +286,151 @@ def erosion_via_id(_weight, value):
|
|
|
298
286
|
_value_lat = _weight['value_lat']
|
|
299
287
|
_value_lon = _weight['value_lon']
|
|
300
288
|
|
|
289
|
+
if len(_change_lat) == 0:
|
|
290
|
+
return value.copy()
|
|
291
|
+
|
|
301
292
|
# 拷贝一份,避免直接改原数组
|
|
302
293
|
new = value.copy()
|
|
294
|
+
|
|
295
|
+
# 统一转成整数索引数组:
|
|
296
|
+
# value_lat_arr / value_lon_arr 形状约为 [n_target, n_neighbor]
|
|
297
|
+
# change_lat_arr / change_lon_arr 形状约为 [n_target]
|
|
298
|
+
# 用 np.intp 可避免高级索引时的额外类型转换
|
|
299
|
+
value_lat_arr = np.asarray(_value_lat, dtype=np.intp)
|
|
300
|
+
value_lon_arr = np.asarray(_value_lon, dtype=np.intp)
|
|
301
|
+
change_lat_arr = np.asarray(_change_lat, dtype=np.intp)
|
|
302
|
+
change_lon_arr = np.asarray(_change_lon, dtype=np.intp)
|
|
303
|
+
|
|
303
304
|
# 3D 情况:常见于 [time, lat, lon]
|
|
304
305
|
if value.ndim == 3:
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
new[i, _change_lat, _change_lon] = replace[:]
|
|
306
|
+
# 一次性取出所有时刻、所有目标点对应的邻居值,形状约为 [time, n_target, n_neighbor]
|
|
307
|
+
replace = value[:, value_lat_arr, value_lon_arr]
|
|
308
|
+
# 沿邻居维求平均,得到每个时刻、每个目标点的新值
|
|
309
|
+
replace = np.nanmean(replace, axis=2)
|
|
310
|
+
# 一次性写回,避免 Python 层逐时次循环
|
|
311
|
+
new[:, change_lat_arr, change_lon_arr] = replace
|
|
312
312
|
|
|
313
313
|
# 2D 情况:直接对一个平面进行处理
|
|
314
314
|
elif value.ndim == 2:
|
|
315
315
|
# 取出每个目标点对应的一组邻居值
|
|
316
|
-
replace = value[
|
|
316
|
+
replace = value[value_lat_arr, value_lon_arr]
|
|
317
317
|
# 每组邻居求平均
|
|
318
318
|
replace = np.nanmean(replace, axis=1)
|
|
319
319
|
# 把平均值写回目标点
|
|
320
|
-
new[
|
|
320
|
+
new[change_lat_arr, change_lon_arr] = replace
|
|
321
321
|
|
|
322
322
|
return new
|
|
323
323
|
|
|
324
324
|
|
|
325
|
+
def erosion_cal_id_multi_times(_times: int,
|
|
326
|
+
g_lon,
|
|
327
|
+
g_lat,
|
|
328
|
+
value,
|
|
329
|
+
k,
|
|
330
|
+
judge_num,
|
|
331
|
+
method='np.nan',
|
|
332
|
+
) -> List:
|
|
333
|
+
"""
|
|
334
|
+
多次迭代执行 erosion_cal_id,适用于需要连续多次回填的情况
|
|
335
|
+
:param _times: 迭代次数
|
|
336
|
+
:param g_lon: 经度数组 传递给 erosion_cal_id 的参数
|
|
337
|
+
:param g_lat: 纬度数组 传递给 erosion_cal_id 的参数
|
|
338
|
+
:param value: 初始格点值 传递给 erosion_cal_id 的参数
|
|
339
|
+
:param k: 每次 erosion_cal_id 传递的参数
|
|
340
|
+
:param judge_num: 每次 erosion_cal_id 传递的参数
|
|
341
|
+
:param method: 每次 erosion_cal_id 传递的参数
|
|
342
|
+
:return: 每次迭代生成的索引列表
|
|
343
|
+
"""
|
|
344
|
+
weights = []
|
|
345
|
+
for _ in range(_times):
|
|
346
|
+
weight = erosion_cal_id(g_lon, g_lat, value, k, judge_num, method)
|
|
347
|
+
weights.append(weight)
|
|
348
|
+
# 每次迭代后,更新 value,供下一次迭代使用
|
|
349
|
+
value = erosion_via_id(weight, value)
|
|
350
|
+
return weights
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
def erosion_via_id_multi_times(weights: List,
|
|
354
|
+
value):
|
|
355
|
+
"""
|
|
356
|
+
根据 erosion_cal_id_multi_times 生成的索引列表,连续多次执行回填
|
|
357
|
+
:param weights: erosion_cal_id_multi_times 返回的索引列表
|
|
358
|
+
:param value: 初始的格点值,后续迭代会在上一次回填的基础上继续修改
|
|
359
|
+
"""
|
|
360
|
+
new_value = value.copy()
|
|
361
|
+
for weight in weights:
|
|
362
|
+
new_value = erosion_via_id(weight, new_value)
|
|
363
|
+
return new_value
|
|
364
|
+
|
|
365
|
+
def erosion_via_id_multi_vars(weights: dict,
|
|
366
|
+
viss: dict,
|
|
367
|
+
_workers=-1,
|
|
368
|
+
_method_multi: str = 'thread',
|
|
369
|
+
) -> dict:
|
|
370
|
+
"""
|
|
371
|
+
根据 erosion_cal_id_multi_times 生成的索引列表,对多个变量执行回填
|
|
372
|
+
:param weights: erosion_cal_id 返回的索引列表
|
|
373
|
+
:param viss: 字典,key 是变量名,value 是对应的格点值数组
|
|
374
|
+
:param _workers: 并行线程数,默认为 -1(使用所有可用线程)
|
|
375
|
+
:param _method_multi: 并行方法,'thread' 或 'process'
|
|
376
|
+
:return: 回填后的变量字典
|
|
377
|
+
"""
|
|
378
|
+
keys = list(viss.keys())
|
|
379
|
+
key_count = len(keys)
|
|
380
|
+
|
|
381
|
+
if key_count == 0:
|
|
382
|
+
return {}
|
|
383
|
+
elif key_count == 1:
|
|
384
|
+
viss[keys[0]] = erosion_via_id(weights, viss[keys[0]])
|
|
385
|
+
elif key_count > 1:
|
|
386
|
+
cpu_count = os.cpu_count() or 1
|
|
387
|
+
# _workers cpu_count key_count 取最小值,避免过度并行导致性能下降
|
|
388
|
+
if _workers < 0:
|
|
389
|
+
_workers = min(cpu_count, key_count)
|
|
390
|
+
else:
|
|
391
|
+
_workers = min(_workers, cpu_count, key_count)
|
|
392
|
+
|
|
393
|
+
# 并行处理多个变量
|
|
394
|
+
if _method_multi == 'thread':
|
|
395
|
+
with ThreadPoolExecutor(max_workers=_workers) as executor:
|
|
396
|
+
futures = []
|
|
397
|
+
for key in keys:
|
|
398
|
+
future = executor.submit(erosion_via_id, weights, viss[key])
|
|
399
|
+
futures.append((key, future))
|
|
400
|
+
for key, future in futures:
|
|
401
|
+
viss[key] = future.result()
|
|
402
|
+
|
|
403
|
+
elif _method_multi == 'process':
|
|
404
|
+
with ProcessPoolExecutor(max_workers=_workers) as ex:
|
|
405
|
+
future_map = {
|
|
406
|
+
key: ex.submit(erosion_via_id, weights, viss[key])
|
|
407
|
+
for key in keys
|
|
408
|
+
}
|
|
409
|
+
for key in keys:
|
|
410
|
+
viss[key] = future_map[key].result()
|
|
411
|
+
|
|
412
|
+
return viss
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def erosion_via_id_multi_times_multi_vars(weights: List,
|
|
416
|
+
viss: dict,
|
|
417
|
+
_workers=-1,
|
|
418
|
+
_method_multi: str = 'thread',
|
|
419
|
+
) -> dict:
|
|
420
|
+
"""
|
|
421
|
+
根据 erosion_cal_id_multi_times 生成的索引列表,对多个变量连续多次执行回填
|
|
422
|
+
:param weights: erosion_cal_id_multi_times 返回的索引列表
|
|
423
|
+
:param viss: 字典,key 是变量名,value 是对应的格点值数组
|
|
424
|
+
:param _workers: 并行线程数,默认为 -1(使用所有可用线程)
|
|
425
|
+
:param _method_multi: 并行方法,'thread' 或 'process'
|
|
426
|
+
:return: 回填后的变量字典
|
|
427
|
+
"""
|
|
428
|
+
new_viss = viss.copy()
|
|
429
|
+
for weight in weights:
|
|
430
|
+
new_viss = erosion_via_id_multi_vars(weight, new_viss, _workers=_workers, _method_multi=_method_multi)
|
|
431
|
+
return new_viss
|
|
432
|
+
|
|
433
|
+
|
|
325
434
|
def example_cal_weight(methoood): # sourcery skip: extract-duplicate-method
|
|
326
435
|
"""
|
|
327
436
|
示例函数:演示如何针对不同类型的数据源计算 weight,并执行一次回填。
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|