Skip to content

Commit

Permalink
Add wgs84 conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
sebhahn committed Nov 10, 2021
1 parent d5071fc commit fc917e0
Show file tree
Hide file tree
Showing 9 changed files with 94 additions and 55 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@
Changelog
=========

Version 0.0.2
=============

- Add Fibonacci grid realization for Geodatum WGS84 at 6.25, 12.5 and 25 km

Version 0.0.1
=============

Expand Down
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ channels:
dependencies:
- numpy
- netCDF4
- pyproj
- numba
- pip
- pip:
Expand Down
80 changes: 37 additions & 43 deletions src/fibgrid/construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import netCDF4
import numpy as np
from numba import jit
from pygeogrids.grids import BasicGrid
from pyproj import CRS, Transformer


@jit(nopython=True, cache=True)
Expand All @@ -58,8 +58,8 @@ def compute_fib_grid(n):
"""
points = np.arange(-n, n+1)
gpi = np.arange(points.size)
lat = np.empty(points.size)
lon = np.empty(points.size)
lat = np.empty(points.size, dtype=np.float64)
lon = np.empty(points.size, dtype=np.float64)
phi = (1. + np.sqrt(5))/2.

for i in points:
Expand All @@ -73,52 +73,36 @@ def compute_fib_grid(n):
return points, gpi, lon, lat


def compute_grid_stats(n, k=5, geodatum='WGS84'):
def compute_fib_grid_wgs84(n):
"""
Compute grid statistics of k nearest neighbors.
Computation of Fibonacci lattice on a sphere and coordinated transformed
to WGS84 ellipsoid.
Parameters
----------
n : int
Number of grid points in the Fibonacci lattice.
k : int, optional
Nearest neighbor (default: 5).
geodatum : str, optional
Geodatum (default: 'WGS84')
"""
points, gpi, lon, lat = compute_fib_grid(n)

grid = BasicGrid(lon, lat, geodatum=geodatum)
nn, dist = grid.find_k_nearest_gpi(lon, lat, k=5)

print('Min distance: {:10.4f}'.format(dist[:, 1:].min()))
print('Max distance: {:10.4f}'.format(dist[:, 1:].max()))
print('Mean distance: {:10.4f}'.format(dist[:, 1:].mean()))
print('Median distance: {:10.4f}'.format(np.median(dist[:, 1:])))
print('Std distance: {:10.4f}'.format(dist[:, 1:].std()))

for i in range(1, k):
print('\n')
print('------- Neighbor #{:} -------'.format(i))
print('Min distance: {:10.4f}'.format(dist[:, i].min()))
print('Max distance: {:10.4f}'.format(dist[:, i].max()))
print('Mean distance: {:10.4f}'.format(dist[:, i].mean()))
print('Median distance: {:10.4f}'.format(np.median(dist[:, i])))
print('Std distance: {:10.4f}'.format(dist[:, i].std()))

print('\n')
lat_bands = range(-90, 90, 5)
for band in lat_bands:
subgrid = grid.subgrid_from_gpis(grid.get_bbox_grid_points(
latmin=band, latmax=band+5))
nn, dist_subgrid = grid.find_k_nearest_gpi(
subgrid.arrlon, subgrid.arrlat, k=k)
print('Band [{} -- {}] deg: {:10.4f}'.format(
band, band+5, dist_subgrid[:, 1:].mean()))


def write_grid(filename, n, nc_fmt='NETCDF4_CLASSIC', nc_zlib=True,
nc_complevel=2):
crs_wgs84 = CRS.from_epsg(4326)
crs_sphere = CRS.from_proj4(
'+proj=lonlat +ellps=sphere +R=6370997 +towgs84=0,0,0')

points, gpi, sphere_lon, sphere_lat = compute_fib_grid(n)
transformer = Transformer.from_crs(crs_sphere, crs_wgs84)

wgs84_lon = np.zeros(sphere_lon.size, dtype=np.float64)
wgs84_lat = np.zeros(sphere_lat.size, dtype=np.float64)

i = 0
for lon, lat in zip(sphere_lon, sphere_lat):
wgs84_lat[i], wgs84_lon[i] = transformer.transform(lon, lat)
i = i + 1

return points, gpi, wgs84_lon, wgs84_lat


def write_grid(filename, n, nc_fmt='NETCDF4', nc_zlib=True,
nc_complevel=2, geodatum='WGS84'):
"""
Write grid file for Fibonacci lattice.
Expand All @@ -137,7 +121,12 @@ def write_grid(filename, n, nc_fmt='NETCDF4_CLASSIC', nc_zlib=True,
The optional keyword complevel is an integer between 1 and 9
describing the level of compression desired (default 2).
"""
points, gpi, lon, lat = compute_fib_grid(n)
if geodatum == 'WGS84':
points, gpi, lon, lat = compute_fib_grid_wgs84(n)
elif geodatum == 'sphere':
points, gpi, lon, lat = compute_fib_grid(n)
else:
raise ValueError('Geodatum unknown')

with netCDF4.Dataset(filename, 'w', format=nc_fmt) as fp:

Expand Down Expand Up @@ -201,3 +190,8 @@ def read_grid(filename, variables=['gpi', 'lon', 'lat']):
data[var] = fp.variables[var][:]

return data


if __name__ == '__main__':
n = 6600000
compute_fib_grid_wgs84(n)
File renamed without changes.
File renamed without changes.
File renamed without changes.
41 changes: 37 additions & 4 deletions src/fibgrid/realization.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
from pygeogrids.grids import CellGrid


def read_grid_file(n):
def read_grid_file(n, geodatum='WGS84'):
"""
Read pre-computed grid files.
Expand All @@ -59,8 +59,9 @@ def read_grid_file(n):
metadata : dict
Metadata information of the grid.
"""
filename = os.path.join(os.path.dirname(__file__),
'files', 'fibgrid_n{}.nc'.format(n))
filename = os.path.join(
os.path.dirname(__file__), 'files',
'fibgrid_{}_n{}.nc'.format(geodatum.lower(), n))

metadata_fields = ['land_frac_fw', 'land_frac_hw',
'land_mask_hw', 'land_mask_fw']
Expand Down Expand Up @@ -104,5 +105,37 @@ def __init__(self, res, geodatum='WGS84'):
else:
raise ValueError('Resolution unknown')

lon, lat, cell, gpi, self.metadata = read_grid_file(n)
lon, lat, cell, gpi, self.metadata = read_grid_file(
n, geodatum=geodatum)
super().__init__(lon, lat, cell, gpi, geodatum=geodatum)


class FibLandGrid(CellGrid):

"""
Fibonacci grid with active points over land defined by land fraction.
"""

def __init__(self, res, geodatum='WGS84'):
"""
Initialize FibGrid.
Parameters
----------
res : int
Sampling.
geodatum : str, optional
Geodatum (default: 'WGS84')
"""
if res == 6.25:
n = 6600000
elif res == 12.5:
n = 1650000
elif res == 25:
n = 430000
else:
raise ValueError('Resolution unknown')

lon, lat, cell, gpi, self.metadata = read_grid_file(
n, geodatum=geodatum)
super().__init__(lon, lat, cell, gpi, geodatum=geodatum)
14 changes: 9 additions & 5 deletions tests/test_construction.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def setUp(self):
"""
self.test_path = mkdtemp()
self.n = [6600000, 1650000, 430000]
self.geodatum = ['sphere', 'WGS84']

def test_fibgrid(self):
"""
Expand All @@ -60,11 +61,14 @@ def test_read_write_fibgrid(self):
"""
Test read/write Fibonacci grid.
"""
for n in self.n:
filename = os.path.join(self.test_path, 'fibgrid_{}.NC'.format(n))
write_grid(filename, n)
data = read_grid(filename)
np.testing.assert_equal(data['gpi'], np.arange(n*2+1))
for geodatum in self.geodatum:
for n in self.n:
filename = os.path.join(
self.test_path, 'fibgrid_{}_n{}.nc'.format(
geodatum.lower(), n))
write_grid(filename, n)
data = read_grid(filename)
np.testing.assert_equal(data['gpi'], np.arange(n*2+1))


if __name__ == '__main__':
Expand Down
8 changes: 5 additions & 3 deletions tests/test_realization.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,16 @@ def setUp(self):
"""
self.res = [6.25, 12.5, 25]
self.n = [6600000, 1650000, 430000]
self.geodatum = ['sphere', 'WGS84']

def test_grid_files(self):
"""
Test read grid files.
"""
for res, n in zip(self.res, self.n):
fb = FibGrid(res)
assert fb.gpis.size == 2*n+1
for geodatum in self.geodatum:
for res, n in zip(self.res, self.n):
fb = FibGrid(res, geodatum=geodatum)
assert fb.gpis.size == 2*n+1


if __name__ == '__main__':
Expand Down

0 comments on commit fc917e0

Please sign in to comment.