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.
- metradar/__init__.py +4 -2
- metradar/config.py +53 -0
- metradar/core/__init__.py +9 -0
- metradar/{get_cross_section_from_pyart.py → core/get_cross_section.py} +5 -157
- metradar/{mosaic_merge.py → core/mosaic_merge.py} +3 -1
- metradar/{oa_dig_func.py → core/oa_dig_func.py} +83 -333
- metradar/graph/__init__.py +9 -0
- metradar/{mosaic_quickdraw.py → graph/draw_comp_mosaic.py} +71 -68
- metradar/{draw_mosaic_new.py → graph/draw_latlon_func.py} +177 -173
- metradar/graph/draw_radar_aws.py +212 -0
- metradar/{draw_radar_comp_func.py → graph/draw_radar_comp_func.py} +319 -248
- metradar/graph/parse_pal.py +157 -0
- metradar/io/__init__.py +9 -0
- metradar/{cnrad_level2.py → io/cnrad_level2.py} +45 -2
- metradar/{decode_fmt_pyart.py → io/decode_fmt_pyart.py} +20 -3
- metradar/{decode_pup_rose.py → io/decode_pup_rose.py} +241 -684
- metradar/{read_new_mosaic_func.py → io/read_new_mosaic_func.py} +30 -2
- metradar/io/read_swan.py +250 -0
- metradar/{rose_structer.py → io/rose_structer.py} +2 -0
- metradar/project/__init__.py +9 -0
- metradar/project/make_mosaic/__init__.py +9 -0
- metradar/project/make_mosaic/batch_draw_mosaic.py +32 -0
- metradar/{make_mosaic_mp_archive.py → project/make_mosaic/make_mosaic_func.py} +144 -175
- metradar/project/make_mosaic/make_mosaic_mp.ini +29 -0
- metradar/project/make_mosaic/make_mosaic_mp.py +70 -0
- metradar/project/make_vpr_aws/__init__.py +9 -0
- metradar/project/make_vpr_aws/construct_aws_refvpr_mainprog.ini +39 -0
- metradar/project/make_vpr_aws/construct_aws_refvpr_mainprog.py +565 -0
- metradar/project/make_vpr_aws/make_mosaic_20230731_daxing.ini +29 -0
- metradar/project/make_vpr_aws/make_mosaic_basefile.ini +29 -0
- metradar/project/nowcasting/__init__.py +9 -0
- metradar/project/nowcasting/nowcast_by_pysteps.py +214 -0
- metradar/{trans_nc_pgmb.py → project/nowcasting/trans_mosaic_pgmb.py} +19 -17
- metradar/project/qpe/Archive /346/250/241/345/274/217/350/257/264/346/230/216.txt" +2 -0
- metradar/project/qpe/__init__.py +9 -0
- metradar/project/qpe/archive_main_qpe_cfg.ini +91 -0
- metradar/project/qpe/do_s1.sh +6 -0
- metradar/project/qpe/do_s2.sh +6 -0
- metradar/project/qpe/do_s3.sh +6 -0
- metradar/project/qpe/do_s4.sh +6 -0
- metradar/project/qpe/do_s5.sh +6 -0
- metradar/project/qpe/exec_all.sh +11 -0
- metradar/project/qpe/get_rainrate_func.py +80 -0
- metradar/project/qpe/main_qpe_cfg.ini +85 -0
- metradar/project/qpe/s1_download_radar_region_cmadaas.py +123 -0
- metradar/project/qpe/s2_pre_process_single_radar.py +183 -0
- metradar/project/qpe/s3_trans_rainrate_to_qpe.py +499 -0
- metradar/project/qpe/s4_mosaic_qpe.py +523 -0
- metradar/project/qpe/s5_draw_qpe_mosaic.py +308 -0
- metradar/project/wind_retrieval/__init__.py +9 -0
- metradar/project/wind_retrieval/config_3dwind.ini +45 -0
- metradar/{main_pydda.py → project/wind_retrieval/main_pydda.py} +152 -149
- metradar/util/__init__.py +9 -0
- metradar/{comm_func.py → util/comm_func.py} +1 -41
- metradar/util/exceptions.py +50 -0
- metradar/util/geo_transforms_pyart.py +627 -0
- metradar/{get_tlogp_from_sharppy.py → util/get_tlogp_from_sharppy.py} +16 -5
- metradar/{parse_pal.py → util/parse_pal.py} +147 -147
- metradar/util/radar_common.py +16 -0
- metradar/{trans_new_mosaic_nc.py → util/trans_new_mosaic_nc.py} +1 -1
- metradar-0.1.8.2.dist-info/METADATA +90 -0
- metradar-0.1.8.2.dist-info/RECORD +69 -0
- {metradar-0.1.6.dist-info → metradar-0.1.8.2.dist-info}/WHEEL +1 -1
- metradar-0.1.8.2.dist-info/licenses/LICENSE +21 -0
- {metradar-0.1.6.dist-info → metradar-0.1.8.2.dist-info}/top_level.txt +0 -1
- cfg/config.py +0 -90
- metradar/grid.py +0 -281
- metradar/grid_data.py +0 -64
- metradar/oa_couhua.py +0 -166
- metradar/read_new_mosaic.py +0 -33
- metradar/retrieve_cmadaas.py +0 -3126
- metradar/retrieve_micaps_server.py +0 -2061
- metradar-0.1.6.dist-info/METADATA +0 -37
- metradar-0.1.6.dist-info/RECORD +0 -34
- /metradar/{pgmb_io.py → io/pgmb_io.py} +0 -0
- /metradar/{exceptions.py → project/make_vpr_aws/exceptions.py} +0 -0
- /metradar/{geo_transforms_pyart.py → project/make_vpr_aws/geo_transforms_pyart.py} +0 -0
- /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
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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'])))
|