metradar 0.1.6__py3-none-any.whl → 0.1.8.2__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.
Files changed (78) hide show
  1. metradar/__init__.py +4 -2
  2. metradar/config.py +53 -0
  3. metradar/core/__init__.py +9 -0
  4. metradar/{get_cross_section_from_pyart.py → core/get_cross_section.py} +5 -157
  5. metradar/{mosaic_merge.py → core/mosaic_merge.py} +3 -1
  6. metradar/{oa_dig_func.py → core/oa_dig_func.py} +83 -333
  7. metradar/graph/__init__.py +9 -0
  8. metradar/{mosaic_quickdraw.py → graph/draw_comp_mosaic.py} +71 -68
  9. metradar/{draw_mosaic_new.py → graph/draw_latlon_func.py} +177 -173
  10. metradar/graph/draw_radar_aws.py +212 -0
  11. metradar/{draw_radar_comp_func.py → graph/draw_radar_comp_func.py} +319 -248
  12. metradar/graph/parse_pal.py +157 -0
  13. metradar/io/__init__.py +9 -0
  14. metradar/{cnrad_level2.py → io/cnrad_level2.py} +45 -2
  15. metradar/{decode_fmt_pyart.py → io/decode_fmt_pyart.py} +20 -3
  16. metradar/{decode_pup_rose.py → io/decode_pup_rose.py} +241 -684
  17. metradar/{read_new_mosaic_func.py → io/read_new_mosaic_func.py} +30 -2
  18. metradar/io/read_swan.py +250 -0
  19. metradar/{rose_structer.py → io/rose_structer.py} +2 -0
  20. metradar/project/__init__.py +9 -0
  21. metradar/project/make_mosaic/__init__.py +9 -0
  22. metradar/project/make_mosaic/batch_draw_mosaic.py +32 -0
  23. metradar/{make_mosaic_mp_archive.py → project/make_mosaic/make_mosaic_func.py} +144 -175
  24. metradar/project/make_mosaic/make_mosaic_mp.ini +29 -0
  25. metradar/project/make_mosaic/make_mosaic_mp.py +70 -0
  26. metradar/project/make_vpr_aws/__init__.py +9 -0
  27. metradar/project/make_vpr_aws/construct_aws_refvpr_mainprog.ini +39 -0
  28. metradar/project/make_vpr_aws/construct_aws_refvpr_mainprog.py +565 -0
  29. metradar/project/make_vpr_aws/make_mosaic_20230731_daxing.ini +29 -0
  30. metradar/project/make_vpr_aws/make_mosaic_basefile.ini +29 -0
  31. metradar/project/nowcasting/__init__.py +9 -0
  32. metradar/project/nowcasting/nowcast_by_pysteps.py +214 -0
  33. metradar/{trans_nc_pgmb.py → project/nowcasting/trans_mosaic_pgmb.py} +19 -17
  34. metradar/project/qpe/Archive /346/250/241/345/274/217/350/257/264/346/230/216.txt" +2 -0
  35. metradar/project/qpe/__init__.py +9 -0
  36. metradar/project/qpe/archive_main_qpe_cfg.ini +91 -0
  37. metradar/project/qpe/do_s1.sh +6 -0
  38. metradar/project/qpe/do_s2.sh +6 -0
  39. metradar/project/qpe/do_s3.sh +6 -0
  40. metradar/project/qpe/do_s4.sh +6 -0
  41. metradar/project/qpe/do_s5.sh +6 -0
  42. metradar/project/qpe/exec_all.sh +11 -0
  43. metradar/project/qpe/get_rainrate_func.py +80 -0
  44. metradar/project/qpe/main_qpe_cfg.ini +85 -0
  45. metradar/project/qpe/s1_download_radar_region_cmadaas.py +123 -0
  46. metradar/project/qpe/s2_pre_process_single_radar.py +183 -0
  47. metradar/project/qpe/s3_trans_rainrate_to_qpe.py +499 -0
  48. metradar/project/qpe/s4_mosaic_qpe.py +523 -0
  49. metradar/project/qpe/s5_draw_qpe_mosaic.py +308 -0
  50. metradar/project/wind_retrieval/__init__.py +9 -0
  51. metradar/project/wind_retrieval/config_3dwind.ini +45 -0
  52. metradar/{main_pydda.py → project/wind_retrieval/main_pydda.py} +152 -149
  53. metradar/util/__init__.py +9 -0
  54. metradar/{comm_func.py → util/comm_func.py} +1 -41
  55. metradar/util/exceptions.py +50 -0
  56. metradar/util/geo_transforms_pyart.py +627 -0
  57. metradar/{get_tlogp_from_sharppy.py → util/get_tlogp_from_sharppy.py} +16 -5
  58. metradar/{parse_pal.py → util/parse_pal.py} +147 -147
  59. metradar/util/radar_common.py +16 -0
  60. metradar/{trans_new_mosaic_nc.py → util/trans_new_mosaic_nc.py} +1 -1
  61. metradar-0.1.8.2.dist-info/METADATA +90 -0
  62. metradar-0.1.8.2.dist-info/RECORD +69 -0
  63. {metradar-0.1.6.dist-info → metradar-0.1.8.2.dist-info}/WHEEL +1 -1
  64. metradar-0.1.8.2.dist-info/licenses/LICENSE +21 -0
  65. {metradar-0.1.6.dist-info → metradar-0.1.8.2.dist-info}/top_level.txt +0 -1
  66. cfg/config.py +0 -90
  67. metradar/grid.py +0 -281
  68. metradar/grid_data.py +0 -64
  69. metradar/oa_couhua.py +0 -166
  70. metradar/read_new_mosaic.py +0 -33
  71. metradar/retrieve_cmadaas.py +0 -3126
  72. metradar/retrieve_micaps_server.py +0 -2061
  73. metradar-0.1.6.dist-info/METADATA +0 -37
  74. metradar-0.1.6.dist-info/RECORD +0 -34
  75. /metradar/{pgmb_io.py → io/pgmb_io.py} +0 -0
  76. /metradar/{exceptions.py → project/make_vpr_aws/exceptions.py} +0 -0
  77. /metradar/{geo_transforms_pyart.py → project/make_vpr_aws/geo_transforms_pyart.py} +0 -0
  78. /metradar/{make_gif.py → util/make_gif.py} +0 -0
@@ -0,0 +1,627 @@
1
+ """
2
+ Transformations between coordinate systems. Routines for converting between
3
+ Cartesian/Cartographic (x, y, z), Geographic (latitude, longitude, altitude)
4
+ and antenna (azimuth, elevation, range) coordinate systems.
5
+
6
+ """
7
+
8
+ import warnings
9
+
10
+ import numpy as np
11
+ try:
12
+ import pyproj
13
+ _PYPROJ_AVAILABLE = True
14
+ except ImportError:
15
+ _PYPROJ_AVAILABLE = False
16
+
17
+ from metradar.util.exceptions import MissingOptionalDependency
18
+
19
+ PI = np.pi
20
+
21
+
22
+ def antenna_to_cartesian(ranges, azimuths, elevations):
23
+ """
24
+ Return Cartesian coordinates from antenna coordinates.
25
+
26
+ Parameters
27
+ ----------
28
+ ranges : array
29
+ Distances to the center of the radar gates (bins) in kilometers.
30
+ azimuths : array
31
+ Azimuth angle of the radar in degrees.
32
+ elevations : array
33
+ Elevation angle of the radar in degrees.
34
+
35
+ Returns
36
+ -------
37
+ x, y, z : array
38
+ Cartesian coordinates in meters from the radar.
39
+
40
+ Notes
41
+ -----
42
+ The calculation for Cartesian coordinate is adapted from equations
43
+ 2.28(b) and 2.28(c) of Doviak and Zrnic [1]_ assuming a
44
+ standard atmosphere (4/3 Earth's radius model).
45
+
46
+ .. math::
47
+
48
+ z = \\sqrt{r^2+R^2+2*r*R*sin(\\theta_e)} - R
49
+
50
+ s = R * arcsin(\\frac{r*cos(\\theta_e)}{R+z})
51
+
52
+ x = s * sin(\\theta_a)
53
+
54
+ y = s * cos(\\theta_a)
55
+
56
+ Where r is the distance from the radar to the center of the gate,
57
+ :math:`\\theta_a` is the azimuth angle, :math:`\\theta_e` is the
58
+ elevation angle, s is the arc length, and R is the effective radius
59
+ of the earth, taken to be 4/3 the mean radius of earth (6371 km).
60
+
61
+ References
62
+ ----------
63
+ .. [1] Doviak and Zrnic, Doppler Radar and Weather Observations, Second
64
+ Edition, 1993, p. 21.
65
+
66
+ """
67
+ theta_e = elevations * np.pi / 180.0 # elevation angle in radians.
68
+ theta_a = azimuths * np.pi / 180.0 # azimuth angle in radians.
69
+ R = 6371.0 * 1000.0 * 4.0 / 3.0 # effective radius of earth in meters.
70
+ r = ranges * 1000.0 # distances to gates in meters.
71
+
72
+ z = (r ** 2 + R ** 2 + 2.0 * r * R * np.sin(theta_e)) ** 0.5 - R
73
+ s = R * np.arcsin(r * np.cos(theta_e) / (R + z)) # arc length in m.
74
+ x = s * np.sin(theta_a)
75
+ y = s * np.cos(theta_a)
76
+ return x, y, z
77
+
78
+
79
+ def antenna_vectors_to_cartesian(ranges, azimuths, elevations, edges=False):
80
+ """
81
+ Calculate Cartesian coordinate for gates from antenna coordinate vectors.
82
+
83
+ Calculates the Cartesian coordinates for the gate centers or edges for
84
+ all gates from antenna coordinate vectors assuming a standard atmosphere
85
+ (4/3 Earth's radius model). See :py:func:`pyart.util.antenna_to_cartesian`
86
+ for details.
87
+
88
+ Parameters
89
+ ----------
90
+ ranges : array, 1D.
91
+ Distances to the center of the radar gates (bins) in meters.
92
+ azimuths : array, 1D.
93
+ Azimuth angles of the rays in degrees.
94
+ elevations : array, 1D.
95
+ Elevation angles of the rays in degrees.
96
+ edges : bool, optional
97
+ True to calculate the coordinates of the gate edges by interpolating
98
+ between gates and extrapolating at the boundaries. False to
99
+ calculate the gate centers.
100
+
101
+ Returns
102
+ -------
103
+ x, y, z : array, 2D
104
+ Cartesian coordinates in meters from the center of the radar to the
105
+ gate centers or edges.
106
+
107
+ """
108
+ if edges:
109
+ if len(ranges) != 1:
110
+ ranges = _interpolate_range_edges(ranges)
111
+ if len(elevations) != 1:
112
+ elevations = _interpolate_elevation_edges(elevations)
113
+ if len(azimuths) != 1:
114
+ azimuths = _interpolate_azimuth_edges(azimuths)
115
+ rg, azg = np.meshgrid(ranges, azimuths)
116
+ rg, eleg = np.meshgrid(ranges, elevations)
117
+ return antenna_to_cartesian(rg / 1000., azg, eleg)
118
+
119
+
120
+ def _interpolate_range_edges(ranges):
121
+ """ Interpolate the edges of the range gates from their centers. """
122
+ edges = np.empty((ranges.shape[0] + 1, ), dtype=ranges.dtype)
123
+ edges[1:-1] = (ranges[:-1] + ranges[1:]) / 2.
124
+ edges[0] = ranges[0] - (ranges[1] - ranges[0]) / 2.
125
+ edges[-1] = ranges[-1] - (ranges[-2] - ranges[-1]) / 2.
126
+ edges[edges < 0] = 0 # do not allow range to become negative
127
+ return edges
128
+
129
+
130
+ def _interpolate_elevation_edges(elevations):
131
+ """ Interpolate the edges of the elevation angles from their centers. """
132
+ edges = np.empty((elevations.shape[0]+1, ), dtype=elevations.dtype)
133
+ edges[1:-1] = (elevations[:-1] + elevations[1:]) / 2.
134
+ edges[0] = elevations[0] - (elevations[1] - elevations[0]) / 2.
135
+ edges[-1] = elevations[-1] - (elevations[-2] - elevations[-1]) / 2.
136
+ edges[edges > 180] = 180. # prevent angles from going below horizon
137
+ edges[edges < 0] = 0.
138
+ return edges
139
+
140
+
141
+ def _interpolate_azimuth_edges(azimuths):
142
+ """ Interpolate the edges of the azimuth angles from their centers. """
143
+ edges = np.empty((azimuths.shape[0]+1, ), dtype=azimuths.dtype)
144
+ # perform interpolation and extrapolation in complex plane to
145
+ # account for periodic nature of azimuth angle.
146
+ azimuths = np.exp(1.j*np.deg2rad(azimuths))
147
+
148
+ edges[1:-1] = np.angle(azimuths[1:] + azimuths[:-1], deg=True)
149
+
150
+ half_angle = _half_angle_complex(azimuths[0], azimuths[1])
151
+ edges[0] = (np.angle(azimuths[0], deg=True) - half_angle) % 360.
152
+
153
+ half_angle = _half_angle_complex(azimuths[-1], azimuths[-2])
154
+ edges[-1] = (np.angle(azimuths[-1], deg=True) + half_angle) % 360.
155
+
156
+ edges[edges < 0] += 360 # range from [-180, 180] to [0, 360]
157
+ return edges
158
+
159
+
160
+ def _half_angle_complex(complex_angle1, complex_angle2):
161
+ """
162
+ Return half the angle between complex numbers on the unit circle.
163
+
164
+ Parameters
165
+ ----------
166
+ complex_angle1, complex_angle2 : complex
167
+ Complex numbers representing unit vectors on the unit circle
168
+
169
+ Returns
170
+ -------
171
+ half_angle : float
172
+ Half the angle between the unit vectors in degrees.
173
+
174
+ """
175
+ dot_product = np.real(complex_angle1 * np.conj(complex_angle2))
176
+ if dot_product > 1:
177
+ warnings.warn("dot_product is larger than one.")
178
+ dot_product = 1.
179
+ full_angle_rad = np.arccos(dot_product)
180
+ half_angle_rad = full_angle_rad / 2.
181
+ half_angle_deg = np.rad2deg(half_angle_rad)
182
+ return half_angle_deg
183
+
184
+
185
+ def _interpolate_axes_edges(axes):
186
+ """ Interpolate the edges of the axes gates from their centers. """
187
+ edges = np.empty((axes.shape[0] + 1, ), dtype=axes.dtype)
188
+ edges[1:-1] = (axes[:-1] + axes[1:]) / 2.
189
+ edges[0] = axes[0] - (axes[1] - axes[0]) / 2.
190
+ edges[-1] = axes[-1] - (axes[-2] - axes[-1]) / 2.
191
+ return edges
192
+
193
+
194
+ def antenna_to_cartesian_track_relative(ranges, rot, roll, drift, tilt, pitch):
195
+ """
196
+ Calculate track-relative Cartesian coordinates from radar coordinates.
197
+
198
+ Parameters
199
+ ----------
200
+ ranges : array
201
+ Distances to the center of the radar gates (bins) in kilometers.
202
+ rot : array
203
+ Rotation angle of the radar in degrees.
204
+ roll : array
205
+ Roll angle of the radar in degrees.
206
+ drift : array
207
+ Drift angle of the radar in degrees.
208
+ tilt : array
209
+ Tilt angle of the radar in degrees.
210
+ pitch : array
211
+ Pitch angle of the radar in degrees.
212
+
213
+ Returns
214
+ -------
215
+ x, y, z : array
216
+ Cartesian coordinates in meters from the radar.
217
+
218
+ Notes
219
+ -----
220
+ Project native (polar) coordinate radar sweep data onto
221
+ track-relative Cartesian coordinate grid.
222
+
223
+ References
224
+ ----------
225
+ .. [1] Lee et al. (1994) Journal of Atmospheric and Oceanic Technology.
226
+
227
+ """
228
+ rot = np.radians(rot) # rotation angle in radians.
229
+ roll = np.radians(roll) # roll angle in radians.
230
+ drift = np.radians(drift) # drift angle in radians.
231
+ tilt = np.radians(tilt) # tilt angle in radians.
232
+ pitch = np.radians(pitch) # pitch angle in radians.
233
+ r = ranges * 1000.0 # distances to gates in meters.
234
+
235
+ x = r * (np.cos(rot + roll) * np.sin(drift) * np.cos(tilt) *
236
+ np.sin(pitch) + np.cos(drift) * np.sin(rot + roll) *
237
+ np.cos(tilt) - np.sin(drift) * np.cos(pitch) * np.sin(tilt))
238
+ y = r * (-1. * np.cos(rot + roll) * np.cos(drift) * np.cos(tilt) *
239
+ np.sin(pitch) + np.sin(drift) * np.sin(rot + roll) *
240
+ np.cos(tilt) + np.cos(drift) * np.cos(pitch) * np.sin(tilt))
241
+ z = (r * np.cos(pitch) * np.cos(tilt) * np.cos(rot + roll) +
242
+ np.sin(pitch) * np.sin(tilt))
243
+ return x, y, z
244
+
245
+
246
+ def antenna_to_cartesian_earth_relative(
247
+ ranges, rot, roll, heading, tilt, pitch):
248
+ """
249
+ Calculate earth-relative Cartesian coordinates from radar coordinates
250
+
251
+ Parameters
252
+ ----------
253
+ ranges : array
254
+ Distances to the center of the radar gates (bins) in kilometers.
255
+ rot : array
256
+ Rotation angle of the radar in degrees.
257
+ roll : array
258
+ Roll angle of the radar in degrees.
259
+ heading : array
260
+ Heading (compass) angle of the radar in degrees clockwise from north.
261
+ tilt : array
262
+ Tilt angle of the radar in degrees.
263
+ pitch : array
264
+ Pitch angle of the radar in degrees.
265
+
266
+ Returns
267
+ -------
268
+ x, y, z : array
269
+ Cartesian coordinates in meters from the radar.
270
+
271
+ Notes
272
+ -----
273
+ Project native (polar) coordinate radar sweep data onto
274
+ earth-relative Cartesian coordinate grid.
275
+
276
+ References
277
+ ----------
278
+ .. [1] Lee et al. (1994) Journal of Atmospheric and Oceanic Technology.
279
+
280
+ """
281
+ rot = np.radians(rot) # rotation angle in radians.
282
+ roll = np.radians(roll) # roll angle in radians.
283
+ heading = np.radians(heading) # drift angle in radians.
284
+ tilt = np.radians(tilt) # tilt angle in radians.
285
+ pitch = np.radians(pitch) # pitch angle in radians.
286
+ r = ranges * 1000.0 # distances to gates in meters.
287
+
288
+ x = r * (-1. * np.cos(rot + roll) * np.sin(heading) * np.cos(tilt) *
289
+ np.sin(pitch) + np.cos(heading) * np.sin(rot + roll) *
290
+ np.cos(tilt) + np.sin(heading) * np.cos(pitch) * np.sin(tilt))
291
+ y = r * (-1. * np.cos(rot + roll) * np.cos(heading) * np.cos(tilt) *
292
+ np.sin(pitch) - np.sin(heading) * np.sin(rot + roll) *
293
+ np.cos(tilt) + np.cos(heading) * np.cos(pitch) * np.sin(tilt))
294
+ z = (r * np.cos(pitch) * np.cos(tilt) * np.cos(rot + roll) +
295
+ np.sin(pitch) * np.sin(tilt))
296
+ return x, y, z
297
+
298
+
299
+ def antenna_to_cartesian_aircraft_relative(ranges, rot, tilt):
300
+ """
301
+ Calculate aircraft-relative Cartesian coordinates from radar coordinates.
302
+
303
+ Parameters
304
+ ----------
305
+ ranges : array
306
+ Distances to the center of the radar gates (bins) in kilometers.
307
+ rot : array
308
+ Rotation angle of the radar in degrees.
309
+ tilt : array
310
+ Tilt angle of the radar in degrees.
311
+
312
+ Returns
313
+ -------
314
+ X, Y, Z : array
315
+ Cartesian coordinates in meters from the radar.
316
+
317
+ Notes
318
+ -----
319
+ Project native (polar) coordinate radar sweep data onto
320
+ earth-relative Cartesian coordinate grid.
321
+
322
+ References
323
+ ----------
324
+ .. [1] Lee et al. (1994) Journal of Atmospheric and Oceanic Technology.
325
+
326
+ """
327
+ rot = np.radians(rot) # rotation angle in radians.
328
+ tilt = np.radians(tilt) # tilt angle in radians.
329
+ r = ranges * 1000.0 # distances to gates in meters.
330
+ x = r * np.cos(tilt) * np.sin(rot)
331
+ y = r * np.sin(tilt)
332
+ z = r * np.cos(rot) * np.cos(tilt)
333
+ return x, y, z
334
+
335
+
336
+ def geographic_to_cartesian(lon, lat, projparams):
337
+ """
338
+ Geographic to Cartesian coordinate transform.
339
+
340
+ Transform a set of Geographic coordinate (lat, lon) to a
341
+ Cartesian/Cartographic coordinate (x, y) using pyproj or a build in
342
+ Azimuthal equidistant projection.
343
+
344
+ Parameters
345
+ ----------
346
+ lon, lat : array-like
347
+ Geographic coordinates in degrees.
348
+ projparams : dict or str
349
+ Projection parameters passed to pyproj.Proj. If this parameter is a
350
+ dictionary with a 'proj' key equal to 'pyart_aeqd' then a azimuthal
351
+ equidistant projection will be used that is native to Py-ART and
352
+ does not require pyproj to be installed. In this case a non-default
353
+ value of R can be specified by setting the 'R' key to the desired
354
+ value.
355
+
356
+ Returns
357
+ -------
358
+ x, y : array-like
359
+ Cartesian coordinates in meters unless projparams defines a value for R
360
+ in different units.
361
+
362
+ """
363
+ if isinstance(projparams, dict) and projparams.get('proj') == 'pyart_aeqd':
364
+ # Use Py-ART's Azimuthal equidistance projection
365
+ lon_0 = projparams['lon_0']
366
+ lat_0 = projparams['lat_0']
367
+ if 'R' in projparams:
368
+ R = projparams['R']
369
+ x, y = geographic_to_cartesian_aeqd(lon, lat, lon_0, lat_0, R)
370
+ else:
371
+ x, y = geographic_to_cartesian_aeqd(lon, lat, lon_0, lat_0)
372
+ else:
373
+ # Use pyproj for the projection
374
+ # check that pyproj is available
375
+ if not _PYPROJ_AVAILABLE:
376
+ raise MissingOptionalDependency(
377
+ "PyProj is required to use geographic_to_cartesian "
378
+ "with a projection other than pyart_aeqd but it is not "
379
+ "installed")
380
+ proj = pyproj.Proj(projparams)
381
+ x, y = proj(lon, lat, inverse=False)
382
+ return x, y
383
+
384
+
385
+ def geographic_to_cartesian_aeqd(lon, lat, lon_0, lat_0, R=6370997.):
386
+ """
387
+ Azimuthal equidistant geographic to Cartesian coordinate transform.
388
+
389
+ Transform a set of geographic coordinates (lat, lon) to
390
+ Cartesian/Cartographic coordinates (x, y) using a azimuthal equidistant
391
+ map projection [1]_.
392
+
393
+ .. math::
394
+
395
+ x = R * k * \\cos(lat) * \\sin(lon - lon_0)
396
+
397
+ y = R * k * [\\cos(lat_0) * \\sin(lat) -
398
+ \\sin(lat_0) * \\cos(lat) * \\cos(lon - lon_0)]
399
+
400
+ k = c / \\sin(c)
401
+
402
+ c = \\arccos(\\sin(lat_0) * \\sin(lat) +
403
+ \\cos(lat_0) * \\cos(lat) * \\cos(lon - lon_0))
404
+
405
+ Where x, y are the Cartesian position from the center of projection;
406
+ lat, lon the corresponding latitude and longitude; lat_0, lon_0 are the
407
+ latitude and longitude of the center of the projection; R is the radius of
408
+ the earth (defaults to ~6371 km).
409
+
410
+ Parameters
411
+ ----------
412
+ lon, lat : array-like
413
+ Longitude and latitude coordinates in degrees.
414
+ lon_0, lat_0 : float
415
+ Longitude and latitude, in degrees, of the center of the projection.
416
+ R : float, optional
417
+ Earth radius in the same units as x and y. The default value is in
418
+ units of meters.
419
+
420
+ Returns
421
+ -------
422
+ x, y : array
423
+ Cartesian coordinates in the same units as R, typically meters.
424
+
425
+ References
426
+ ----------
427
+ .. [1] Snyder, J. P. Map Projections--A Working Manual. U. S. Geological
428
+ Survey Professional Paper 1395, 1987, pp. 191-202.
429
+
430
+ """
431
+ lon = np.atleast_1d(np.asarray(lon))
432
+ lat = np.atleast_1d(np.asarray(lat))
433
+
434
+ lon_rad = np.deg2rad(lon)
435
+ lat_rad = np.deg2rad(lat)
436
+
437
+ lat_0_rad = np.deg2rad(lat_0)
438
+ lon_0_rad = np.deg2rad(lon_0)
439
+
440
+ lon_diff_rad = lon_rad - lon_0_rad
441
+
442
+ # calculate the arccos after ensuring all values in valid domain, [-1, 1]
443
+ arg_arccos = (np.sin(lat_0_rad) * np.sin(lat_rad) +
444
+ np.cos(lat_0_rad) * np.cos(lat_rad) * np.cos(lon_diff_rad))
445
+ arg_arccos[arg_arccos > 1] = 1
446
+ arg_arccos[arg_arccos < -1] = -1
447
+ c = np.arccos(arg_arccos)
448
+ with warnings.catch_warnings():
449
+ # division by zero may occur here but is properly addressed below so
450
+ # the warnings can be ignored
451
+ warnings.simplefilter("ignore", RuntimeWarning)
452
+ k = c / np.sin(c)
453
+ # fix cases where k is undefined (c is zero), k should be 1
454
+ k[c == 0] = 1
455
+
456
+ x = R * k * np.cos(lat_rad) * np.sin(lon_diff_rad)
457
+ y = R * k * (np.cos(lat_0_rad) * np.sin(lat_rad) -
458
+ np.sin(lat_0_rad) * np.cos(lat_rad) * np.cos(lon_diff_rad))
459
+ return x, y
460
+
461
+
462
+ def cartesian_to_geographic(x, y, projparams):
463
+ """
464
+ Cartesian to Geographic coordinate transform.
465
+
466
+ Transform a set of Cartesian/Cartographic coordinates (x, y) to a
467
+ geographic coordinate system (lat, lon) using pyproj or a build in
468
+ Azimuthal equidistant projection.
469
+
470
+ Parameters
471
+ ----------
472
+ x, y : array-like
473
+ Cartesian coordinates in meters unless R is defined in different units
474
+ in the projparams parameter.
475
+ projparams : dict or str
476
+ Projection parameters passed to pyproj.Proj. If this parameter is a
477
+ dictionary with a 'proj' key equal to 'pyart_aeqd' then a azimuthal
478
+ equidistant projection will be used that is native to Py-ART and
479
+ does not require pyproj to be installed. In this case a non-default
480
+ value of R can be specified by setting the 'R' key to the desired
481
+ value.
482
+
483
+ Returns
484
+ -------
485
+ lon, lat : array
486
+ Longitude and latitude of the Cartesian coordinates in degrees.
487
+
488
+ """
489
+ if isinstance(projparams, dict) and projparams.get('proj') == 'pyart_aeqd':
490
+ # Use Py-ART's Azimuthal equidistance projection
491
+ lon_0 = projparams['lon_0']
492
+ lat_0 = projparams['lat_0']
493
+ if 'R' in projparams:
494
+ R = projparams['R']
495
+ lon, lat = cartesian_to_geographic_aeqd(x, y, lon_0, lat_0, R)
496
+ else:
497
+ lon, lat = cartesian_to_geographic_aeqd(x, y, lon_0, lat_0)
498
+ else:
499
+ # Use pyproj for the projection
500
+ # check that pyproj is available
501
+ if not _PYPROJ_AVAILABLE:
502
+ raise MissingOptionalDependency(
503
+ "PyProj is required to use cartesian_to_geographic "
504
+ "with a projection other than pyart_aeqd but it is not "
505
+ "installed")
506
+ proj = pyproj.Proj(projparams)
507
+ lon, lat = proj(x, y, inverse=True)
508
+ return lon, lat
509
+
510
+
511
+ def cartesian_vectors_to_geographic(x, y, projparams, edges=False):
512
+ """
513
+ Cartesian vectors to Geographic coordinate transform.
514
+
515
+ Transform a set of Cartesian/Cartographic coordinate vectors (x, y) to a
516
+ geographic coordinate system (lat, lon) using pyproj or a build in
517
+ Azimuthal equidistant projection finding the coordinates edges in
518
+ Cartesian space if requested.
519
+
520
+ Parameters
521
+ ----------
522
+ x, y : array 1D.
523
+ Cartesian coordinate vectors in meters unless R is defined in
524
+ different units in the projparams parameter.
525
+ projparams : dict or str
526
+ Projection parameters passed to pyproj.Proj. If this parameter is a
527
+ dictionary with a 'proj' key equal to 'pyart_aeqd' then a azimuthal
528
+ equidistant projection will be used that is native to Py-ART and
529
+ does not require pyproj to be installed. In this case a
530
+ non-default value of R can be specified by setting the 'R' key to the
531
+ desired value.
532
+ edges : bool, optional
533
+ True to calculate the coordinates of the geographic edges by
534
+ interpolating between Cartesian points and extrapolating at the
535
+ boundaries. False to calculate the coordinate centers.
536
+
537
+ Returns
538
+ -------
539
+ lon, lat : array
540
+ Longitude and latitude of the Cartesian coordinates in degrees.
541
+
542
+ """
543
+ if edges:
544
+ if len(x) > 1:
545
+ x = _interpolate_axes_edges(x)
546
+ if len(y) > 1:
547
+ y = _interpolate_axes_edges(y)
548
+ x, y = np.meshgrid(x, y)
549
+ return cartesian_to_geographic(x, y, projparams)
550
+
551
+
552
+ def cartesian_to_geographic_aeqd(x, y, lon_0, lat_0, R=6370997.):
553
+ """
554
+ Azimuthal equidistant Cartesian to geographic coordinate transform.
555
+
556
+ Transform a set of Cartesian/Cartographic coordinates (x, y) to
557
+ geographic coordinate system (lat, lon) using a azimuthal equidistant
558
+ map projection [1]_.
559
+
560
+ .. math::
561
+
562
+ lat = \\arcsin(\\cos(c) * \\sin(lat_0) +
563
+ (y * \\sin(c) * \\cos(lat_0) / \\rho))
564
+
565
+ lon = lon_0 + \\arctan2(
566
+ x * \\sin(c),
567
+ \\rho * \\cos(lat_0) * \\cos(c) - y * \\sin(lat_0) * \\sin(c))
568
+
569
+ \\rho = \\sqrt(x^2 + y^2)
570
+
571
+ c = \\rho / R
572
+
573
+ Where x, y are the Cartesian position from the center of projection;
574
+ lat, lon the corresponding latitude and longitude; lat_0, lon_0 are the
575
+ latitude and longitude of the center of the projection; R is the radius of
576
+ the earth (defaults to ~6371 km). lon is adjusted to be between -180 and
577
+ 180.
578
+
579
+ Parameters
580
+ ----------
581
+ x, y : array-like
582
+ Cartesian coordinates in the same units as R, typically meters.
583
+ lon_0, lat_0 : float
584
+ Longitude and latitude, in degrees, of the center of the projection.
585
+ R : float, optional
586
+ Earth radius in the same units as x and y. The default value is in
587
+ units of meters.
588
+
589
+ Returns
590
+ -------
591
+ lon, lat : array
592
+ Longitude and latitude of Cartesian coordinates in degrees.
593
+
594
+ References
595
+ ----------
596
+ .. [1] Snyder, J. P. Map Projections--A Working Manual. U. S. Geological
597
+ Survey Professional Paper 1395, 1987, pp. 191-202.
598
+
599
+ """
600
+ x = np.atleast_1d(np.asarray(x))
601
+ y = np.atleast_1d(np.asarray(y))
602
+
603
+ lat_0_rad = np.deg2rad(lat_0)
604
+ lon_0_rad = np.deg2rad(lon_0)
605
+
606
+ rho = np.sqrt(x*x + y*y)
607
+ c = rho / R
608
+
609
+ with warnings.catch_warnings():
610
+ # division by zero may occur here but is properly addressed below so
611
+ # the warnings can be ignored
612
+ warnings.simplefilter("ignore", RuntimeWarning)
613
+ lat_rad = np.arcsin(np.cos(c) * np.sin(lat_0_rad) +
614
+ y * np.sin(c) * np.cos(lat_0_rad) / rho)
615
+ lat_deg = np.rad2deg(lat_rad)
616
+ # fix cases where the distance from the center of the projection is zero
617
+ lat_deg[rho == 0] = lat_0
618
+
619
+ x1 = x * np.sin(c)
620
+ x2 = rho*np.cos(lat_0_rad)*np.cos(c) - y*np.sin(lat_0_rad)*np.sin(c)
621
+ lon_rad = lon_0_rad + np.arctan2(x1, x2)
622
+ lon_deg = np.rad2deg(lon_rad)
623
+ # Longitudes should be from -180 to 180 degrees
624
+ lon_deg[lon_deg > 180] -= 360.
625
+ lon_deg[lon_deg < -180] += 360.
626
+
627
+ return lon_deg, lat_deg
@@ -1,6 +1,6 @@
1
1
  '''
2
2
  从sharppy格式的探空数据中获取风廓线,作为背景场
3
- 2021.3.9
3
+
4
4
  朱文剑
5
5
  '''
6
6
 
@@ -13,8 +13,21 @@ import warnings
13
13
  warnings.filterwarnings("ignore")
14
14
 
15
15
  def get_profile(filepath,filename):
16
- # filepath = '/Users/wenjianzhu/Downloads/CMADAAS/tlogp'
17
- # filename = '20061208.58238'
16
+ """
17
+ 该函数读取sharppy格式的探空文件,提取高度、风速、风向等信息,构建并返回一个HorizontalWindProfile对象,便于后续风廓线分析和可视化。
18
+ Parameters
19
+ ----------
20
+ filepath : str
21
+ 文件路径
22
+ filename : str
23
+ 文件名
24
+ Returns
25
+ -------
26
+ outprofile : HorizontalWindProfile
27
+
28
+ 补充说明:
29
+
30
+ """
18
31
 
19
32
  fin = open(filepath + os.sep + filename,'rt')
20
33
 
@@ -72,8 +85,6 @@ def get_profile(filepath,filename):
72
85
  profile[varnames[dd]].append(values[dd])
73
86
  else:
74
87
  continue
75
- # for dd in range(len(varnames)):
76
- # exec("profile.update({'%s':%s})"%(varnames[dd],varnames[dd]))
77
88
 
78
89
  outprofile = HorizontalWindProfile(
79
90
  profile['HGHT'], np.array(profile['WSPD'])/1.94, profile['WDIR'], latitude=np.tile(float(profile['lat']), len(profile['HGHT'])), longitude=np.tile(float(profile['lon']), len(profile['HGHT'])))