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