@@ -1,5 +1,6 | |||||
1 | import os |
|
1 | import os | |
2 | import datetime |
|
2 | import datetime | |
|
3 | import warnings | |||
3 | import numpy |
|
4 | import numpy | |
4 | from mpl_toolkits.axisartist.grid_finder import FixedLocator, DictFormatter |
|
5 | from mpl_toolkits.axisartist.grid_finder import FixedLocator, DictFormatter | |
5 |
|
6 | |||
@@ -7,11 +8,150 from schainpy.model.graphics.jroplot_base import Plot, plt | |||||
7 | from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot, SpectraCutPlot |
|
8 | from schainpy.model.graphics.jroplot_spectra import SpectraPlot, RTIPlot, CoherencePlot, SpectraCutPlot | |
8 | from schainpy.utils import log |
|
9 | from schainpy.utils import log | |
9 |
|
10 | |||
10 | import wradlib.georef as georef |
|
|||
11 |
|
11 | |||
12 | EARTH_RADIUS = 6.3710e3 |
|
12 | EARTH_RADIUS = 6.3710e3 | |
13 |
|
13 | |||
14 |
|
14 | |||
|
15 | def antenna_to_cartesian(ranges, azimuths, elevations): | |||
|
16 | """ | |||
|
17 | Return Cartesian coordinates from antenna coordinates. | |||
|
18 | ||||
|
19 | Parameters | |||
|
20 | ---------- | |||
|
21 | ranges : array | |||
|
22 | Distances to the center of the radar gates (bins) in kilometers. | |||
|
23 | azimuths : array | |||
|
24 | Azimuth angle of the radar in degrees. | |||
|
25 | elevations : array | |||
|
26 | Elevation angle of the radar in degrees. | |||
|
27 | ||||
|
28 | Returns | |||
|
29 | ------- | |||
|
30 | x, y, z : array | |||
|
31 | Cartesian coordinates in meters from the radar. | |||
|
32 | ||||
|
33 | Notes | |||
|
34 | ----- | |||
|
35 | The calculation for Cartesian coordinate is adapted from equations | |||
|
36 | 2.28(b) and 2.28(c) of Doviak and Zrnic [1]_ assuming a | |||
|
37 | standard atmosphere (4/3 Earth's radius model). | |||
|
38 | ||||
|
39 | .. math:: | |||
|
40 | ||||
|
41 | z = \\sqrt{r^2+R^2+2*r*R*sin(\\theta_e)} - R | |||
|
42 | ||||
|
43 | s = R * arcsin(\\frac{r*cos(\\theta_e)}{R+z}) | |||
|
44 | ||||
|
45 | x = s * sin(\\theta_a) | |||
|
46 | ||||
|
47 | y = s * cos(\\theta_a) | |||
|
48 | ||||
|
49 | Where r is the distance from the radar to the center of the gate, | |||
|
50 | :math:`\\theta_a` is the azimuth angle, :math:`\\theta_e` is the | |||
|
51 | elevation angle, s is the arc length, and R is the effective radius | |||
|
52 | of the earth, taken to be 4/3 the mean radius of earth (6371 km). | |||
|
53 | ||||
|
54 | References | |||
|
55 | ---------- | |||
|
56 | .. [1] Doviak and Zrnic, Doppler Radar and Weather Observations, Second | |||
|
57 | Edition, 1993, p. 21. | |||
|
58 | ||||
|
59 | """ | |||
|
60 | theta_e = numpy.deg2rad(elevations) # elevation angle in radians. | |||
|
61 | theta_a = numpy.deg2rad(azimuths) # azimuth angle in radians. | |||
|
62 | R = 6371.0 * 1000.0 * 4.0 / 3.0 # effective radius of earth in meters. | |||
|
63 | r = ranges * 1000.0 # distances to gates in meters. | |||
|
64 | ||||
|
65 | z = (r ** 2 + R ** 2 + 2.0 * r * R * numpy.sin(theta_e)) ** 0.5 - R | |||
|
66 | s = R * numpy.arcsin(r * numpy.cos(theta_e) / (R + z)) # arc length in m. | |||
|
67 | x = s * numpy.sin(theta_a) | |||
|
68 | y = s * numpy.cos(theta_a) | |||
|
69 | return x, y, z | |||
|
70 | ||||
|
71 | def cartesian_to_geographic_aeqd(x, y, lon_0, lat_0, R=EARTH_RADIUS): | |||
|
72 | """ | |||
|
73 | Azimuthal equidistant Cartesian to geographic coordinate transform. | |||
|
74 | ||||
|
75 | Transform a set of Cartesian/Cartographic coordinates (x, y) to | |||
|
76 | geographic coordinate system (lat, lon) using a azimuthal equidistant | |||
|
77 | map projection [1]_. | |||
|
78 | ||||
|
79 | .. math:: | |||
|
80 | ||||
|
81 | lat = \\arcsin(\\cos(c) * \\sin(lat_0) + | |||
|
82 | (y * \\sin(c) * \\cos(lat_0) / \\rho)) | |||
|
83 | ||||
|
84 | lon = lon_0 + \\arctan2( | |||
|
85 | x * \\sin(c), | |||
|
86 | \\rho * \\cos(lat_0) * \\cos(c) - y * \\sin(lat_0) * \\sin(c)) | |||
|
87 | ||||
|
88 | \\rho = \\sqrt(x^2 + y^2) | |||
|
89 | ||||
|
90 | c = \\rho / R | |||
|
91 | ||||
|
92 | Where x, y are the Cartesian position from the center of projection; | |||
|
93 | lat, lon the corresponding latitude and longitude; lat_0, lon_0 are the | |||
|
94 | latitude and longitude of the center of the projection; R is the radius of | |||
|
95 | the earth (defaults to ~6371 km). lon is adjusted to be between -180 and | |||
|
96 | 180. | |||
|
97 | ||||
|
98 | Parameters | |||
|
99 | ---------- | |||
|
100 | x, y : array-like | |||
|
101 | Cartesian coordinates in the same units as R, typically meters. | |||
|
102 | lon_0, lat_0 : float | |||
|
103 | Longitude and latitude, in degrees, of the center of the projection. | |||
|
104 | R : float, optional | |||
|
105 | Earth radius in the same units as x and y. The default value is in | |||
|
106 | units of meters. | |||
|
107 | ||||
|
108 | Returns | |||
|
109 | ------- | |||
|
110 | lon, lat : array | |||
|
111 | Longitude and latitude of Cartesian coordinates in degrees. | |||
|
112 | ||||
|
113 | References | |||
|
114 | ---------- | |||
|
115 | .. [1] Snyder, J. P. Map Projections--A Working Manual. U. S. Geological | |||
|
116 | Survey Professional Paper 1395, 1987, pp. 191-202. | |||
|
117 | ||||
|
118 | """ | |||
|
119 | x = numpy.atleast_1d(numpy.asarray(x)) | |||
|
120 | y = numpy.atleast_1d(numpy.asarray(y)) | |||
|
121 | ||||
|
122 | lat_0_rad = numpy.deg2rad(lat_0) | |||
|
123 | lon_0_rad = numpy.deg2rad(lon_0) | |||
|
124 | ||||
|
125 | rho = numpy.sqrt(x*x + y*y) | |||
|
126 | c = rho / R | |||
|
127 | ||||
|
128 | with warnings.catch_warnings(): | |||
|
129 | # division by zero may occur here but is properly addressed below so | |||
|
130 | # the warnings can be ignored | |||
|
131 | warnings.simplefilter("ignore", RuntimeWarning) | |||
|
132 | lat_rad = numpy.arcsin(numpy.cos(c) * numpy.sin(lat_0_rad) + | |||
|
133 | y * numpy.sin(c) * numpy.cos(lat_0_rad) / rho) | |||
|
134 | lat_deg = numpy.rad2deg(lat_rad) | |||
|
135 | # fix cases where the distance from the center of the projection is zero | |||
|
136 | lat_deg[rho == 0] = lat_0 | |||
|
137 | ||||
|
138 | x1 = x * numpy.sin(c) | |||
|
139 | x2 = rho*numpy.cos(lat_0_rad)*numpy.cos(c) - y*numpy.sin(lat_0_rad)*numpy.sin(c) | |||
|
140 | lon_rad = lon_0_rad + numpy.arctan2(x1, x2) | |||
|
141 | lon_deg = numpy.rad2deg(lon_rad) | |||
|
142 | # Longitudes should be from -180 to 180 degrees | |||
|
143 | lon_deg[lon_deg > 180] -= 360. | |||
|
144 | lon_deg[lon_deg < -180] += 360. | |||
|
145 | ||||
|
146 | return lon_deg, lat_deg | |||
|
147 | ||||
|
148 | def antenna_to_geographic(ranges, azimuths, elevations, site): | |||
|
149 | ||||
|
150 | x, y, z = antenna_to_cartesian(numpy.array(ranges), numpy.array(azimuths), numpy.array(elevations)) | |||
|
151 | lon, lat = cartesian_to_geographic_aeqd(x, y, site[0], site[1], R=6370997.) | |||
|
152 | ||||
|
153 | return lon, lat | |||
|
154 | ||||
15 | def ll2xy(lat1, lon1, lat2, lon2): |
|
155 | def ll2xy(lat1, lon1, lat2, lon2): | |
16 |
|
156 | |||
17 | p = 0.017453292519943295 |
|
157 | p = 0.017453292519943295 | |
@@ -457,15 +597,21 class WeatherParamsPlot(Plot): | |||||
457 | data['ele'] = dataOut.data_ele |
|
597 | data['ele'] = dataOut.data_ele | |
458 | data['mode_op'] = dataOut.mode_op |
|
598 | data['mode_op'] = dataOut.mode_op | |
459 | var = data['data'].flatten() |
|
599 | var = data['data'].flatten() | |
460 |
r = numpy.tile(data['r'], data['data'].shape[0]) |
|
600 | r = numpy.tile(data['r'], data['data'].shape[0]) | |
461 | lla = georef.spherical_to_proj(r, data['azi'], data['ele'], (-75.295893, -12.040436, 3379.2147)) |
|
601 | az = numpy.repeat(data['azi'], data['data'].shape[1]) | |
|
602 | el = numpy.repeat(data['ele'], data['data'].shape[1]) | |||
|
603 | ||||
|
604 | # lla = georef.spherical_to_proj(r, data['azi'], data['ele'], (-75.295893, -12.040436, 3379.2147)) | |||
|
605 | ||||
|
606 | latlon = antenna_to_geographic(r, az, el, (-75.295893, -12.040436)) | |||
|
607 | ||||
462 | if self.mask: |
|
608 | if self.mask: | |
463 |
meta['lat'] = l |
|
609 | meta['lat'] = latlon[1][var.mask==False] | |
464 |
meta['lon'] = l |
|
610 | meta['lon'] = latlon[0][var.mask==False] | |
465 | data['var'] = numpy.array([var[var.mask==False]]) |
|
611 | data['var'] = numpy.array([var[var.mask==False]]) | |
466 | else: |
|
612 | else: | |
467 |
meta['lat'] = l |
|
613 | meta['lat'] = latlon[1] | |
468 |
meta['lon'] = l |
|
614 | meta['lon'] = latlon[0] | |
469 | data['var'] = numpy.array([var]) |
|
615 | data['var'] = numpy.array([var]) | |
470 |
|
616 | |||
471 | return data, meta |
|
617 | return data, meta |
@@ -4146,7 +4146,6 class PedestalInformation(Operation): | |||||
4146 | ok = True |
|
4146 | ok = True | |
4147 | break |
|
4147 | break | |
4148 | except Exception as e: |
|
4148 | except Exception as e: | |
4149 | print(e) |
|
|||
4150 | log.warning('Waiting {}s for position file to be ready...'.format(self.delay), self.name) |
|
4149 | log.warning('Waiting {}s for position file to be ready...'.format(self.delay), self.name) | |
4151 | time.sleep(self.delay) |
|
4150 | time.sleep(self.delay) | |
4152 | continue |
|
4151 | continue | |
@@ -4168,8 +4167,7 class PedestalInformation(Operation): | |||||
4168 | flag_mode = None |
|
4167 | flag_mode = None | |
4169 | azi = self.fp['Data']['azi_pos'][:] |
|
4168 | azi = self.fp['Data']['azi_pos'][:] | |
4170 | ele = self.fp['Data']['ele_pos'][:] |
|
4169 | ele = self.fp['Data']['ele_pos'][:] | |
4171 | #print("az: ",az) |
|
4170 | ||
4172 | #exit(1) |
|
|||
4173 | while True: |
|
4171 | while True: | |
4174 | if start+sample_max > numpy.shape(ele)[0]: |
|
4172 | if start+sample_max > numpy.shape(ele)[0]: | |
4175 | print("CANNOT KNOW IF MODE IS PPI OR RHI, ANALIZE NEXT FILE") |
|
4173 | print("CANNOT KNOW IF MODE IS PPI OR RHI, ANALIZE NEXT FILE") | |
@@ -4219,7 +4217,7 class PedestalInformation(Operation): | |||||
4219 | else: |
|
4217 | else: | |
4220 | return numpy.nan, numpy.nan, numpy.nan |
|
4218 | return numpy.nan, numpy.nan, numpy.nan | |
4221 |
|
4219 | |||
4222 | def setup(self, dataOut, path, conf, samples, interval, mode): |
|
4220 | def setup(self, dataOut, path, conf, samples, interval, mode, online): | |
4223 |
|
4221 | |||
4224 | self.path = path |
|
4222 | self.path = path | |
4225 | self.conf = conf |
|
4223 | self.conf = conf | |
@@ -4235,15 +4233,26 class PedestalInformation(Operation): | |||||
4235 | log.error('No position files found in {}'.format(path), self.name) |
|
4233 | log.error('No position files found in {}'.format(path), self.name) | |
4236 | raise IOError('No position files found in {}'.format(path)) |
|
4234 | raise IOError('No position files found in {}'.format(path)) | |
4237 | else: |
|
4235 | else: | |
4238 |
self. |
|
4236 | if self.online: | |
4239 | self.utcfile = int(self.filename.split('/')[-1][4:14]) |
|
4237 | self.filename = filelist[-1] | |
4240 | log.log('Opening file: {}'.format(self.filename), self.name) |
|
4238 | self.utcfile = int(self.filename.split('/')[-1][4:14]) | |
4241 | self.fp = h5py.File(self.filename, 'r') |
|
4239 | log.log('Opening file: {}'.format(self.filename), self.name) | |
|
4240 | for i in range(self.nTries): | |||
|
4241 | try: | |||
|
4242 | self.fp = h5py.File(self.filename, 'r') | |||
|
4243 | except: | |||
|
4244 | log.warning('Waiting {}s for position file to be ready...'.format(self.delay), self.name) | |||
|
4245 | time.sleep(self.delay) | |||
|
4246 | else: | |||
|
4247 | self.filename = filelist[0] | |||
|
4248 | self.utcfile = int(self.filename.split('/')[-1][4:14]) | |||
|
4249 | log.log('Opening file: {}'.format(self.filename), self.name) | |||
|
4250 | self.fp = h5py.File(self.filename, 'r') | |||
4242 |
|
4251 | |||
4243 |
def run(self, dataOut, path, conf=None, samples=1500, interval=0.04, |
|
4252 | def run(self, dataOut, path, conf=None, samples=1500, interval=0.04, time_offset=0, mode=None, online=False): | |
4244 |
|
4253 | |||
4245 | if not self.isConfig: |
|
4254 | if not self.isConfig: | |
4246 | self.setup(dataOut, path, conf, samples, interval, mode) |
|
4255 | self.setup(dataOut, path, conf, samples, interval, mode, online) | |
4247 | self.isConfig = True |
|
4256 | self.isConfig = True | |
4248 |
|
4257 | |||
4249 | self.utctime = dataOut.utctime + time_offset |
|
4258 | self.utctime = dataOut.utctime + time_offset | |
@@ -4256,10 +4265,8 class PedestalInformation(Operation): | |||||
4256 | dataOut.flagNoData = True |
|
4265 | dataOut.flagNoData = True | |
4257 | return dataOut |
|
4266 | return dataOut | |
4258 |
|
4267 | |||
4259 |
dataOut.azimuth = az |
|
4268 | dataOut.azimuth = round(az, 2) | |
4260 | if dataOut.azimuth < 0: |
|
4269 | dataOut.elevation = round(el, 2) | |
4261 | dataOut.azimuth += 360 |
|
|||
4262 | dataOut.elevation = el |
|
|||
4263 | dataOut.mode_op = scan |
|
4270 | dataOut.mode_op = scan | |
4264 |
|
4271 | |||
4265 | return dataOut |
|
4272 | return dataOut | |
@@ -4307,7 +4314,6 class Block360(Operation): | |||||
4307 | Add a profile to he __buffer and increase in one the __profiel Index |
|
4314 | Add a profile to he __buffer and increase in one the __profiel Index | |
4308 | ''' |
|
4315 | ''' | |
4309 | tmp= getattr(data, attr) |
|
4316 | tmp= getattr(data, attr) | |
4310 |
|
||||
4311 | self.__buffer.append(tmp) |
|
4317 | self.__buffer.append(tmp) | |
4312 | self.__buffer2.append(data.azimuth) |
|
4318 | self.__buffer2.append(data.azimuth) | |
4313 | self.__buffer3.append(data.elevation) |
|
4319 | self.__buffer3.append(data.elevation) |
General Comments 0
You need to be logged in to leave comments.
Login now