Coverage for pyrdnap / v_grids.py: 99%
71 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-06 16:53 -0400
« prev ^ index » next coverage.py v7.14.0, created at 2026-06-06 16:53 -0400
2# -*- coding: utf-8 -*-
4u'''(INTERNAL) C{RD NAP 2018} v#grid utilities.
5'''
6from pyrdnap import pyrdnap_abspath # pyrdnap 1st
7from pyrdnap.__pygeodesy import _0_0s, import_module, _ValueError
8from pygeodesy import print_
10from array import array
11import os.path as os_path
12import sys
13from zipfile import ZipFile
15__all__ = ()
16__version__ = '26.05.29'
18_R_C = 481, 301 # shape: rows, cols
19_RxC = 144781 # total
22class RDNAPError(_ValueError): # exported by rdnap2018
23 '''Error raised for C{RD}, C{NAP} and unzip issues.
24 '''
25 pass
28class _V_grid(tuple):
29 '''(INTERNAL) V_grid, an R-tuple of C-arrays of C{floats}.
30 '''
32 def __call__(self, i, j):
33 # R, C = _R_C
34 # assert isinstance(i, int) and 0 <= i < R
35 # assert isinstance(j, int) and 0 <= j < C
36 return self[i][j]
38 def _assert(self, _0s=0):
39 z, Z = self._assert2(*_R_C)
40 _v_assert(z, _0s)
41 _v_assert(Z, 197 if _0s else 0)
42 _v_assert(sum(map(len, self)), _RxC)
43 return self
45 def _assert2(self, R, C):
46 _v_assert(len(self), R)
47 _v_assert(len(_ZEROW), C)
48 z = Z = 0 # count zeros and _ZEROSWs
49 try:
50 for i, r in enumerate(self):
51 _v_assert(type(r), array)
52 _v_assert(len(r), C)
53 if r is _ZEROW:
54 Z += 1
55 z += C
56 else:
57 z += sum((0 if f else 1) for f in r)
58 except AssertionError as x:
59 raise AssertionError('row %s: %s' % (i, x))
60 return z, Z
62 def _round(self, _op, ndigits):
63 # round(_op(f for a in self
64 # for f in a), ndigits)
65 return round(_op(map(_op, self)), ndigits)
68def _d_array(floats): # lat_/lon_corr_
69 return array('d', floats)
72def _f_array(floats): # _NAP_h, _ZEROW
73 return array('f', floats)
75_ZEROW = _f_array(_0_0s(301)) # PYCHOK singleton
78def _v_grid(v):
79 return 'v%sgrid' % (v,)
82def _v_assert(value, valid=_R_C): # in .rd0
83 if value != valid:
84 raise AssertionError('%r not %r' % (value, valid))
85 return True
88def _v_grid_txt(v, name, col2or3, _array, **_0s):
89 '''(INTERNAL) Return a C{_V_grid} for column C{col2or3} of
90 compressed, variant C{v} grid file C{<name>2018.txt.zip}.
91 '''
92 v = _V_grid(_v_txt_unzip(v, name, col2or3, _array))
93 return v._assert(**_0s)
96def _v_gridz3(v): # PHYCOK no cover
97 '''(INTERNAL) Return the fully-qualified path, directory and module.
98 '''
99 m = _v_grid(v)
100 d = pyrdnap_abspath
101 p = os_path.join(d, m + 'z.zip')
102 return p, d, m
105def _v_gridz_import(v): # PHYCOK no cover
106 '''(INTERNAL) Try "from v#gridz.zip import v#grid"
107 '''
108 v_grid = None
109 p, _, m = _v_gridz3(v)
110 try: # Py 3.4+
111 # <https://RealPython.com/python-zip-import/
112 # #explore-pythons-zipimport-the-tool-behind-zip-imports>
113 from zipimport import zipimporter as Z # ZipImportError
114 # get an importer for zip file p and load module m
115 v_grid = Z(p).load_module(m) # Py3.14-
116 # XXX should use .exec_module but that fails and/or
117 # XXX needs .create_module, .find_spec, etc???
118 except (AttributeError, ImportError):
119 try: # trusted old-fashion way
120 sys.path.insert(0, p)
121 v_grid = import_module(m)
122# except ImportError:
123# v_grid = None
124 finally:
125 try:
126 sys.path.remove(p)
127 except ValueError:
128 pass # AssertionError
129# if v_grid:
130# sys.modules[m] = v_grid
131 return v_grid
134def _v_gridz_unzip(v, force=False, verbose=False): # PHYCOK no cover
135 '''(INTERNAL) Unzip a C{v#gridz.zip} file into the "pyrdnap" directory
136 '''
137 p, d, m = _v_gridz3(v)
138 t = os_path.join(d, m)
139 if (not force) and os_path.exists(t):
140 t = '%r exists: %r' % (m, t)
141 raise RDNAPError(t)
142 try:
143 with ZipFile(p) as z:
144 z.extractall(d)
145 except Exception as x:
146 raise RDNAPError(m, cause=x)
147 if verbose:
148 print_('unzipped', repr(p))
149 print_(' into', repr(t))
152def _v_txt_unzip(v, name, col2or3, _array):
153 '''(INTERNAL) Open grid file C{<name>2018.txt} or unzip
154 C{<name>2018.txt.zip} of variant C{v}, extract column
155 C{col2or3} and yield 481 rows, each a 301-C{_array}
156 of floats or a _ZEROW if all zeros.
157 '''
158 r = []
159 try:
160 n = name + '2018.txt'
161 p = pyrdnap_abspath
162 p = os_path.join(p, _v_grid(v), n)
163 with (open(p, 'rb') if os_path.exists(p) else
164 ZipFile(p + '.zip').open(n)) as f:
165 _, C = _R_C
166 _r = r.append
167 t = f.readline() # ignore 1st line
168 while t:
169 for _ in range(C * 2):
170 t = f.readline()
171 if t:
172 _r(t.strip().split()[col2or3])
173 else:
174 break
175 while len(r) >= C:
176 y = _array(map(float, r[:C]))
177 yield y if any(y) else _ZEROW
178 r[:] = r[C:]
179 except Exception as x:
180 raise RDNAPError(n, cause=x)
181 _v_assert(len(r), 0)
184# __all__ += _ALL_OTHER(RDNAPError) # in .rdnap2018
186# **) MIT License
187#
188# Copyright (C) 2026-2026 -- mrJean1 at Gmail -- All Rights Reserved.
189#
190# Permission is hereby granted, free of charge, to any person obtaining a
191# copy of this software and associated documentation files (the "Software"),
192# to deal in the Software without restriction, including without limitation
193# the rights to use, copy, modify, merge, publish, distribute, sublicense,
194# and/or sell copies of the Software, and to permit persons to whom the
195# Software is furnished to do so, subject to the following conditions:
196#
197# The above copyright notice and this permission notice shall be included
198# in all copies or substantial portions of the Software.
199#
200# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
201# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
202# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
203# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
204# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
205# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
206# OTHER DEALINGS IN THE SOFTWARE.