Skip to content

Commit

Permalink
Bug fixes and increased test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
jreniel committed Jan 15, 2020
1 parent 006b51d commit 9017699
Show file tree
Hide file tree
Showing 5 changed files with 164 additions and 113 deletions.
10 changes: 9 additions & 1 deletion pyschism/mesh/gmesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from collections.abc import Mapping
from matplotlib.tri import Triangulation
from matplotlib.collections import PolyCollection
from pyproj import CRS, Transformer
from pyproj import CRS, Transformer, Proj
from functools import lru_cache


Expand Down Expand Up @@ -158,6 +158,14 @@ def triangulation(self):
def description(self):
return self._description

@property
def proj(self):
return Proj(self.crs)

@property
def srs(self):
return self.proj.srs

@property
def crs(self):
return self._crs
Expand Down
29 changes: 17 additions & 12 deletions pyschism/mesh/hgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,16 @@ def add_boundary_type(self, ibtype):
if ibtype not in self.boundaries:
self._boundaries[ibtype] = defaultdict()

def add_boundary_data(self, ibtype, id, indexes, **properties):
assert set(indexes).issubset(set(self.vertices.keys()))
self._boundary[ibtype] = {
def set_boundary_data(self, ibtype, id, indexes, **properties):
keys = set(self.nodes.keys())
for idx in indexes:
msg = "Indexes must be subset of node id's."
if isinstance(idx, (str, int)):
assert set(idx).issubset(keys), msg
elif isinstance(idx, Iterable):
for _idx in idx:
assert set(_idx).issubset(keys), msg
self._boundaries[ibtype] = {
'indexes': indexes,
**properties
}
Expand Down Expand Up @@ -101,7 +108,7 @@ def make_plot(
if vmax is None:
vmax = np.max(self.values)
kwargs.update(**fig.get_topobathy_kwargs(self.values, vmin, vmax))
col_val = kwargs.pop('col_val')
kwargs.pop('col_val')
self.tricontourf(axes=axes, vmin=vmin, vmax=vmax, **kwargs)
kwargs.pop('levels')
self.quadface(axes=axes, **kwargs)
Expand All @@ -118,15 +125,10 @@ def make_plot(
cbar = plt.colorbar(
mappable,
cax=cax,
# extend=cmap_extend,
orientation='horizontal'
)
if col_val != 0:
cbar.set_ticks([vmin, vmin + col_val * (vmax-vmin), vmax])
cbar.set_ticklabels([np.around(vmin, 2), 0.0, np.around(vmax, 2)])
else:
cbar.set_ticks([vmin, vmax])
cbar.set_ticklabels([np.around(vmin, 2), np.around(vmax, 2)])
cbar.set_ticks([vmin, vmax])
cbar.set_ticklabels([np.around(vmin, 2), np.around(vmax, 2)])
if cbar_label is not None:
cbar.set_label(cbar_label)
return axes
Expand Down Expand Up @@ -200,12 +202,15 @@ def _boundaries(self, boundaries):
"""
elements in boundaries should be a subset of the node keys.
"""
keys = set(self.nodes)
if boundaries is not None:
msg = "elements argument must be a dictionary of the form "
msg += "\\{element_id: (e0, ..., en)\\} where n==2 or n==3."
assert isinstance(boundaries, Mapping), msg
msg = "(e0, ..., en) must be a subset of the node keys."
for geom in boundaries.values():
assert len(geom) in [3, 4], msg
for bnd in geom.values():
assert set(bnd).issubset(keys), msg
else:
boundaries = {}
# ocean boundaries
Expand Down
5 changes: 2 additions & 3 deletions tests/cmd/test_plot_mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import tempfile
import warnings
import pathlib
import matplotlib.pyplot as plt
from pyschism.cmd import plot_mesh


class PlotMeshCmdTestCase(unittest.TestCase):

def test_plot_mesh_command(self):
plt.switch_backend('Agg')
@patch('matplotlib.pyplot.show')
def test_plot_mesh_command(self, mock):
tmpdir = tempfile.TemporaryDirectory()
outdir = pathlib.Path(tmpdir.name)
nodes = {
Expand Down
4 changes: 2 additions & 2 deletions tests/coverage.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
229 changes: 134 additions & 95 deletions tests/mesh/test_hgrid.py
Original file line number Diff line number Diff line change
@@ -1,108 +1,126 @@
#! /usr/bin/env python
import numpy as np
import tempfile
import pathlib
import warnings
import matplotlib.pyplot as plt
from unittest.mock import patch
from pyschism.mesh import Hgrid
from pyschism.mesh.friction import Fgrid
import unittest


class HgridTestCase(unittest.TestCase):

def test_triangles_only(self):
nodes = {
0: ((0., 0.), np.nan),
1: ((1., 0.), np.nan),
2: ((0., 1.), np.nan),
}
elements = {0: [0, 1, 2]}
h = Hgrid(nodes, elements)
self.assertIsInstance(h, Hgrid)
def setUp(self):
self.nodes = {
'1': ((0., 0.), -5.),
'2': ((.5, 0.), -4.),
'3': ((0., 1.), -3.),
'4': ((1., 1.), -2.),
'5': ((0., 1.), -1.),
'6': ((.5, 1.5), 0.),
'7': ((.33, .33), 1.),
'8': ((.66, .33), 2.),
'9': ((.5, .66), 3.),
'10': ((-1., 1.), 4.),
'11': ((-1., 0.), 5.),
}
self.elements = {
'1': ['5', '7', '9'],
'2': ['1', '2', '7'],
'3': ['2', '3', '8'],
'4': ['8', '7', '2'],
'5': ['3', '4', '8'],
'6': ['4', '9', '8'],
'7': ['4', '6', '5'],
'8': ['5', '10', '11', '1'],
'9': ['9', '4', '5'],
'10': ['5', '1', '7']
}

def test_quads_only(self):
nodes = {
0: ((0., 0.), np.nan),
1: ((1., 0.), np.nan),
2: ((1., 1.), np.nan),
3: ((0., 1.), np.nan),
self.boundaries = dict()

self.boundaries[None] = { # "open" boundaries
0: ['10', '11', '1', '2'],
1: ['2', '3', '4']
}
elements = {0: [0, 1, 2, 3]}
h = Hgrid(nodes, elements)
self.assertIsInstance(h, Hgrid)

def test_hybrid(self):
nodes = {
0: ((0., 0.), np.nan),
1: ((1., 0.), np.nan),
2: ((1., 1.), np.nan),
3: ((0., 1.), np.nan),
4: ((0.5, 1.5), np.nan),
self.boundaries[0] = { # "land" boundaries
0: ['4', '6'],
1: ['6', '5', '10']
}
elements = {
0: [2, 4, 3],
1: [3, 0, 1, 2],

self.boundaries[1] = {0: ['7', '8', '9']} # "interior" boundary

self.grd = {
'nodes': self.nodes,
'elements': self.elements,
'boundaries': self.boundaries,
'description': 'gr3_unittest'
}
h = Hgrid(nodes, elements)
self.assertIsInstance(h, Hgrid)

def test_triangles_only(self):
self.assertIsInstance(
Hgrid(
self.nodes,
{id: geom for geom in self.elements.values() if len(geom) == 3}
),
Hgrid
)

def test_quads_only(self):
self.assertIsInstance(
Hgrid(
self.nodes,
{id: geom for geom in self.elements.values() if len(geom) == 4}
),
Hgrid
)

def test_hybrid(self):
self.assertIsInstance(Hgrid(self.nodes, self.elements), Hgrid)

def test_open(self):
nodes = {
0: ((0., 0.), np.nan),
1: ((1., 0.), np.nan),
2: ((1., 1.), np.nan),
3: ((0., 1.), np.nan),
4: ((0.5, 1.5), np.nan),
}
elements = {
0: [2, 4, 3],
1: [0, 1, 2, 3],
}
tmpfile = tempfile.NamedTemporaryFile()
with open(tmpfile.name, 'w') as f:
f.write('\n')
f.write(f'{len(elements):d} ')
f.write(f'{len(nodes):d}\n')
for id, ((x, y), z) in nodes.items():
f.write(f'{len(self.elements):d} ')
f.write(f'{len(self.nodes):d}\n')
for id, ((x, y), z) in self.nodes.items():
f.write(f"{id} ")
f.write(f"{x} ")
f.write(f"{y} ")
f.write(f"{z}\n")
for id, geom in elements.items():
for id, geom in self.elements.items():
f.write(f"{id} ")
f.write(f"{len(geom)} ")
for idx in geom:
f.write(f"{idx:d} ")
f.write(f"{idx} ")
f.write(f"\n")
self.assertIsInstance(Hgrid.open(tmpfile.name), Hgrid)

def test_make_plot(self):
nodes = {
0: ((0., 0.), 0),
1: ((1., 0.), 1),
2: ((1., 1.), 2),
3: ((0., 1.), 3),
4: ((0.5, 1.5), 4),
}
elements = {
0: [2, 4, 3],
1: [0, 1, 2, 3],
}
h = Hgrid(nodes, elements)
with warnings.catch_warnings():
plt.switch_backend('Agg')
warnings.simplefilter("ignore")
h.make_plot(show=True)
@patch('matplotlib.pyplot.show')
def test_make_plot(self, mock):
h = Hgrid(self.nodes, self.elements)
h.make_plot(
show=True,
extent=[0, 1, 0, 1],
title='test',
cbar_label='elevation [m]',
vmax=0.
)
self.assertIsInstance(h, Hgrid)

def test_plot_boundary(self):
h = Hgrid(**self.grd)
h.plot_boundary(None, 0)
self.assertIsInstance(h, Hgrid)

def test_make_plot_wet_only(self):
nodes = {
0: ((0., 0.), 0),
1: ((1., 0.), -1),
2: ((1., 1.), -2),
3: ((0., 1.), -3),
4: ((0.5, 1.5), -4),
0: ((0., 0.), 0.),
1: ((1., 0.), -1.),
2: ((1., 1.), -2.),
3: ((0., 1.), -3.),
4: ((0.5, 1.5), -4.),
}
elements = {
0: [2, 4, 3],
Expand All @@ -113,38 +131,59 @@ def test_make_plot_wet_only(self):
self.assertIsInstance(h, Hgrid)

def test_write(self):
nodes = {
0: ((0., 0.), 0),
1: ((1., 0.), -1),
2: ((1., 1.), -2),
3: ((0., 1.), -3),
4: ((0.5, 1.5), -4),
}
elements = {
0: [2, 4, 3],
1: [0, 1, 2, 3],
}
h = Hgrid(nodes, elements)
h = Hgrid(self.nodes, self.elements)
tmpdir = tempfile.TemporaryDirectory()
h.write(pathlib.Path(tmpdir.name) / 'test_hgrid.gr3')
self.assertIsInstance(h, Hgrid)

def test_set_friction(self):
nodes = {
0: ((0., 0), 0),
1: ((1., 0.), -1),
2: ((1., 1.), -2),
3: ((0., 1.), -3),
4: ((0.5, 1.5), -4),
}
elements = {
0: [2, 4, 3],
1: [0, 1, 2, 3],
}
h = Hgrid(nodes, elements)
h = Hgrid(self.nodes, self.elements)
fric = h.set_friction(0.025, 'manning')
self.assertIsInstance(fric, Fgrid)

def test_add_custom_boundary_custom(self):
h = Hgrid(self.nodes, self.elements)
h.add_boundary_type('ibtype')
indexes = [('2', '7'), ('3', '8'), ('4', '9')]
props = {'flow': [1, 2, 3]}
h.set_boundary_data('ibtype', 0, indexes, properties=props)

def test_add_boundary_custom_raise(self):
h = Hgrid(self.nodes, self.elements)
h.add_boundary_type('ibtype')
indexes = [('2', '7'), ('3', '10000'), ('4', '9')]
props = {'flow': [1, 2, 3]}
self.assertRaises(
AssertionError,
h.set_boundary_data,
'ibtype',
0,
indexes,
**props
)

def test_add_boundary(self):
h = Hgrid(self.nodes, self.elements)
h.add_boundary_type('ibtype')
indexes = ['1']
h.set_boundary_data('ibtype', 0, indexes)

def test_add_boundary_raise(self):
h = Hgrid(self.nodes, self.elements)
h.add_boundary_type('ibtype')
indexes = ['10000']
self.assertRaises(
AssertionError,
h.set_boundary_data,
'ibtype',
0,
indexes,
)

def test_plot_boundaries(self):
h = Hgrid(self.nodes, self.elements, self.boundaries)
h.plot_boundaries()


if __name__ == '__main__':
unittest.main()

0 comments on commit 9017699

Please sign in to comment.