GridNavRetriever.GridNavRetriever.getNavBlk()   F
last analyzed

Complexity

Conditions 13

Size

Total Lines 101
Code Lines 83

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 83
dl 0
loc 101
rs 3.4963
c 0
b 0
f 0
cc 13
nop 1

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like GridNavRetriever.GridNavRetriever.getNavBlk() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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
introduced by
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
introduced by
The variable lllat does not seem to be defined for all execution paths.
Loading history...
245
            nav.append(lllon)
0 ignored issues
show
introduced by
The variable lllon does not seem to be defined for all execution paths.
Loading history...
246
            nav.append(urlat)
0 ignored issues
show
introduced by
The variable urlat does not seem to be defined for all execution paths.
Loading history...
247
            nav.append(urlon)
0 ignored issues
show
introduced by
The variable urlon does not seem to be defined for all execution paths.
Loading history...
248
            nav.append(ang1)
0 ignored issues
show
introduced by
The variable ang1 does not seem to be defined for all execution paths.
Loading history...
249
            nav.append(ang2)
0 ignored issues
show
introduced by
The variable ang2 does not seem to be defined for all execution paths.
Loading history...
250
            nav.append(ang3)
0 ignored issues
show
introduced by
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