Issues (227)

awips/gempak/GridNavRetriever.py (11 issues)

1
import os
2
import math
3
from awips import ThriftClient
4
from dynamicserialize.dstypes.gov.noaa.nws.ncep.common.dataplugin.gempak.request import GetGridNavRequest
5
from ctypes import *
6
7
EARTH_RADIUS = 6371200.0
8
DEG_TO_RAD = math.pi / 180.0
9
RAD_TO_DEG = 180.0 / math.pi
10
TWOPI = math.pi * 2.0
11
HALFPI = math.pi / 2.0
12
PI4TH = math.pi / 4.0
13
PI3RD = math.pi / 3.0
14
15
16
def createPolar(nsflag, clon, lat1, lon1, dx, dy, unit, nx, ny):
17
    clonr = clon * DEG_TO_RAD
18
    latr = lat1 * DEG_TO_RAD
19
    lonr = lon1 * DEG_TO_RAD
20
    if nsflag == 'N':
21
        x1 = EARTH_RADIUS * math.tan(PI4TH - latr/2.0) * math.sin(lonr-clonr)
22
        y1 = -1 * EARTH_RADIUS * math.tan(PI4TH - latr/2.0) * math.cos(lonr-clonr)
23
    else:
24
        x1 = EARTH_RADIUS * math.tan(PI4TH + latr/2.0) * math.sin(lonr-clonr)
25
        y1 = EARTH_RADIUS * math.tan(PI4TH + latr/2.0) * math.cos(lonr-clonr)
26
27
    if unit == 'm':
28
        tdx = dx / (1 + math.sin(PI3RD))
29
        tdy = dy / (1 + math.sin(PI3RD))
30
    else:
31
        tdx = (dx*1000.0) / (1 + math.sin(PI3RD))
32
        tdy = (dy*1000.0) / (1 + math.sin(PI3RD))
33
34
    x2 = x1 + tdx * (nx-1)
35
    y2 = y1 + tdy * (ny-1)
36
    xll = min(x1, x2)
37
    yll = min(y1, y2)
38
    xur = max(x1, x2)
39
    yur = max(y1, y2)
40
41
    if nsflag == 'N':
42
        latll = (HALFPI - 2*math.atan2(math.hypot(xll, yll), EARTH_RADIUS)) * RAD_TO_DEG
43
        rtemp = clonr + math.atan2(xll, -yll)
44
    else:
45
        latll = -1 * (HALFPI - 2*math.atan2(math.hypot(xll, yll), EARTH_RADIUS)) * RAD_TO_DEG
46
        rtemp = clonr + math.atan2(xll, yll)
47
48
    if rtemp > math.pi:
49
        lonll = (rtemp-TWOPI) * RAD_TO_DEG
50
    elif rtemp < -math.pi:
51
        lonll = (rtemp+TWOPI) * RAD_TO_DEG
52
    else:
53
        lonll = rtemp * RAD_TO_DEG
54
55
    if nsflag == 'N':
56
        latur = (HALFPI - 2*math.atan2(math.hypot(xur, yur), EARTH_RADIUS)) * RAD_TO_DEG
57
        rtemp = clonr + math.atan2(xur, -yur)
58
    else:
59
        latur = -1 * (HALFPI - 2*math.atan2(math.hypot(xur, yur), EARTH_RADIUS)) * RAD_TO_DEG
60
        rtemp = clonr + math.atan2(xur, yur)
61
62
    if rtemp > math.pi:
63
        lonur = (rtemp-TWOPI) * RAD_TO_DEG
64
    elif rtemp < -math.pi:
65
        lonur = (rtemp+TWOPI) * RAD_TO_DEG
66
    else:
67
        lonur = rtemp * RAD_TO_DEG
68
69
    return [latll, lonll, latur, lonur]
70
71
72
def createConic(nsflag, clon, lat1, lon1, dx, dy, unit, nx, ny, ang1, ang3):
73
    clonr = clon * DEG_TO_RAD
74
    latr = lat1 * DEG_TO_RAD
75
    lonr = lon1 * DEG_TO_RAD
76
77
    angle1 = HALFPI - (math.fabs(ang1) * DEG_TO_RAD)
78
    angle2 = HALFPI - (math.fabs(ang3) * DEG_TO_RAD)
79
80
    if ang1 == ang3:
81
        cc = math.cos(angle1)
82
    else:
83
        cc = (math.log(math.sin(angle2)) - math.log(math.sin(angle1))) \
84
             / (math.log(math.tan(angle2/2.0)) - math.log(math.tan(angle1/2.0)))
85
86
    er = EARTH_RADIUS / cc
87
88
    if nsflag == 'N':
89
        x1 = er * math.pow(math.tan((HALFPI-latr)/2.0), cc) * math.sin(cc*(lonr-clonr))
90
        y1 = -1.0 * er * math.pow(math.tan((HALFPI-latr)/2.0), cc) * math.cos(cc*(lonr-clonr))
91
    else:
92
        x1 = er * math.pow(math.tan((HALFPI+latr)/2.0), cc) * math.sin(cc*(lonr-clonr))
93
        y1 = er * math.pow(math.tan((HALFPI+latr)/2.0), cc) * math.cos(cc*(lonr-clonr))
94
95
    alpha = math.pow(math.tan(angle1/2.0), cc) / math.sin(angle1)
96
97
    if unit == 'm':
98
        x2 = x1 + (nx-1) * alpha * dx
99
        y2 = y1 + (ny-1) * alpha * dy
100
    else:
101
        x2 = x1 + (nx-1) * alpha * (dx*1000.0)
102
        y2 = y1 + (ny-1) * alpha * (dy*1000.0)
103
104
    xll = min(x1, x2)
105
    yll = min(y1, y2)
106
    xur = max(x1, x2)
107
    yur = max(y1, y2)
108
109
    if nsflag == 'N':
110
        latll = (HALFPI - 2.0 * math.atan(math.pow(math.hypot(xll, yll)/er, (1/cc)))) * RAD_TO_DEG
111
        rtemp = math.atan2(xll, -yll) * (1/cc) + clonr
112
    else:
113
        latll = (-1.0 * (HALFPI - 2.0 * math.atan(math.pow(math.hypot(xll, yll)/er, (1/cc))))) * RAD_TO_DEG
114
        rtemp = math.atan2(xll, yll) * (1/cc) + clonr
115
116
    if rtemp > math.pi:
117
        lonll = (rtemp-TWOPI) * RAD_TO_DEG
118
    elif rtemp < -math.pi:
119
        lonll = (rtemp+TWOPI) * RAD_TO_DEG
120
    else:
121
        lonll = rtemp * RAD_TO_DEG
122
123
    if nsflag == 'N':
124
        latur = (HALFPI - 2.0 * math.atan(math.pow(math.hypot(xur, yur)/er, (1/cc)))) * RAD_TO_DEG
125
        rtemp = math.atan2(xur, -yur) * (1/cc) + clonr
126
    else:
127
        latur = (-1.0 * (HALFPI - 2.0 * math.atan(math.pow(math.hypot(xur, yur)/er, (1/cc))))) * RAD_TO_DEG
128
        rtemp = math.atan2(xur, yur) * (1/cc) + clonr
129
130
    if rtemp > math.pi:
131
        lonur = (rtemp-TWOPI) * RAD_TO_DEG
132
    elif rtemp < -math.pi:
133
        lonur = (rtemp+TWOPI) * RAD_TO_DEG
134
    else:
135
        lonur = rtemp * RAD_TO_DEG
136
137
    return [latll, lonll, latur, lonur]
138
139
140
class StringConverter(Union):
141
    _fields_ = [("char", c_char*4), ("int", c_int), ("float", c_float)]
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable c_int does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable c_float does not seem to be defined.
Loading history...
Comprehensibility Best Practice introduced by
The variable c_char does not seem to be defined.
Loading history...
142
143
144
class GridNavRetriever:
145
146
    def __init__(self, server, pluginName, modelId, arrayLen):
147
        self.pluginName = pluginName
148
        self.modelId = modelId
149
        self.arrayLen = arrayLen
150
        self.host = os.getenv("DEFAULT_HOST", server)
151
        self.port = os.getenv("DEFAULT_PORT", "9581")
152
        self.client = ThriftClient.ThriftClient(self.host, self.port)
153
154
    def getNavBlk(self):
155
        """ Sends ThriftClient request and writes out received files."""
156
        req = GetGridNavRequest()
157
        req.setPluginName(self.pluginName)
158
        req.setModelId(self.modelId)
159
        resp = self.client.sendRequest(req)
160
161
        for i, rec in enumerate(resp):
162
            resp[i] = {
163
                key.decode() if isinstance(key, bytes) else key:
164
                    val.decode() if isinstance(val, bytes) else val
165
                for key, val in rec.items()
166
            }
167
168
        nav = []
169
170
        for record in resp:
171
            unit = record['spacingunit']
172
            sk = record['spatialkey']
173
            skarr = sk.split('/')
174
175
            nx = float(skarr[1])
176
            ny = float(skarr[2])
177
            dx = float(skarr[3])
178
            dy = float(skarr[4])
179
180
            sc = StringConverter()
181
            if record['projtype'] == 'LatLon':
182
                sc.char = 'CED '
183
                gemproj = 2.0
184
                ang1 = 0.0
185
                ang2 = 0.0
186
                ang3 = 0.0
187
188
                lllat = float(record['lowerleftlat'])
189
                lllon = float(record['lowerleftlon'])
190
                urlat = lllat + (dy * (ny-1))
191
                urlon = lllon + (dx * (nx-1))
192
                if lllon > 180:
193
                    lllon -= 360.0
194
                if urlon > 180:
195
                    urlon -= 360.0
196
197
            if record['projtype'] == 'Polar Stereographic':
198
                sc.char = 'STR '
199
                gemproj = 2.0
200
                if float(record['standard_parallel_1']) < 0.0:
201
                    ang1 = -90.0
202
                    nsflag = 'S'
203
                else:
204
                    ang1 = 90.0
205
                    nsflag = 'N'
206
                ang2 = float(record['central_meridian'])
207
                ang3 = 0.0
208
209
                lat1 = float(record['lowerleftlat'])
210
                lon1 = float(record['lowerleftlon'])
211
                coords = createPolar(nsflag, ang2, lat1, lon1, dx, dy, unit, nx, ny)
212
                lllat = coords[0]
213
                lllon = coords[1]
214
                urlat = coords[2]
215
                urlon = coords[3]
216
217
            if record['projtype'] == 'Lambert Conformal':
218
                sc.char = 'LCC '
219
                gemproj = 2.0
220
221
                ang1 = float(skarr[7])
222
                ang2 = float(record['central_meridian'])
223
                ang3 = float(skarr[8])
224
                if ang1 < 0.0:
225
                    nsflag = 'S'
226
                else:
227
                    nsflag = 'N'
228
229
                lat1 = float(record['lowerleftlat'])
230
                lon1 = float(record['lowerleftlon'])
231
                coords = createConic(nsflag, ang2, lat1, lon1, dx, dy, unit, nx, ny, ang1, ang3)
232
                lllat = coords[0]
233
                lllon = coords[1]
234
                urlat = coords[2]
235
                urlon = coords[3]
236
237
            # Fill up the output array of floats
238
            nav.append(gemproj)
0 ignored issues
show
The variable gemproj does not seem to be defined for all execution paths.
Loading history...
239
            nav.append(sc.float)
240
            nav.append(1.0)
241
            nav.append(1.0)
242
            nav.append(nx)
243
            nav.append(ny)
244
            nav.append(lllat)
0 ignored issues
show
The variable lllat does not seem to be defined for all execution paths.
Loading history...
245
            nav.append(lllon)
0 ignored issues
show
The variable lllon does not seem to be defined for all execution paths.
Loading history...
246
            nav.append(urlat)
0 ignored issues
show
The variable urlat does not seem to be defined for all execution paths.
Loading history...
247
            nav.append(urlon)
0 ignored issues
show
The variable urlon does not seem to be defined for all execution paths.
Loading history...
248
            nav.append(ang1)
0 ignored issues
show
The variable ang1 does not seem to be defined for all execution paths.
Loading history...
249
            nav.append(ang2)
0 ignored issues
show
The variable ang2 does not seem to be defined for all execution paths.
Loading history...
250
            nav.append(ang3)
0 ignored issues
show
The variable ang3 does not seem to be defined for all execution paths.
Loading history...
251
252
        for i in range(13, int(self.arrayLen)):
253
            nav.append(0.0)
254
        return nav
255
256
    def getAnlBlk(self):
257
        anl = []
258
        # Type
259
        anl.append(2.0)
260
        # Delta
261
        anl.append(1.0)
262
        # Extend area
263
        anl.append(0.0)
264
        anl.append(0.0)
265
        anl.append(0.0)
266
        anl.append(0.0)
267
        # Grid area
268
        anl.append(-90.0)
269
        anl.append(-180.0)
270
        anl.append(90.0)
271
        anl.append(180.0)
272
        # Data area
273
        anl.append(-90.0)
274
        anl.append(-180.0)
275
        anl.append(90.0)
276
        anl.append(180.0)
277
        for i in range(18, int(self.arrayLen)):
278
            anl.append(0.0)
279
        return anl
280
281
282
def getnavb(server, table, model, arrlen):
283
    gnr = GridNavRetriever(server, table, model, arrlen)
284
    return gnr.getNavBlk()
285
286
287
def getanlb(server, table, model, arrlen):
288
    gnr = GridNavRetriever(server, table, model, arrlen)
289
    return gnr.getAnlBlk()
290
291
292
# This is the standard boilerplate that runs this script as a main
293
if __name__ == '__main__':
294
    # Run Test
295
    srv = 'edex-cloud.unidata.ucar.edu'
296
    tbl = 'grid_info'
297
    mdl = 'NAM40'
298
    navlen = '256'
299
    print(getnavb(srv, tbl, mdl, navlen))
300
    anllen = '128'
301
    print(getanlb(srv, tbl, mdl, anllen))
302