metradar 0.1.0__py3-none-any.whl
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.
- metradar/__init__.py +7 -0
- metradar/cnrad_level2.py +1326 -0
- metradar/comm_func.py +135 -0
- metradar/construct_aws_refvpr_mainprog.py +515 -0
- metradar/construct_aws_refvpr_mainprog_cams.py +310 -0
- metradar/construct_aws_refvpr_mainprog_datan3d.py +386 -0
- metradar/construct_aws_refvpr_mainprog_swan.py +306 -0
- metradar/decode_fmt_pyart.py +200 -0
- metradar/decode_pup_rose.py +1993 -0
- metradar/draw_mosaic_new.py +421 -0
- metradar/draw_radar_aws_jilin_new.py +206 -0
- metradar/draw_radar_comp_func.py +1379 -0
- metradar/exceptions.py +50 -0
- metradar/geo_transforms_pyart.py +627 -0
- metradar/get_cross_section_from_pyart.py +354 -0
- metradar/get_tlogp_from_sharppy.py +93 -0
- metradar/grid.py +281 -0
- metradar/grid_data.py +64 -0
- metradar/main_pydda.py +653 -0
- metradar/make_gif.py +24 -0
- metradar/make_mosaic_mp_archive.py +538 -0
- metradar/mosaic_merge.py +64 -0
- metradar/mosaic_quickdraw.py +338 -0
- metradar/nowcast_by_pysteps.py +219 -0
- metradar/oa_couhua.py +166 -0
- metradar/oa_dig_func.py +955 -0
- metradar/parse_pal.py +148 -0
- metradar/pgmb_io.py +169 -0
- metradar/prepare_for_radar_draw.py +197 -0
- metradar/read_new_mosaic.py +33 -0
- metradar/read_new_mosaic_func.py +231 -0
- metradar/retrieve_cmadaas.py +3126 -0
- metradar/retrieve_micaps_server.py +2061 -0
- metradar/rose_structer.py +807 -0
- metradar/trans_nc_pgmb.py +62 -0
- metradar/trans_new_mosaic_nc.py +309 -0
- metradar/trans_polor2grid_func.py +203 -0
- metradar-0.1.0.dist-info/METADATA +12 -0
- metradar-0.1.0.dist-info/RECORD +41 -0
- metradar-0.1.0.dist-info/WHEEL +5 -0
- metradar-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
'''
|
|
2
|
+
制作雷达拼图,多进程
|
|
3
|
+
朱文剑
|
|
4
|
+
2021
|
|
5
|
+
|
|
6
|
+
'''
|
|
7
|
+
|
|
8
|
+
# %%
|
|
9
|
+
|
|
10
|
+
import pyart
|
|
11
|
+
import os
|
|
12
|
+
import time
|
|
13
|
+
import pandas as pd
|
|
14
|
+
from datetime import datetime,timedelta
|
|
15
|
+
import numpy as np
|
|
16
|
+
from multiprocessing import Process,Pool
|
|
17
|
+
from mosaic_merge import mosaic_merge
|
|
18
|
+
import configparser
|
|
19
|
+
import warnings
|
|
20
|
+
import glob
|
|
21
|
+
warnings.filterwarnings('ignore')
|
|
22
|
+
import schedule
|
|
23
|
+
import threading
|
|
24
|
+
from decode_fmt_pyart import read_cnrad_fmt
|
|
25
|
+
|
|
26
|
+
class MAKE_RADAR_MOSAIC:
|
|
27
|
+
|
|
28
|
+
# sub function for reading config file
|
|
29
|
+
def ConfigFetchError(Exception):
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
def _get_config_from_rcfile(self, rcfile):
|
|
33
|
+
"""
|
|
34
|
+
Get configure information from xxx.ini file.
|
|
35
|
+
"""
|
|
36
|
+
# print(os.getcwd())
|
|
37
|
+
# rc = os.getcwd() + os.sep + rcfile
|
|
38
|
+
rc = rcfile
|
|
39
|
+
if not os.path.exists(rc):
|
|
40
|
+
print('Config file: ' + rc + ' not exists!')
|
|
41
|
+
return None
|
|
42
|
+
try:
|
|
43
|
+
config = configparser.ConfigParser()
|
|
44
|
+
config.read(rc,encoding='UTF-8')
|
|
45
|
+
except IOError as e:
|
|
46
|
+
raise self.ConfigFetchError(str(e))
|
|
47
|
+
except Exception as e:
|
|
48
|
+
raise self.ConfigFetchError(str(e))
|
|
49
|
+
|
|
50
|
+
return config
|
|
51
|
+
|
|
52
|
+
def __init__(self,rcfile) -> None:
|
|
53
|
+
self.berror = False
|
|
54
|
+
if not os.path.exists(rcfile):
|
|
55
|
+
print(rcfile + ' not exists!')
|
|
56
|
+
self.berror = True
|
|
57
|
+
return None
|
|
58
|
+
config = self._get_config_from_rcfile(rcfile)
|
|
59
|
+
self.run_mode = config['RUN_MODE']['run_mode']
|
|
60
|
+
|
|
61
|
+
self.radar_mode = config['COMMON_SETTING']['radar_mode']
|
|
62
|
+
self.radar_sitesfile = config['COMMON_SETTING']['radar_sitesfile']
|
|
63
|
+
|
|
64
|
+
if not os.path.exists(self.radar_sitesfile):
|
|
65
|
+
print(self.radar_sitesfile + ' not exists!')
|
|
66
|
+
self.berror = True
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
self.realtime_peroids = int(config['REAL_TIME']['realtime_peroids'])
|
|
70
|
+
|
|
71
|
+
self.center_lon = float(config['COMMON_SETTING']['center_lon'])
|
|
72
|
+
self.center_lat = float(config['COMMON_SETTING']['center_lat'])
|
|
73
|
+
self.mosaic_range = float(config['COMMON_SETTING']['mosaic_range'])
|
|
74
|
+
self.hori_reso = float(config['COMMON_SETTING']['hori_reso'])
|
|
75
|
+
self.verti_reso = float(config['COMMON_SETTING']['verti_reso'])
|
|
76
|
+
self.breplace = int(config['COMMON_SETTING']['breplace'])
|
|
77
|
+
self.bshow_debuginfo = int(config['COMMON_SETTING']['bshow_debuginfo'])
|
|
78
|
+
|
|
79
|
+
self.multi_levels = config['COMMON_SETTING']['multi_levels'].split(',')
|
|
80
|
+
self.multi_levels = [float(tt.strip(' ')) for tt in self.multi_levels]
|
|
81
|
+
self.mosaic_vars = config['COMMON_SETTING']['mosaic_vars'].split(',')
|
|
82
|
+
self.mosaic_vars = [tt.strip(' ') for tt in self.mosaic_vars]
|
|
83
|
+
|
|
84
|
+
if self.radar_mode == 'manul':
|
|
85
|
+
self.radars = config['COMMON_SETTING']['radars'].split(',')
|
|
86
|
+
self.radars = [tt.strip(' ') for tt in self.radars]
|
|
87
|
+
else:
|
|
88
|
+
pass
|
|
89
|
+
# 根据经纬度和半径,自动计算目标范围内的雷达站名
|
|
90
|
+
# 将km半径大致除以100,换算成°
|
|
91
|
+
minlon = self.center_lon - self.mosaic_range / 100.0
|
|
92
|
+
maxlon = self.center_lon + self.mosaic_range / 100.0
|
|
93
|
+
minlat = self.center_lat - self.mosaic_range / 100.0
|
|
94
|
+
maxlat = self.center_lat + self.mosaic_range / 100.0
|
|
95
|
+
|
|
96
|
+
# load radar site file
|
|
97
|
+
|
|
98
|
+
# 根据数字站号查找对应的中文名
|
|
99
|
+
|
|
100
|
+
frad = open(self.radar_sitesfile,'rt',encoding='UTF-8')
|
|
101
|
+
|
|
102
|
+
infos = frad.readlines()
|
|
103
|
+
radsite_num = {}
|
|
104
|
+
radname_gr2 = {}
|
|
105
|
+
staname_chn={}
|
|
106
|
+
radarlat={}
|
|
107
|
+
radarlon={}
|
|
108
|
+
radheight={}
|
|
109
|
+
|
|
110
|
+
for ss in infos:
|
|
111
|
+
tmps = ss.rstrip('\n').split('|')
|
|
112
|
+
|
|
113
|
+
curlon = float(tmps[4])
|
|
114
|
+
curlat = float(tmps[3])
|
|
115
|
+
if curlon > minlon and curlon < maxlon and curlat > minlat and curlat < maxlat:
|
|
116
|
+
radsite_num[tmps[0]] = tmps[2]
|
|
117
|
+
radname_gr2[tmps[2]] = tmps[0]
|
|
118
|
+
staname_chn[tmps[2]] = tmps[1]
|
|
119
|
+
radarlat[tmps[2]]=float(tmps[3])
|
|
120
|
+
radarlon[tmps[2]]=float(tmps[4])
|
|
121
|
+
radheight[tmps[2]]=float(tmps[5])
|
|
122
|
+
self.radars = list(radsite_num.keys())
|
|
123
|
+
|
|
124
|
+
self.input_path_realtime = config['REAL_TIME']['input_path_realtime']
|
|
125
|
+
self.output_path_realtime = config['REAL_TIME']['output_path_realtime']
|
|
126
|
+
self.input_path_archive = config['ARCHIVE']['input_path_archive']
|
|
127
|
+
self.output_path_archive = config['ARCHIVE']['output_path_archive']
|
|
128
|
+
|
|
129
|
+
self.starttime = config['ARCHIVE']['starttime']
|
|
130
|
+
self.endtime = config['ARCHIVE']['endtime']
|
|
131
|
+
self.tstep = int(config['ARCHIVE']['tstep'])
|
|
132
|
+
|
|
133
|
+
# check starttime and enttime
|
|
134
|
+
try:
|
|
135
|
+
st = datetime.strptime(self.starttime,'%Y%m%d%H%M')
|
|
136
|
+
except:
|
|
137
|
+
self.berror = True
|
|
138
|
+
print('starttime set error!')
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
try:
|
|
142
|
+
et = datetime.strptime(self.endtime,'%Y%m%d%H%M')
|
|
143
|
+
except:
|
|
144
|
+
self.berror = True
|
|
145
|
+
print('endtime set error!')
|
|
146
|
+
return None
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
# check time step
|
|
151
|
+
if self.tstep < 0 or self.tstep > 60:
|
|
152
|
+
print('tstep set error, should between 0 and 60')
|
|
153
|
+
self.berror = True
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
if (et - st).total_seconds() < self.tstep * 60:
|
|
157
|
+
print('seconds between endtime and starttime is less than tstep, error!')
|
|
158
|
+
self.berror = True
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def make_mosaic(self, params):
|
|
166
|
+
|
|
167
|
+
'''
|
|
168
|
+
params={
|
|
169
|
+
# 原始数据路径
|
|
170
|
+
'rootpath':rootpath,
|
|
171
|
+
# 输出数据路径
|
|
172
|
+
'outpath': outpath,
|
|
173
|
+
# 参与拼图的雷达站点
|
|
174
|
+
'radars': ['NJJS','HAJS','BBAH','MASR','HFAH','CZJS','TZJS'],
|
|
175
|
+
'origin_latitude':center_lat, # 拼图的中心纬度
|
|
176
|
+
'origin_longitude':center_lon, # 拼图的中心经度
|
|
177
|
+
'mosaic_range':mosaic_range, # 拼图半径,km,其实是正方形
|
|
178
|
+
'hor_reso':1, # 水平方向分辨率,km
|
|
179
|
+
'ver_reso':0.5, # 垂直方向分辨率,km
|
|
180
|
+
'bdebug':True,
|
|
181
|
+
'timestr':timestr,
|
|
182
|
+
'bot_z_lev':0.5, # 最底层所在高度
|
|
183
|
+
'top_z_lev':16, # 最顶层所在高度
|
|
184
|
+
'breplace':True,
|
|
185
|
+
'outname': 'mosaic_%s.nc'%timestr
|
|
186
|
+
}
|
|
187
|
+
'''
|
|
188
|
+
|
|
189
|
+
rootpath=params['rootpath']
|
|
190
|
+
outpath=params['outpath']
|
|
191
|
+
radars=params['radars']
|
|
192
|
+
origin_latitude = params['origin_latitude']
|
|
193
|
+
origin_longitude = params['origin_longitude']
|
|
194
|
+
mr = params['mosaic_range']
|
|
195
|
+
hor_reso = params['hor_reso']
|
|
196
|
+
ver_reso = params['ver_reso']
|
|
197
|
+
bdebug = params['bdebug']
|
|
198
|
+
timestr = params['timestr']
|
|
199
|
+
outname = params['outname']
|
|
200
|
+
bot_z_lev = params['bot_z_lev']
|
|
201
|
+
top_z_lev = params['top_z_lev']
|
|
202
|
+
breplace = params['breplace']
|
|
203
|
+
|
|
204
|
+
# if timestr == '202307031912':
|
|
205
|
+
# pass
|
|
206
|
+
if not os.path.exists(outpath): os.makedirs(outpath)
|
|
207
|
+
# timestr = '201607190112'
|
|
208
|
+
if not breplace and os.path.exists(outpath + os.sep + outname):
|
|
209
|
+
print(outname + ' already exits!')
|
|
210
|
+
return False
|
|
211
|
+
curt = datetime.strptime(timestr,'%Y%m%d%H%M')
|
|
212
|
+
curt = curt.timestamp()
|
|
213
|
+
timeinfo=dict()
|
|
214
|
+
fileinfo=dict()
|
|
215
|
+
nvalidradars = 0
|
|
216
|
+
validradars=[]
|
|
217
|
+
for radar in radars:
|
|
218
|
+
curpath = rootpath + os.sep + radar
|
|
219
|
+
if not os.path.exists(curpath):
|
|
220
|
+
# print(curpath + ' not exists!')
|
|
221
|
+
# radars.remove(radar)
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
curfiles = os.listdir(curpath)
|
|
225
|
+
if len(curfiles)==0:
|
|
226
|
+
print(curpath + ' file number = %d'%len(curfiles))
|
|
227
|
+
continue
|
|
228
|
+
|
|
229
|
+
validfiles = []
|
|
230
|
+
for ff in curfiles:
|
|
231
|
+
# if ff.find('ar2v') < 0:
|
|
232
|
+
if ff.find('_CAP_FMT.bin.bz2') < 0:
|
|
233
|
+
continue
|
|
234
|
+
else:
|
|
235
|
+
validfiles.append(ff)
|
|
236
|
+
curfiles = sorted(validfiles)
|
|
237
|
+
tmptime=[]
|
|
238
|
+
tmpfile=[]
|
|
239
|
+
for file in curfiles:
|
|
240
|
+
if file.find(radar) < 0:
|
|
241
|
+
print(file + ' not contain %s, so continue...'%radar)
|
|
242
|
+
# curfiles.remove(file)
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
# cft = datetime.strptime(file[5:5+14],'%Y%m%d%H%M%S')
|
|
246
|
+
# Z_RADR_I_Z9090_20230703193348_O_DOR_SB_CAP_FMT.bin.bz2
|
|
247
|
+
# cft = datetime.strptime(file[5:13]+file[14:20],'%Y%m%d%H%M%S')
|
|
248
|
+
cft = datetime.strptime(file[15:29],'%Y%m%d%H%M%S')
|
|
249
|
+
tmptime.append(cft.timestamp())
|
|
250
|
+
tmpfile.append(curpath + os.sep + file)
|
|
251
|
+
if len(tmptime)==0:
|
|
252
|
+
continue
|
|
253
|
+
else:
|
|
254
|
+
timeinfo[radar]=tmptime
|
|
255
|
+
fileinfo[radar]=tmpfile
|
|
256
|
+
|
|
257
|
+
nvalidradars +=1
|
|
258
|
+
validradars.append(radar)
|
|
259
|
+
used_files = []
|
|
260
|
+
if nvalidradars == 0:
|
|
261
|
+
print('no valid files')
|
|
262
|
+
return False
|
|
263
|
+
|
|
264
|
+
for radar in validradars:
|
|
265
|
+
# print(radar)
|
|
266
|
+
tmpt = np.array(timeinfo[radar]) - curt
|
|
267
|
+
# try:
|
|
268
|
+
idx=list(abs(tmpt)).index(abs(tmpt).min())
|
|
269
|
+
# except:
|
|
270
|
+
# pass
|
|
271
|
+
if isinstance(idx,list):
|
|
272
|
+
idx = idx[0]
|
|
273
|
+
if abs(tmpt[idx]) > 240:
|
|
274
|
+
continue
|
|
275
|
+
used_files.append(fileinfo[radar][idx])
|
|
276
|
+
# assert isinstance(filenames,list)
|
|
277
|
+
|
|
278
|
+
if len(used_files)==0:
|
|
279
|
+
print('Error: len(used_files)==0')
|
|
280
|
+
return False
|
|
281
|
+
xgridnum = int(2*mr/hor_reso) + 1
|
|
282
|
+
ygridnum = int(2*mr/hor_reso) + 1
|
|
283
|
+
zgridnum = int((top_z_lev - bot_z_lev)/ver_reso) + 1
|
|
284
|
+
print('xgridnum = %d, ygridnum = %d, zgridnum = %d'%(xgridnum,ygridnum,zgridnum))
|
|
285
|
+
radars=[]
|
|
286
|
+
for filename in used_files:
|
|
287
|
+
try:
|
|
288
|
+
# radar = pyart.io.read_nexrad_archive(filename)
|
|
289
|
+
radar = read_cnrad_fmt(filename)
|
|
290
|
+
except:
|
|
291
|
+
print(filename + ' read error!')
|
|
292
|
+
continue
|
|
293
|
+
radars.append(radar)
|
|
294
|
+
print('add file %s'%filename)
|
|
295
|
+
|
|
296
|
+
sttime = time.time()
|
|
297
|
+
grid = pyart.map.grid_from_radars(
|
|
298
|
+
tuple(radars),
|
|
299
|
+
grid_origin = [origin_latitude,origin_longitude],
|
|
300
|
+
grid_shape=(zgridnum, ygridnum, xgridnum),
|
|
301
|
+
grid_limits=((bot_z_lev*1000, top_z_lev*1000), (-1.0*mr*1000, 1.0*mr*1000), (-1.0*mr*1000, 1.0*mr*1000)),
|
|
302
|
+
fields=['reflectivity',])#'differential_reflectivity','differential_phase'
|
|
303
|
+
|
|
304
|
+
edtime = time.time()
|
|
305
|
+
if bdebug:
|
|
306
|
+
print('grid over! cost time = %d seconds'%(int(edtime - sttime)))
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
outref = grid.fields['reflectivity']['data']
|
|
310
|
+
# prepare for netcdf output
|
|
311
|
+
# outref = outref *2 + 64
|
|
312
|
+
# grid.fields['reflectivity']['data'] = outref
|
|
313
|
+
# grid.fields['reflectivity']['valid_max'] = np.array(grid.fields['reflectivity']['valid_max'] * 2 + 64).astype(np.uint8)
|
|
314
|
+
# grid.fields['reflectivity']['valid_min'] = np.array(grid.fields['reflectivity']['valid_min'] * 2 + 64).astype(np.uint8)
|
|
315
|
+
|
|
316
|
+
grid.fields['reflectivity']['data'] = outref
|
|
317
|
+
grid.fields['reflectivity']['valid_max'] = np.array(grid.fields['reflectivity']['valid_max'])
|
|
318
|
+
grid.fields['reflectivity']['valid_min'] = np.array(grid.fields['reflectivity']['valid_min'])
|
|
319
|
+
|
|
320
|
+
# write to netcdf
|
|
321
|
+
# gx = grid.to_xarray()
|
|
322
|
+
# gx.reflectivity.data=gx.reflectivity.astype(np.uint8)
|
|
323
|
+
# gx = gx.drop_vars('ROI')
|
|
324
|
+
# cref = np.nanmax(gx.reflectivity.data[0,:,:,:],axis=0)
|
|
325
|
+
# # 增加变量到Dataset
|
|
326
|
+
# gx["cref"]=(['y', 'x'],cref,{'scale':2,'offset':64,'decode':'dBZ = (cref-64)/2'})
|
|
327
|
+
# # gx = gx.drop_vars('reflectivity')
|
|
328
|
+
# gx.to_netcdf(outpath + os.sep + outname)
|
|
329
|
+
|
|
330
|
+
pyart.io.write_grid(outpath + os.sep + outname ,grid)
|
|
331
|
+
|
|
332
|
+
print(outpath + os.sep + outname + ' done!')
|
|
333
|
+
|
|
334
|
+
def do_realtime(self,):
|
|
335
|
+
if os.path.exists('file.lock'):
|
|
336
|
+
print('do_realtime still running')
|
|
337
|
+
return False
|
|
338
|
+
|
|
339
|
+
print('进入 do_realtime')
|
|
340
|
+
|
|
341
|
+
# 创建锁文件,防止程序重复运行
|
|
342
|
+
lockfile = open('file.lock','wt')
|
|
343
|
+
lockfile.write(datetime.utcnow().strftime('%Y%m%d%H%M%S'))
|
|
344
|
+
lockfile.close()
|
|
345
|
+
|
|
346
|
+
rootpath = self.input_path_realtime
|
|
347
|
+
outpath = self.output_path_realtime
|
|
348
|
+
radars = self.radars
|
|
349
|
+
center_lat = self.center_lat
|
|
350
|
+
center_lon = self.center_lon
|
|
351
|
+
mosaic_range = self.mosaic_range
|
|
352
|
+
hor_reso = self.hori_reso
|
|
353
|
+
ver_reso = self.verti_reso
|
|
354
|
+
bshow_debug = self.bshow_debuginfo
|
|
355
|
+
breplace = self.breplace
|
|
356
|
+
levels = self.multi_levels
|
|
357
|
+
|
|
358
|
+
allparams = []
|
|
359
|
+
ct = datetime.utcnow()
|
|
360
|
+
newct = ct - timedelta(minutes= ct.minute % 6 )
|
|
361
|
+
timestr = newct.strftime('%Y%m%d%H%M')
|
|
362
|
+
print('processing : ' + timestr)
|
|
363
|
+
|
|
364
|
+
alloutfiles=[]
|
|
365
|
+
mergename = outpath + os.sep + 'mosaic_%s.nc'%timestr
|
|
366
|
+
if not breplace and os.path.exists(mergename):
|
|
367
|
+
print(mergename + ' already exists!')
|
|
368
|
+
return True
|
|
369
|
+
|
|
370
|
+
for nn in range(len(levels)-1):
|
|
371
|
+
|
|
372
|
+
outname = 'mosaic_%s_%d_tmp.nc'%(timestr,nn+1)
|
|
373
|
+
# 分为多个进程,每个进程计算一段高度上的拼图,最后再进行拼接
|
|
374
|
+
params={
|
|
375
|
+
# 原始数据路径
|
|
376
|
+
'rootpath':rootpath,
|
|
377
|
+
# 输出数据路径
|
|
378
|
+
'outpath': outpath,
|
|
379
|
+
# 参与拼图的雷达站点
|
|
380
|
+
'radars':radars,
|
|
381
|
+
'origin_latitude':center_lat, # 拼图的中心纬度
|
|
382
|
+
'origin_longitude':center_lon, # 拼图的中心经度
|
|
383
|
+
'mosaic_range':mosaic_range, # 拼图半径,km,其实是正方形
|
|
384
|
+
'hor_reso':hor_reso, # 水平方向分辨率,km
|
|
385
|
+
'ver_reso':ver_reso, # 垂直方向分辨率,km
|
|
386
|
+
'bdebug':bshow_debug,
|
|
387
|
+
'timestr':timestr, # 时间戳,程序按照这个时间来匹配数据
|
|
388
|
+
'bot_z_lev':levels[nn] + ver_reso, # 最底层所在高度
|
|
389
|
+
'top_z_lev':levels[nn+1], # 最顶层所在高度
|
|
390
|
+
'breplace':breplace,
|
|
391
|
+
'outname':outname,
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
alloutfiles.append(outpath + os.sep + outname)
|
|
395
|
+
allparams.append(params)
|
|
396
|
+
|
|
397
|
+
MAXP=len(levels)-1
|
|
398
|
+
pools = Pool(MAXP)
|
|
399
|
+
|
|
400
|
+
pools.map(self.make_mosaic, allparams)
|
|
401
|
+
pools.close()
|
|
402
|
+
pools.join()
|
|
403
|
+
|
|
404
|
+
# 对数据进行拼接
|
|
405
|
+
|
|
406
|
+
newgrid = mosaic_merge(files = alloutfiles)
|
|
407
|
+
# write to file
|
|
408
|
+
if newgrid is not None:
|
|
409
|
+
newgrid.write(mergename)
|
|
410
|
+
print(mergename + ' saved!')
|
|
411
|
+
# time.sleep(2)
|
|
412
|
+
|
|
413
|
+
else:
|
|
414
|
+
print('merge error!')
|
|
415
|
+
# delete temp files
|
|
416
|
+
files = glob.glob(outpath + os.sep + '*tmp.nc')
|
|
417
|
+
if len(files) >0:
|
|
418
|
+
for file in files:
|
|
419
|
+
os.remove(file)
|
|
420
|
+
|
|
421
|
+
# 删除锁文件,允许程序运行
|
|
422
|
+
if os.path.exists('file.lock'): os.remove('file.lock')
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def do_archive(self,):
|
|
426
|
+
|
|
427
|
+
st = datetime.strptime(self.starttime,'%Y%m%d%H%M')
|
|
428
|
+
et = datetime.strptime(self.endtime,'%Y%m%d%H%M')
|
|
429
|
+
periods = int(((et - st).total_seconds() / 60)/self.tstep)+1
|
|
430
|
+
print('periods = %d'%periods)
|
|
431
|
+
dt = pd.date_range(st,freq='%dmin'%self.tstep,periods=periods)
|
|
432
|
+
dt = pd.to_datetime(dt)
|
|
433
|
+
alltimes=[tt.strftime('%Y%m%d%H%M') for tt in dt]
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
# radars = self.radars
|
|
438
|
+
# center_lat = _make_mosaic.center_lat
|
|
439
|
+
# center_lon = _make_mosaic.center_lon
|
|
440
|
+
# mosaic_range = _make_mosaic.mosaic_range
|
|
441
|
+
# hor_reso = _make_mosaic.hori_reso
|
|
442
|
+
# ver_reso = _make_mosaic.verti_reso
|
|
443
|
+
# bshow_debug = self.bshow_debuginfo
|
|
444
|
+
# breplace = _make_mosaic.breplace
|
|
445
|
+
# levels = self.multi_levels
|
|
446
|
+
|
|
447
|
+
# levels 高度层 单位KM
|
|
448
|
+
# levels = [0, 5, 9, 12, 16]
|
|
449
|
+
# levels = [0, 7, 10, 13, 16, 20] 82s
|
|
450
|
+
# levels = [0, 7, 10, 13, 16, 20]
|
|
451
|
+
# MAXP = int(cpu_count()*0.2)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
for timestr in alltimes:
|
|
455
|
+
allparams = []
|
|
456
|
+
print('processing : ' + timestr)
|
|
457
|
+
|
|
458
|
+
alloutfiles=[]
|
|
459
|
+
rootpath = self.input_path_archive + os.sep + timestr[0:4] + os.sep + timestr[0:8]
|
|
460
|
+
outpath = self.output_path_archive
|
|
461
|
+
|
|
462
|
+
if not os.path.exists(outpath):
|
|
463
|
+
os.makedirs(outpath)
|
|
464
|
+
mergename = outpath + os.sep + 'mosaic_%s.nc'%timestr
|
|
465
|
+
if not self.breplace and os.path.exists(mergename):
|
|
466
|
+
print(mergename + ' already exists!')
|
|
467
|
+
continue
|
|
468
|
+
|
|
469
|
+
for nn in range(len(self.multi_levels)-1):
|
|
470
|
+
|
|
471
|
+
outname = 'mosaic_%s_%d_tmp.nc'%(timestr,nn+1)
|
|
472
|
+
# 分为多个进程,每个进程计算一段高度上的拼图,最后再进行拼接
|
|
473
|
+
params={
|
|
474
|
+
# 原始数据路径
|
|
475
|
+
'rootpath':rootpath,
|
|
476
|
+
# 输出数据路径
|
|
477
|
+
'outpath': outpath,
|
|
478
|
+
# 参与拼图的雷达站点
|
|
479
|
+
'radars':self.radars,
|
|
480
|
+
'origin_latitude':self.center_lat, # 拼图的中心纬度
|
|
481
|
+
'origin_longitude':self.center_lon, # 拼图的中心经度
|
|
482
|
+
'mosaic_range':self.mosaic_range, # 拼图半径,km,其实是正方形
|
|
483
|
+
'hor_reso':self.hori_reso, # 水平方向分辨率,km
|
|
484
|
+
'ver_reso':self.verti_reso, # 垂直方向分辨率,km
|
|
485
|
+
'bdebug':self.bshow_debuginfo,
|
|
486
|
+
'timestr':timestr, # 时间戳,程序按照这个时间来匹配数据
|
|
487
|
+
'bot_z_lev':self.multi_levels[nn] + nn*self.verti_reso, # 最底层所在高度
|
|
488
|
+
'top_z_lev':self.multi_levels[nn+1], # 最顶层所在高度
|
|
489
|
+
'breplace':self.breplace,
|
|
490
|
+
'outname':outname,
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
alloutfiles.append(outpath + os.sep + outname)
|
|
494
|
+
allparams.append(params)
|
|
495
|
+
|
|
496
|
+
MAXP=len(self.multi_levels)-1
|
|
497
|
+
pools = Pool(MAXP)
|
|
498
|
+
|
|
499
|
+
pools.map(self.make_mosaic, allparams)
|
|
500
|
+
pools.close()
|
|
501
|
+
pools.join()
|
|
502
|
+
|
|
503
|
+
# 对数据进行拼接
|
|
504
|
+
|
|
505
|
+
newgrid = mosaic_merge(files = alloutfiles)
|
|
506
|
+
if newgrid is not None:
|
|
507
|
+
# write to file
|
|
508
|
+
newgrid.write(mergename)
|
|
509
|
+
|
|
510
|
+
print(mergename + ' saved!')
|
|
511
|
+
else:
|
|
512
|
+
print('merge error!')
|
|
513
|
+
# time.sleep(2)
|
|
514
|
+
# delete temp files
|
|
515
|
+
files = glob.glob(outpath + os.sep + '*tmp.nc')
|
|
516
|
+
if len(files) >0:
|
|
517
|
+
for file in files:
|
|
518
|
+
os.remove(file)
|
|
519
|
+
|
|
520
|
+
def run_threaded(job_func):
|
|
521
|
+
job_thread = threading.Thread(target=job_func)
|
|
522
|
+
job_thread.start()
|
|
523
|
+
|
|
524
|
+
if __name__ == "__main__":
|
|
525
|
+
|
|
526
|
+
print('starting mosaic program......')
|
|
527
|
+
|
|
528
|
+
_make_mosaic = MAKE_RADAR_MOSAIC('make_mosaic_mp_archive.ini')
|
|
529
|
+
|
|
530
|
+
if not _make_mosaic.berror:
|
|
531
|
+
if _make_mosaic.run_mode == 'archive':
|
|
532
|
+
_make_mosaic.do_archive()
|
|
533
|
+
else:
|
|
534
|
+
print('run mode is not archive!')
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
# %%
|
metradar/mosaic_merge.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
'''
|
|
2
|
+
将不同层次的mosacdata stack在一起
|
|
3
|
+
ZhuWJ
|
|
4
|
+
|
|
5
|
+
'''
|
|
6
|
+
|
|
7
|
+
# %%
|
|
8
|
+
import pyart
|
|
9
|
+
import os
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# 将多层的临时文件在高度维度上进行拼接
|
|
14
|
+
def mosaic_merge(files:list):
|
|
15
|
+
|
|
16
|
+
grids = []
|
|
17
|
+
for file in files:
|
|
18
|
+
if not os.path.exists(file):
|
|
19
|
+
print(file + ' not exists!')
|
|
20
|
+
return None
|
|
21
|
+
try:
|
|
22
|
+
tmpgrid = pyart.io.read_grid(file)
|
|
23
|
+
grids.append(tmpgrid)
|
|
24
|
+
print(tmpgrid.nz,tmpgrid.ny,tmpgrid.nx)
|
|
25
|
+
except:
|
|
26
|
+
print(file + ' load error!')
|
|
27
|
+
return None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# newz = list(grid1.z['data']) + list(grid2.z['data'])
|
|
31
|
+
newz = []
|
|
32
|
+
for nn in range(len(grids)):
|
|
33
|
+
for val in grids[nn].z['data']:
|
|
34
|
+
newz.append(val)
|
|
35
|
+
|
|
36
|
+
# trans list to mask array
|
|
37
|
+
newz = np.ma.MaskedArray(newz)
|
|
38
|
+
|
|
39
|
+
# 对数据进行垂直方向拼接
|
|
40
|
+
newgrid = pyart.io.read_grid(files[0])
|
|
41
|
+
newgrid.z['data'] = newz
|
|
42
|
+
newgrid.nz = len(newz)
|
|
43
|
+
|
|
44
|
+
# 对所有的field都要进行拼接
|
|
45
|
+
for field in newgrid.fields.keys():
|
|
46
|
+
newdata = np.ma.zeros((newgrid.nz,newgrid.ny,newgrid.nx),dtype='float32')
|
|
47
|
+
newdata[:grids[0].nz,:,:] = grids[0].fields[field]['data']
|
|
48
|
+
curidx=grids[0].nz
|
|
49
|
+
for nn in range(len(grids)-1):
|
|
50
|
+
newdata[curidx:curidx+grids[nn+1].nz,:,:] = grids[nn+1].fields[field]['data']
|
|
51
|
+
curidx +=grids[nn+1].nz
|
|
52
|
+
|
|
53
|
+
newgrid.fields[field]['data'] = np.ma.MaskedArray(newdata)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
return newgrid
|
|
57
|
+
|
|
58
|
+
# 如果拼接成功,那么可以调用grid3.to_xarray()来检验,看返回是否成功
|
|
59
|
+
# grid3.to_xarray()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
if __name__ == "__main__":
|
|
63
|
+
|
|
64
|
+
pass
|