Coverage for pyrdnap/v_grids.py: 100%

72 statements  

« prev     ^ index     » next       coverage.py v7.10.7, created at 2026-05-08 18:11 -0400

1 

2# -*- coding: utf-8 -*- 

3 

4u'''(INTERNAL) C{RD NAP 2018} v#grid utilities. 

5''' 

6from pyrdnap import pyrdnap_abspath # pyrdnap 1st 

7from pyrdnap.__pygeodesy import _0_0s, _1_0, import_module 

8from pygeodesy import print_ 

9 

10from array import array 

11import os.path as os_path 

12import sys 

13 

14__all__ = () 

15__version__ = '26.05.08' 

16 

17_R_C = 481, 301 # shape: rows, cols 

18_RxC = 144781 # total 

19 

20 

21class _V_grid(tuple): 

22 '''(INTERNAL) V_grid, an R-tuple of C-arrays of C{floats}. 

23 ''' 

24 _scale = None 

25 

26 def __call__(self, i, j): 

27 # R, C = _R_C 

28 # assert isinstance(i, int) and 0 <= i < R 

29 # assert isinstance(j, int) and 0 <= j < C 

30 return self[i][j] * self._scale 

31 

32 def _assert(self, scale, ndigits, *len_min_0s_max): 

33 self._scale = scale 

34 z = self._assert0s(*_R_C) 

35 n = sum(map(len, self)) # _RxC 

36 t = (n, self._round(min, ndigits), 

37 z, self._round(max, ndigits)) 

38 _v_assert(t, len_min_0s_max) 

39 return self 

40 

41 def _assert0s(self, R, C): 

42 _v_assert(len(self), R) 

43 z = 0 # count zeros 

44 try: 

45 for i, r in enumerate(self): 

46 _v_assert(type(r), array) 

47 _v_assert(len(r), C) 

48 z += C if r is _ZEROW else \ 

49 sum((0 if f else 1) for f in r) 

50 except AssertionError as x: 

51 raise AssertionError('row %s: %s' % (i, x)) 

52 return z 

53 

54 def _round(self, _op, ndigits): 

55 # round(_op(f for a in self 

56 # for f in a), ndigits) 

57 return round(_op(map(_op, self)), ndigits) 

58 

59 

60def _d_array(floats): # lat_/lon_corr_ 

61 return array('d', floats) 

62 

63 

64def _f_array(floats): # _NAP_h, _ZEROW 

65 return array('f', floats) 

66 

67_ZEROW = _f_array(_0_0s(301)) # PYCHOK singleton 

68 

69 

70def _run(s, e, floats): # run of non-zeros 

71 _v_assert(len(floats), e - s) 

72 return s, e, floats 

73 

74 

75def _v_assert(value, valid=_R_C): 

76 if value != valid: 

77 raise AssertionError('%r not %r' % (value, valid)) 

78 return True 

79 

80 

81def _v1corr_grid(runs, ndigits, cmin, cmax, c0s=0, flen=_RxC, scale=1e-5): 

82 '''(INTERNAL) Build a variant 1 C{lat_/lon_corr} _V_grid from C{s_e_runs}, 

83 each a run of non-zero floats preceeded by a start and end index. 

84 ''' 

85 v = _V_grid(_v1corr_rows(runs, *_R_C)) 

86 return v._assert(scale, ndigits, flen, cmin, c0s, cmax) 

87 

88 

89def _v1corr_rows(runs, R, C): 

90 '''(INTERNAL) Yield R d-/f-arrays, each of C floats, see C{v1grid.__init__.py}. 

91 ''' 

92 z = _ZEROW # f-array of C zeros 

93 i = runs[0][0] # index of 1st non-zero 

94 y, s = divmod(i, C) 

95 for _ in range(y): # 28 leading ZEROWs 

96 yield z 

97 r = list(_0_0s(s)) # remainder, 170 zeros 

98 for (s, e, t) in runs: 

99 r.extend(_0_0s(s - i)) 

100 r.extend(t) # len(r) < 600 

101 while len(r) >= C: 

102 d = _d_array(r[:C]) 

103 r[:] = r[C:] 

104 yield d if any(d) else z # just in case 

105 y += 1 

106 i = e 

107 if r: # remaining, 216/219 non-zeros 

108 # assert 0 < len(r) < C 

109 r.extend(_0_0s(C - len(r))) 

110 yield _d_array(r) 

111 # r[:] = () 

112 y += 1 

113 for _ in range(y, R): # 169 trailing ZEROWs 

114 yield z 

115 

116 

117def _v2corr_grid(d_arrays, ndigits, cmin, cmax, c0s=0, flen=_RxC, scale=0): 

118 '''(INTERNAL) A variant 2 C{lat_/lon_corr} _V_grid. 

119 ''' 

120 return _V_grid(d_arrays)._assert(scale, ndigits, flen, cmin, c0s, cmax) 

121 

122 

123def _v_h_grid(f_arrays, hmin, hmax, flen=_RxC, scale=_1_0): 

124 '''(INTERNAL) An C{NAP_h} _V_grid. 

125 ''' 

126 return _V_grid(f_arrays)._assert(scale, 4, flen, hmin, 0, hmax) 

127 

128 

129def _v_gridz3(v): # PHYCOK no cover 

130 '''(INTERNAL) Return the fully-qualified path, directory and module. 

131 ''' 

132 m = 'v%sgrid' % (v,) 

133 z = m + 'z.zip' 

134 d = pyrdnap_abspath 

135 p = os_path.join(d, z) 

136 return p, d, m 

137 

138 

139def _v_gridz_import(v): # PHYCOK no cover 

140 '''(INTERNAL) Try "from v#gridz.zip import v#grid" 

141 ''' 

142 v_grid = None 

143 p, _, m = _v_gridz3(v) 

144 try: # Py 3.4+ 

145 # <https://RealPython.com/python-zip-import/ 

146 # #explore-pythons-zipimport-the-tool-behind-zip-imports> 

147 from zipimport import zipimporter as Z # ZipImportError 

148 # get an importer for zip file p and load module m 

149 v_grid = Z(p).load_module(m) # Py3.14- 

150 # XXX should use .exec_module but that fails and/or 

151 # XXX needs .create_module, .find_spec, etc??? 

152 except (AttributeError, ImportError): 

153 try: # trusted old-fashion way 

154 sys.path.insert(0, p) 

155 v_grid = import_module(m) 

156# except ImportError: 

157# v_grid = None 

158 finally: 

159 try: 

160 sys.path.remove(p) 

161 except ValueError: 

162 pass # AssertionError 

163# if v_grid: 

164# sys.modules[m] = v_grid 

165 return v_grid 

166 

167 

168def _v_gridz_unzip(v, force=False, verbose=False): # PHYCOK no cover 

169 '''(INTERNAL) Unzip a C{v#gridz.zip} file into the "pyrdnap" directory 

170 ''' 

171 try: 

172 from zipfile import BadZipFile, ZipFile 

173 except ImportError: # Py3.3- 

174 from zipfile import BadZipfile as BadZipFile, ZipFile 

175 

176 p, d, m = _v_gridz3(v) 

177 t = os_path.join(d, m) 

178 if (not force) and os_path.exists(t): 

179 t = 'dir %r exists: %r' % (m, t) 

180 raise OSError(t) 

181 try: 

182 with ZipFile(p, 'r') as z: 

183 z.extractall(d) 

184 except BadZipFile as x: 

185 raise ValueError(str(x), cause=x) 

186 if verbose: 

187 print_('unzipped', repr(p)) 

188 print_(' into', repr(t)) 

189 

190# **) MIT License 

191# 

192# Copyright (C) 2026-2026 -- mrJean1 at Gmail -- All Rights Reserved. 

193# 

194# Permission is hereby granted, free of charge, to any person obtaining a 

195# copy of this software and associated documentation files (the "Software"), 

196# to deal in the Software without restriction, including without limitation 

197# the rights to use, copy, modify, merge, publish, distribute, sublicense, 

198# and/or sell copies of the Software, and to permit persons to whom the 

199# Software is furnished to do so, subject to the following conditions: 

200# 

201# The above copyright notice and this permission notice shall be included 

202# in all copies or substantial portions of the Software. 

203# 

204# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 

205# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

206# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 

207# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 

208# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 

209# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 

210# OTHER DEALINGS IN THE SOFTWARE.