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